guardian-framework 0.1.155 → 0.1.156

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3206,7 +3206,7 @@ __export(exports_package, {
3206
3206
  bin: () => bin,
3207
3207
  author: () => author
3208
3208
  });
3209
- var name = "guardian-framework", version = "0.1.155", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
3209
+ var name = "guardian-framework", version = "0.1.156", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
3210
3210
  var init_package = __esm(() => {
3211
3211
  exports = {
3212
3212
  ".": {
package/dist/exports.js CHANGED
@@ -1991,7 +1991,7 @@ __export(exports_package, {
1991
1991
  bin: () => bin,
1992
1992
  author: () => author
1993
1993
  });
1994
- var name = "guardian-framework", version = "0.1.155", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1994
+ var name = "guardian-framework", version = "0.1.156", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1995
1995
  var init_package = __esm(() => {
1996
1996
  exports = {
1997
1997
  ".": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guardian-framework",
3
- "version": "0.1.155",
3
+ "version": "0.1.156",
4
4
  "description": "Token-optimized agentic framework scaffolder with pi-first architecture",
5
5
  "type": "module",
6
6
  "main": "dist/exports.js",
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-11-13T17:15:30Z",
2
+ "timestamp": "2026-11-13T17:26:44Z",
3
3
  "mode": "all",
4
4
  "stages_run": [],
5
5
  "summary": {
@@ -58,6 +58,16 @@ RUNNER="$ROOT/.pi/scripts/epic-runner.mjs"
58
58
  [ -f "$RUNNER" ] || { echo "missing $RUNNER — run guardian update" >&2; exit 1; }
59
59
 
60
60
  # The runner is a Node script; bun also executes it.
61
+ # The project directory is the one that owns .pi/ (this script lives in
62
+ # <project>/.pi/scripts). It is NOT necessarily the git top level: a monorepo
63
+ # often keeps the app in <repo>/backend with .pi/ inside it. Agents must run in
64
+ # the project dir, otherwise pi finds no extensions and /architect is not a
65
+ # command at all.
66
+ PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
67
+ GIT_TOP="$(git -C "$PROJECT_DIR" rev-parse --show-toplevel 2>/dev/null || echo "$PROJECT_DIR")"
68
+ PROJECT_REL="${PROJECT_DIR#"$GIT_TOP"}"
69
+ PROJECT_REL="${PROJECT_REL#/}"
70
+
61
71
  NODE_BIN="$(command -v node || command -v bun || true)"
62
72
  if [ -z "$NODE_BIN" ]; then
63
73
  echo "neither node nor bun found — required to spawn headless agents" >&2
@@ -158,6 +168,17 @@ while IFS= read -r modline; do
158
168
  [ -n "$modline" ] && MODULES+=("$modline")
159
169
  done <<<"$SELECTED"
160
170
 
171
+ # ── Pre-flight: the spawned agents inherit THIS project's .pi/ ──────────────
172
+ # Without extensions, /architect is not a command: the prompt falls through to
173
+ # the model, which then improvises (expensive and wrong). Fail before spawning.
174
+ if [ "$NO_SPAWN" -eq 0 ] && [ "$DRY_RUN" -eq 0 ]; then
175
+ if [ ! -d "$PROJECT_DIR/.pi/extensions" ]; then
176
+ echo "⛔ $PROJECT_DIR/.pi/extensions is missing — the agent would have no /architect command." >&2
177
+ echo " Run guardian update in $PROJECT_DIR, or use --no-spawn." >&2
178
+ exit 1
179
+ fi
180
+ fi
181
+
161
182
  echo "============================================"
162
183
  echo " Parallel epic fan-out"
163
184
  echo "============================================"
@@ -388,15 +409,23 @@ for m in ${MODULES[@]+"${MODULES[@]}"}; do
388
409
  echo " ✓ worktree $WT"
389
410
 
390
411
  if [ "$NO_SPAWN" -eq 1 ]; then
391
- echo " → run: cd \"$WT\" && /architect --epic \"$m\"$( [ "$TDD" -eq 1 ] && echo " --tdd")"
412
+ echo " → run: cd \"$WT${PROJECT_REL:+/$PROJECT_REL}\" && /architect --epic \"$m\"$( [ "$TDD" -eq 1 ] && echo " --tdd")"
392
413
  STARTED+=("$m")
393
414
  continue
394
415
  fi
395
416
 
396
417
  # 3. spawn one headless agent in the worktree (RPC mode dispatches the command)
418
+ # cwd must be the PROJECT dir inside the worktree (where .pi/ lives).
419
+ SPAWN_CWD="$WT"
420
+ [ -n "$PROJECT_REL" ] && SPAWN_CWD="$WT/$PROJECT_REL"
421
+ if [ ! -d "$SPAWN_CWD/.pi/extensions" ]; then
422
+ echo " ✗ $SPAWN_CWD/.pi/extensions missing — refusing to spawn a blind agent"
423
+ FAILED+=("$m")
424
+ continue
425
+ fi
397
426
  "$NODE_BIN" "$RUNNER" \
398
427
  "/architect --epic \"$m\"$( [ "$TDD" -eq 1 ] && echo " --tdd")" \
399
- --cwd "$WT" --log "$log" ${TIMEOUT_MS:+--timeout-ms "$TIMEOUT_MS"} \
428
+ --cwd "$SPAWN_CWD" --log "$log" ${TIMEOUT_MS:+--timeout-ms "$TIMEOUT_MS"} \
400
429
  >/dev/null 2>&1 &
401
430
  PID=$!
402
431
  bash "$REGISTRY" set "$m" "pid=$PID" "log=$log" "spawnedAt=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >/dev/null 2>&1
@@ -115,9 +115,32 @@ function handleLine(line) {
115
115
  // The prompt was accepted by an extension command?
116
116
  if (msg.type === "response" && msg.command === "prompt" && msg.success === true) {
117
117
  const d = msg.data?.disposition;
118
- if (d === "handled") handled = true;
119
- else if (d === "started" || d === "queued") handled = true;
120
- if (handled) armGrace();
118
+ // "handled" = an extension command consumed it (what we need).
119
+ // "started"/"queued" = it went to the MODEL. For a /command that means
120
+ // the extension was not loaded (wrong cwd, missing .pi/extensions) — the
121
+ // model then improvises the workflow, which looks like success and burns
122
+ // tokens. Treat that as a hard error.
123
+ const isCommand = opts.command.startsWith("/");
124
+ if (d === "handled") {
125
+ handled = true;
126
+ armGrace();
127
+ } else if (isCommand) {
128
+ emit(
129
+ JSON.stringify({
130
+ type: "runner_error",
131
+ reason: "command_not_dispatched",
132
+ detail:
133
+ `'${opts.command.split(/\s+/)[0]}' was routed to the model ` +
134
+ `(disposition "${d}") — the extension is not loaded in ${opts.cwd}. ` +
135
+ "Check that .pi/extensions exists in that directory.",
136
+ }),
137
+ );
138
+ failed = true;
139
+ finish(3);
140
+ } else {
141
+ handled = true;
142
+ armGrace();
143
+ }
121
144
  }
122
145
  if (msg.type === "response" && msg.command === "prompt" && msg.success === false) {
123
146
  emit(JSON.stringify({ type: "runner_error", reason: "prompt rejected" }));