mirror of
https://github.com/Heretek-AI/openrig.git
synced 2026-11-07 11:06:04 -10:00
The CLI package build now stages `packages/daemon/assets` with Node's `fs.cp` (recursive, `verbatimSymlinks`) instead of `cp -r`. Staged assets keep their source modes, so a build run under a narrower umask than the checkout no longer packs them as 0600 or 0700 (npm keeps owner-only bits when packing). A relative link stays a link in staging and is omitted by npm, rather than being followed and copied in on macOS. Copied bytes and sources are unchanged, and a failed copy still stops the build before the staged root is recorded. Only the assets step changes; the other copy steps still use `cp -r`. Contributed by @Aummadour.
176 lines
7.8 KiB
Bash
Executable File
176 lines
7.8 KiB
Bash
Executable File
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
CLI_DIR="$REPO_ROOT/packages/cli"
|
|
DAEMON_DIR="$REPO_ROOT/packages/daemon"
|
|
UI_DIR="$REPO_ROOT/packages/ui"
|
|
TUI_DIR="$REPO_ROOT/packages/tui"
|
|
SUBSTANCE_SURFACE_ROOTS=()
|
|
|
|
echo "=== OpenRig Package Build ==="
|
|
echo "Repo root: $REPO_ROOT"
|
|
echo ""
|
|
|
|
# 1. Clean previous build artifacts
|
|
echo "[1/6] Cleaning previous artifacts..."
|
|
rm -rf "$CLI_DIR/daemon" "$CLI_DIR/ui" "$CLI_DIR/tui"
|
|
|
|
# 2. Build daemon
|
|
echo "[2/6] Building daemon..."
|
|
(cd "$DAEMON_DIR" && npm run build)
|
|
|
|
# 3. Build UI
|
|
echo "[3/6] Building UI..."
|
|
(cd "$UI_DIR" && npm run build)
|
|
|
|
# 4. Build TUI
|
|
echo "[4/6] Building TUI..."
|
|
(cd "$TUI_DIR" && npm run build)
|
|
|
|
# 5. Build CLI
|
|
echo "[5/6] Building CLI..."
|
|
(cd "$CLI_DIR" && npm run build)
|
|
|
|
# 6. Assemble: copy daemon + UI + TUI into CLI package
|
|
echo "[6/6] Assembling package..."
|
|
|
|
# OPR.0.4.4.11 FR-6 — deploy-identity stamp. Computed ONCE here (the runtime
|
|
# worktree is at the SHA — available at build), then written as the compiled
|
|
# build-info module into EACH package's dist (per-package generated modules;
|
|
# the committed src/build-info.ts files stay the honest dev stubs). No
|
|
# runtime cross-package import.
|
|
STAMP_SEMVER="$(node -p "require('$CLI_DIR/package.json').version")"
|
|
STAMP_COMMIT="$(git -C "$REPO_ROOT" rev-parse HEAD)"
|
|
# DIRTY = the BUILD INPUTS differ from the commit, not "the working dir has scratch in it".
|
|
# Bare `git status --porcelain` counts UNTRACKED files repo-wide, so ordinary scratch
|
|
# (.mcp.json, workspace/, scratch dirs) stamped every build on a working machine as
|
|
# dirty=true — and a dirty stamp is unidentifiable, which defeats the whole point of
|
|
# pinning a runtime to a commit. Untracked files are NOT blanket-ignored (a new
|
|
# untracked .ts under packages/*/src really would compile in), so the check is SCOPED
|
|
# to the build inputs: anything under packages/ or scripts/, tracked or not, counts
|
|
# (scripts/ included because build-package.sh IS the builder — if it differs from the
|
|
# commit, the artifact is not reproducible from that commit either).
|
|
if [ -n "$(git -C "$REPO_ROOT" status --porcelain -- packages scripts)" ]; then STAMP_DIRTY=true; else STAMP_DIRTY=false; fi
|
|
STAMP_BUILT_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
echo "Build identity: ${STAMP_SEMVER} (${STAMP_COMMIT}) dirty=${STAMP_DIRTY} at ${STAMP_BUILT_AT}"
|
|
|
|
write_build_info() {
|
|
cat > "$1" <<EOF
|
|
// GENERATED by scripts/build-package.sh — the packaged build-identity stamp.
|
|
export const BUILD_INFO = {
|
|
semver: "${STAMP_SEMVER}",
|
|
commit: "${STAMP_COMMIT}",
|
|
dirty: ${STAMP_DIRTY},
|
|
builtAt: "${STAMP_BUILT_AT}",
|
|
};
|
|
export function stampFields(info = BUILD_INFO) {
|
|
if (!info.commit) return {};
|
|
return { semver: info.semver, commit: info.commit, dirty: info.dirty, builtAt: info.builtAt };
|
|
}
|
|
EOF
|
|
}
|
|
write_build_info "$DAEMON_DIR/dist/build-info.js"
|
|
write_build_info "$CLI_DIR/dist/build-info.js"
|
|
|
|
# OPR.0.5.3.7 R2 — generate the context-pack projection of canonical skills at
|
|
# PACKAGE TIME (into $DAEMON_DIR/context-packs; never committed, regenerated every
|
|
# build). Validated through the DAEMON's own manifest parser — a malformed
|
|
# projection FAILS THE BUILD here, never at serve time. Pinned to the build semver
|
|
# so served packs carry the binary's version.
|
|
echo "Generating shipped context-packs..."
|
|
(cd "$REPO_ROOT" && node scripts/generate-context-packs.mjs --version="$STAMP_SEMVER")
|
|
|
|
# Daemon: dist + assets + specs
|
|
mkdir -p "$CLI_DIR/daemon/dist"
|
|
cp -r "$DAEMON_DIR/dist/"* "$CLI_DIR/daemon/dist/"
|
|
|
|
if [ -d "$DAEMON_DIR/assets" ]; then
|
|
node --input-type=module -e '
|
|
import { cp } from "node:fs/promises";
|
|
await cp(process.argv[1], process.argv[2], {
|
|
recursive: true,
|
|
verbatimSymlinks: true,
|
|
});
|
|
' "$DAEMON_DIR/assets" "$CLI_DIR/daemon/assets"
|
|
SUBSTANCE_SURFACE_ROOTS+=("daemon/assets")
|
|
fi
|
|
|
|
if [ -d "$DAEMON_DIR/specs" ]; then
|
|
# OPR.0.5.6.12 LP-7 — the specs tree is copied wholesale into the npm
|
|
# artifact, so scan the actual filesystem input (including untracked build
|
|
# inputs) before the copy. Path-safety and manifest validation solve other
|
|
# problems; this is the public-substance refusal floor. Its term lists come from
|
|
# the local file OPENRIG_LEAK_GUARD_RULES names, when set.
|
|
node "$REPO_ROOT/scripts/check-internal-leak-guard.mjs" \
|
|
--repo "$REPO_ROOT" \
|
|
--mode tree \
|
|
--tree "$DAEMON_DIR/specs"
|
|
cp -r "$DAEMON_DIR/specs" "$CLI_DIR/daemon/specs"
|
|
SUBSTANCE_SURFACE_ROOTS+=("daemon/specs")
|
|
fi
|
|
|
|
# OPR.0.5.3.7 R2 — the shipped context-pack projection (generated above). The daemon
|
|
# registers this as a `builtin` discovery root resolved RELATIVE TO THE BINARY
|
|
# (startup.ts: import.meta.dirname/../context-packs -> <cli>/daemon/context-packs),
|
|
# so `rig context get` serves bytes that match `rig --version` by construction.
|
|
if [ -d "$DAEMON_DIR/context-packs" ]; then
|
|
cp -r "$DAEMON_DIR/context-packs" "$CLI_DIR/daemon/context-packs"
|
|
SUBSTANCE_SURFACE_ROOTS+=("daemon/context-packs")
|
|
fi
|
|
|
|
# The named substance gate reviews the roots the packager ACTUALLY staged. Keep
|
|
# that inventory beside the artifact instead of duplicating a source-root list
|
|
# in the gate; npm's own dry-run file list supplies the complete scan surface.
|
|
node -e '
|
|
const fs = require("fs");
|
|
const [out, ...roots] = process.argv.slice(1);
|
|
if (roots.length === 0) throw new Error("no shippable substance roots were staged");
|
|
fs.writeFileSync(out, JSON.stringify({ schemaVersion: 1, roots: [...new Set(roots)].sort() }, null, 2) + "\n");
|
|
' "$CLI_DIR/daemon/substance-surfaces.json" "${SUBSTANCE_SURFACE_ROOTS[@]}"
|
|
|
|
# Built-in policies (OPR.0.4.8.3): canonical source packages/daemon/policies/builtin/
|
|
# ships with the daemon; startup materializes read-only inspection copies at
|
|
# $OPENRIG_HOME/reference/policies/builtin/ (same chain as reference docs below).
|
|
if [ -d "$DAEMON_DIR/policies" ]; then
|
|
cp -r "$DAEMON_DIR/policies" "$CLI_DIR/daemon/policies"
|
|
fi
|
|
|
|
# Reference docs: copy from repo root docs/reference/ into the assembled package
|
|
if [ -d "$REPO_ROOT/docs/reference" ]; then
|
|
mkdir -p "$CLI_DIR/daemon/docs/reference"
|
|
cp -r "$REPO_ROOT/docs/reference/"* "$CLI_DIR/daemon/docs/reference/"
|
|
fi
|
|
|
|
# Earlier builds assembled a bundled copy of the unpublished @openrig/daemon here. The package now
|
|
# imports the shipped daemon/dist directly (rewrite step below), so remove any stale copy: it would
|
|
# otherwise shadow the development workspace link for code under packages/cli.
|
|
rm -rf "$CLI_DIR/node_modules/@openrig/daemon"
|
|
|
|
# UI: dist
|
|
mkdir -p "$CLI_DIR/ui/dist"
|
|
cp -r "$UI_DIR/dist/"* "$CLI_DIR/ui/dist/"
|
|
|
|
# TUI: dist (public openrig-tui bin declared by the CLI package)
|
|
mkdir -p "$CLI_DIR/tui/dist"
|
|
cp -r "$TUI_DIR/dist/"* "$CLI_DIR/tui/dist/"
|
|
|
|
# The CLI and TUI import daemon code as @openrig/daemon/<subpath>. That package is not published, so
|
|
# rewrite those specifiers in the staged JS to the daemon/dist copy shipped above (#66). Fails the
|
|
# build on an unmapped or unstaged subpath and on any daemon import left afterwards.
|
|
node "$REPO_ROOT/scripts/rewrite-daemon-imports.mjs"
|
|
|
|
# Report
|
|
echo ""
|
|
echo "=== Package Assembled ==="
|
|
echo "CLI dist: $(find "$CLI_DIR/dist" -name '*.js' | wc -l | tr -d ' ') JS files"
|
|
echo "Daemon dist: $(find "$CLI_DIR/daemon/dist" -name '*.js' | wc -l | tr -d ' ') JS files"
|
|
echo "Daemon assets: $(find "$CLI_DIR/daemon/assets" -type f 2>/dev/null | wc -l | tr -d ' ') files"
|
|
echo "Daemon specs: $(find "$CLI_DIR/daemon/specs" -type f 2>/dev/null | wc -l | tr -d ' ') files"
|
|
echo "Daemon policies: $(find "$CLI_DIR/daemon/policies" -type f 2>/dev/null | wc -l | tr -d ' ') files"
|
|
echo "Daemon docs: $(find "$CLI_DIR/daemon/docs" -type f 2>/dev/null | wc -l | tr -d ' ') files"
|
|
echo "UI dist: $(find "$CLI_DIR/ui/dist" -type f | wc -l | tr -d ' ') files"
|
|
echo "TUI dist: $(find "$CLI_DIR/tui/dist" -type f | wc -l | tr -d ' ') files"
|
|
echo ""
|
|
echo "Ready to publish: cd packages/cli && npm publish --access public"
|