pi-crew 0.11.16 → 0.11.18

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.
Files changed (45) hide show
  1. package/CHANGELOG.md +228 -0
  2. package/NOTICE.md +9 -0
  3. package/README.md +1 -0
  4. package/dist/index.mjs +517 -516
  5. package/docs/usage.md +66 -0
  6. package/package.json +1 -1
  7. package/skills/real-test-pi-crew/SKILL.md +19 -3
  8. package/src/config/config-validation.ts +26 -1
  9. package/src/config/config.ts +6 -1
  10. package/src/config/env-allowlist-registry.ts +463 -0
  11. package/src/config/env-vars.ts +13 -0
  12. package/src/config/types.ts +36 -0
  13. package/src/extension/registration/team-tool.ts +7 -1
  14. package/src/extension/registration/terminal-status-wiring.ts +155 -2
  15. package/src/extension/run-index.ts +30 -5
  16. package/src/extension/team-tool/context.ts +6 -0
  17. package/src/extension/team-tool/handle-settings.ts +9 -6
  18. package/src/runtime/async-runner.ts +11 -96
  19. package/src/runtime/broker/crew-broker.ts +12 -0
  20. package/src/runtime/child-pi/child-pi-rpc.ts +61 -8
  21. package/src/runtime/child-pi/child-pi-spawn.ts +5 -31
  22. package/src/runtime/live-session/embedded-tier.ts +994 -0
  23. package/src/runtime/live-session/live-session-runtime.ts +223 -11
  24. package/src/runtime/model/pi-args.ts +30 -2
  25. package/src/runtime/model/runtime-policy.ts +45 -0
  26. package/src/runtime/scheduling/nested-slots.ts +26 -0
  27. package/src/runtime/surface/herdr-provider.ts +58 -7
  28. package/src/runtime/task-runner/child-executor.ts +7 -7
  29. package/src/runtime/task-runner/hybrid-tier.ts +439 -0
  30. package/src/runtime/task-runner/live-executor.ts +53 -0
  31. package/src/runtime/task-runner.ts +159 -51
  32. package/src/schema/config-schema.ts +13 -0
  33. package/src/skills/validate.ts +1 -1
  34. package/src/state/contracts.ts +15 -0
  35. package/src/state/stores/state-store.ts +6 -2
  36. package/src/ui/events-state-source.ts +7 -1
  37. package/src/ui/pi-ui-compat.ts +33 -0
  38. package/src/ui/program-status.ts +74 -0
  39. package/src/ui/syntax-highlight.ts +1 -1
  40. package/src/ui/terminal-status.ts +81 -2
  41. package/src/ui/theme-discovery.ts +38 -2
  42. package/src/ui/tool-progress-formatter.ts +17 -1
  43. package/src/utils/env-allowlist.ts +4 -1
  44. package/src/utils/git.ts +6 -71
  45. package/src/utils/paths.ts +18 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,233 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ## [0.11.18] — U11 hybrid 2-tier worker + Δ-wave benches/gates + windows CI repair (2026-10-12)
6
+
7
+ ### Added
8
+
9
+ - **bench(runtime): b15 — broker/scheduler task-array scan-cost microbench (Δ3)** — `bench/b15-broker-scan-cost.bench.ts` (b14 convention): measures the REAL scheduler paths (`taskGraphSnapshot`, `getReadyTasks`), a line-cited replica of the module-private `dagReadyTaskIds` call-site, the REAL crew-broker delegate/wait call-sites over a unix socket with an injected instant fake spawner, `loadRunManifestById` cold/warm floors, and the `scanZombieTempWorkspaces` walk at N=10/100/1000 in isolated mkdtemp homes. Scan-count instrumentation is bench-local (Array.prototype wrapped in-process only) — zero hot-file edits. **Δ3 verdict (bench-first rule): all 6 candidate index sites NOT-JUSTIFIED** — at realistic N≤11 tasks/run, scans cost 0.006-0.05 ms/call vs ms-scale I/O floors (loadCold 8.1 ms, DAG planner 28.8 ms @ n1000); even at 90× N, scans (0.86 ms) sit below the parse floor. **Held-lifetime audit closed no-op:** no structure is UNBOUNDED-RISK (details: `docs/perf/broker-scan-audit-2026-10-11.md`).
10
+ - **feat(runtime): U11 — hybrid 2-tier worker model (embedded tier, DEFAULT-OFF)** — per-role opt-in to the EMBEDDED worker tier (in-process Pi session on the U4 live-session stack) with the subprocess tier kept as the default and automatic fallback:
11
+ - **Config** `runtime.embeddedWorkers {enabled, roles, maxConcurrent, faultThreshold}` (types + schema + lenient parse stay in sync, F19-1 discipline; all-invalid block collapses to undefined so a malformed config can never enable the tier). With the block absent/disabled, tier routing is a byte-identical no-op — no imports, no events, no budget reads (pinned by regression tests in both lanes).
12
+ - **Routing** (`resolveTaskRuntimeKind`, optional 5th input — every pre-U11 call site unchanged): an opted-in role upgrades a child-process resolution to live-session only. `isolationPolicy.isolatedRoles`, the scaffold kind, and the `PI_CREW_DEPTH > 0` nesting guard ALWAYS beat the opt-in (the depth rule is applied to the embedded upgrade itself — extended, never weakened). The legacy `runtime.mode: live-session` path is deliberately frozen (ADR 2026-08-15 (a)) — it gets no budget/ledger semantics.
13
+ - **Orchestration** (`task-runner/hybrid-tier.ts`, lazily imported only when the policy is enabled): fail-fast embedded ceiling (blast-radius bound, default `max(1, floor(worker-cap/2))`) → SHARED global worker slot (the exact `acquireWorkerSlot` semaphore the subprocess tier uses — no concurrency bypass; abort while queued takes no slot) → durable per-task fault ledger (`task.diagnostics.embeddedTier`, disk-merged freshest-count so retries/recovery see it) → automatic fallback to subprocess after `faultThreshold` counted faults (default 2; aborts and capacity rejections never count). `tier.decision` / `tier.fault` / `tier.fallback` events registered in `TEAM_EVENT_TYPES`. The subprocess fallback runs strictly sequentially after the live attempt resolved — the single-writer sink invariant is preserved.
14
+ - **Mitigations** (`live-session/embedded-tier.ts`, gated on `embeddedMitigations` passed only for embedded-routed tasks): (a) builtin-tools-only enforcement with verify-after-set and fail-closed degradation (no `mcp__*`, no extension drift); (b) provider `timeoutMs` clamp + restore on the session's ModelRuntime; (c) turn-count watchdog (bounded grace → dispose + escape); (d) session-side concurrency cap (fail-fast, never queue); ref-counted process `uncaughtException` guard (quarantine-all embedded sessions, host kept alive, 20-quarantine circuit breaker restores default crash behavior); ring-capped rate-limited memory metrics; factory-surface + global-state asserts (U4 pattern).
15
+ - **Fix round (2026-10-11, P1)**: provider-timeout registration is now ref-counted per (ModelRuntime, providerId) with wrapper-base chasing — concurrent embedded sessions share ONE ModelRuntime, and the original apply/restore could stack wrappers and permanently leak the embedded timeout clamp onto every later session on that runtime (silently — restore reported success). The registered wrapper now always delegates to the chased BASE provider at the min of the active clamps; the base is re-registered exactly when the last session leaves; any restore order is safe (pinned by two regression tests).
16
+ - **docs(runtime): U11 DEFAULT-OFF policy guide** — `docs/usage.md` gains a "Hybrid 2-tier workers" section (config example, per-key semantics, the full safety model, fallback stickiness, `tier.*` / `live-session.embedded_*` observability) and the README config table documents `runtime.embeddedWorkers`.
17
+
18
+ ### Changed
19
+
20
+ - **fix(utils): drop dead `hosted-git-info` branch in `parseGitUrl` — Δ2 gate allowlist back to strict** — the Δ2 finding's `require()` in `src/utils/git.ts` was verified to never resolve in ANY environment (undeclared, and in the repo checkout even the transitive path via peer `@earendil-works/pi-coding-agent` is unreachable from `src/`), so the hosted-parse candidate loops were dead code in every deployment and `parseGenericGitUrl` was the only path that ever executed. Removed the require, its types/loader, and both candidate loops (zero behavior change); `OPTIONAL_RUNTIME_REQUIRES` in `scripts/check-lazy-imports.mjs` is empty again — the gate is strict, resolving the "pending `optionalDependencies` decision" note in the Δ2 entry below.
21
+
22
+ - **feat(scripts): Δ2 — declared-deps/lazy-import gate rewritten from regex to AST** (esbuild type-strip + acorn walk of `ImportDeclaration` / `export … from` / runtime `import()` / `require()`-`require.resolve()`, ports upstream check-runtime-deps semantics; per-entry budget `{maxFiles: 521, forbid: [test/, scripts/, docs/, dist/]}` for `index.bundle.ts`, ports upstream check-entry-graphs; `--root` fixture seam for tests) — closes every RR-021 residual regex blind spot; first run surfaced one real finding: `hosted-git-info` is an undeclared optional `require()` in `src/utils/git.ts` (resolves transitively via peer `@earendil-works/pi-coding-agent`; explicitly allowlisted in the gate pending an `optionalDependencies` decision).
23
+
24
+ ### Fixed
25
+
26
+ - **fix(state): register 3 mailbox event types — CI `check:event-types --enforce` green** — `mailbox.send` (`crew-broker.ts:993`), `mailbox.pickup` and `mailbox.pickup_deduped` (`inbox-poll.ts`) were emitted but missing from `TEAM_EVENT_TYPES`, failing the CI registry-enforce gate (U5 exactly-once delivery audit trail; dedup key + receipt payload only — never message bodies). Bundle note: the registry const is tree-shaken from `dist/index.mjs` (fresh build byte-identical to the committed dist — `check-bundle-staleness --committed-hash` passes with no dist delta to commit).
27
+ - **fix(test): fill 4 empty arrow-function bodies in `socket-path-fbat1.test.ts`** — comment-filled the `destroy: () => {}` / `net.createServer(() => {})` bodies that tripped biome `noEmptyBlockStatements` in CI; zero assertion changes.
28
+ - **fix(test): `verify-gate-tool` Windows path assertion — exact string compare instead of `new RegExp(path)`** — building a RegExp from an absolute Windows path consumes the backslashes as regex escapes (`\t`→TAB, `\r`→CR, `\U`/`\p` identity-dropped), so the pattern could never match the literal path (windows-latest CI failure). Now `assert.equal` on the exact command string, plus a regression pin proving a raw-backslash RegExp does NOT match a Windows path.
29
+ - **fix(test): U15 concurrent-dispose CI flake — fork-free busy loop closes the deferred-TERM-trap race** — with `while :; do sleep 1; done` there is a write→fork gap right after the readiness `echo`: dispose's group TERM lands inside that gap on loaded runners, dash defers the pending trap until the NEXT (post-signal) sleep dies (~1s) > `gracefulMs` 500, so SIGKILL beats the trap and the marker never appears (~30% flake; probe-pinned: failing runs always tReady<6ms, passing runs >20ms). `while :; do :; done` has no fork to straddle — dash runs the pending trap at the next simple-command boundary (ms), far inside the grace window. 11/11 pass locally.
30
+ - **fix(state): stop unit-test runs leaking into the real user crew root** — the
31
+ test runner now isolates the crew home per suite (`scripts/test-runner.mjs`
32
+ sets BOTH `PI_CREW_HOME` and `PI_TEAMS_HOME` to a per-suite temp dir; PI_TEAMS_HOME
33
+ wins the mirror pair, so setting only one is silently defeatable; opt-out
34
+ `PI_CREW_TEST_NO_HOME_ISOLATION=1`; cleanup on all exit paths). Until now every
35
+ fixture that created a run from a bare `/tmp` cwd routed its state to
36
+ `~/.pi/agent/extensions/pi-crew/` via `scopeBaseRoot()`'s no-repo fallback — and
37
+ every live Pi session's async-notifier toasted those fixture failures as
38
+ `Error: pi-crew run failed: team_… (inline-seam-fixture/none)` (104 leaked run
39
+ dirs since June; quarantined + cleaned 2026-10-11).
40
+ - **fix(run-index): hide terminal bare-temp-cwd runs from non-temp crew roots**
41
+ (defense-in-depth for the same leak) — `collectRuns()`'s 2.19 temp guard now
42
+ also covers the CWD dimension: in NON-temp roots (the real project/user roots)
43
+ a TERMINAL run whose cwd sits under a temp dir WITHOUT repo markers is a
44
+ test/isolated-workspace fixture parked by the no-repo fallback and is hidden.
45
+ Temp-root scans keep their original semantics (active runs liveness-gated,
46
+ terminal runs listed — prune/health consumers rely on it); temp cwds WITH repo
47
+ markers (deliberate /tmp projects, isolated worktrees) and active bare-temp-cwd
48
+ runs stay listed. By-ID resolution (`team status <runId>`) is unchanged.
49
+ Covered by `test/unit/extension/core/run-index-temp-cwd.test.ts`.
50
+
51
+ ### Docs
52
+
53
+ - **docs(u12): upstream pi-durable tracking doc** — new
54
+ `docs/reviews/pi-upstream-tracking-u12.md` (living re-check log, rerun every pi npm
55
+ release). Records the U12 spec's 4 adoption triggers with verdicts pinned at upstream
56
+ `origin/main` = `cdaf6c227`: T1 banner/API-freeze NOT met (`README.md:3` banner stands,
57
+ `[Unreleased]` opens with 5 breaking bullets), T2 multi-process NOT met (everything still
58
+ under `packages/coding-agent/src/experimental/`, `PI_EXPERIMENTAL=1`-gated), T3 subagent
59
+ conversations via services NOT met (TODO open at `services/README.md:44`), T4 concurrency
60
+ cap MET via pi-crew's own `resolveBatchConcurrency` cap (upstream `cb4375493` changed the
61
+ pass algorithm, added no cap). Appends the 7-item blacklist of unreleased post-1.1.0 churn
62
+ from the 2026-10-11 delta §5, each with verbatim `[Unreleased]` changelog wording. Overall:
63
+ still track-only (1/4 vs ≥3/4 bar); exact-pin policy unchanged.
64
+
65
+ ## [0.11.17] — upgrade wave A: pi-1.1.0 adoption, central env registry, OSC 7501 program-status (2026-10-11)
66
+
67
+ Implements the 10-item Wave A from `pi-crew-upgrade-research-round2.md` +
68
+ `pi-crew-upgrade-research-round3-deep.md` (verification-backed anchors), built by 4
69
+ lanes (W1 env/child-pi, W2 ui, W3 runtime fixes, W4 retrieval) in one shared worktree;
70
+ finalize ran the full gate battery + real-test T1/T3 + a fresh Linux bench baseline.
71
+
72
+ ### Added
73
+
74
+ - **feat(env): central env-forwarding registry (C-1)** — `src/config/env-allowlist-registry.ts`
75
+ now GENERATES `BACKGROUND_RUNNER_ENV_ALLOWLIST` (async-runner.ts) and `BASE_ALLOWLIST`
76
+ (child-pi-spawn.ts) from one decision table seeded from `config/env-vars.ts`; every
77
+ `CREW_ENV_VARS` key must carry an explicit forwarding decision (allowlist / explicit
78
+ channel / child-write / host-only / gap / test-only) — fail-fast at import + unit-tested
79
+ (no orphan entries, no dropped control vars). Content byte-identical to v0.11.16 plus the
80
+ one documented addition `PI_CREW_TOOLS_MODIFIERS`. Closes the incident class behind
81
+ 2026-09-29 (`PI_CREW_MODEL` stripped) and `44d16d94` (STATE_BACKEND trio). Registry gaps
82
+ fixed: `PI_CREW_DELEGATE_ENABLED` + `PI_CREW_ASYNC_RUN` were live read/write sites missing
83
+ from env-vars.ts. 29 runner-read vars are classified known-gaps (surfaced via
84
+ `crewEnvForwardingGapReport()`) for a follow-up wave.
85
+ - **feat(child-pi): adopt pi 1.1.0 `agent_settled.aborted` (L2-1)** — the rpc transport
86
+ feature-detects `record.aborted === true` (absent on ≤1.0.4 hosts → byte-identical legacy):
87
+ a host-cancelled settle now marks the run `aborted:true` / `crashClass:"cancelled"` (was:
88
+ healthy exit 0) and the worker is evicted from / never registered into the rpc pool — a
89
+ cancelled worker can no longer be revived as a healthy reuse candidate.
90
+ - **feat(child-pi): opt-in pi 1.1.0 `+tool` modifier spawn syntax (L2-3)** —
91
+ `PI_CREW_TOOLS_MODIFIERS=1` (default OFF) + probed host pi ≥ 1.1.0 emits declared agent
92
+ tools: as `--tools +a,+b` (additive on the default surface; no CONTROL_TOOLS merge)
93
+ instead of the legacy replacement allowlist. **Decision — default OFF even though version
94
+ detection is reliable** (`probePiVersion()` memoized + threaded into arg build): the
95
+ additive syntax changes `tools:` SEMANTICS from a least-privilege replacement allowlist
96
+ (pinned by tests + the 2026-09-10 battery) to additive on the default surface — i.e. it
97
+ would WIDEN the worker tool surface on every 1.1.0+ host, and this workspace's peer dep
98
+ is still 1.0.4 (mixed fleet). Below-floor/unknown versions keep the legacy syntax
99
+ (strict-parser safety; 1.1.0 also forbids mixing plain names with modifiers).
100
+ - **feat(ui): OSC 7501 program-status channel (B-1)** — `src/ui/program-status.ts` vendors
101
+ the upstream `@earendil-works/pi-tui` v1.1.0 wire format (MIT © 2025 Mario Zechner;
102
+ vendored — the peer dep has no 1.1.0 floor and `PROGRAM_STATUS_QUERY` is not re-exported;
103
+ never imported from the host). terminal-status.ts gains a third best-effort no-throw
104
+ channel (working / blocked+kind+message / idle / clear); the wiring derives blocked state
105
+ from durable runs — plan-approval pending, `ask`/wait park (`manifest.waitState`, 65-min
106
+ freshness matching the 1h broker deadline clamp), stuck-blocked subagent records — kind
107
+ `question` for all sources. Blocked now shows even with zero live-session agents
108
+ (child-process runs). crew-broker emits an in-process `mailbox_updated` wake after a
109
+ successful park (task.waiting / ask.requested never reach the live UI bus). Headless stays
110
+ no-op. Raw tty writer failures no longer propagate from any terminal-status path (no-throw
111
+ hardening, caught by the new C-8 rule-4 test).
112
+ - **feat(ui): host `durationMs` for tool progress (B-3)** — `formatCompactToolProgress`
113
+ prefers an optional host-measured `durationMs` (pi ≥1.1.0 ToolRenderContext.durationMs;
114
+ used only when present + numeric + finite ≥ 0, value never trusted blindly) over
115
+ self-timing; fallback unchanged. Audit result: `outputPad` has 0 usages and no
116
+ `renderShell:"self"` sites exist in src — nothing added (no apply site).
117
+ - **feat(ui): theme discovery delegates to `ctx.ui.getAllThemes()` (B-4)** — host list wins
118
+ when non-empty; empty (RPC-degraded `[]`), throwing, or missing API falls back to the
119
+ unchanged fs scan. Feature-detected shim in pi-ui-compat.ts (undefined = fallback).
120
+
121
+ ### Fixed
122
+
123
+ - **bench: strip-types break from TS parameter properties (R3-1)** —
124
+ `LiveSessionHungToolError` used `constructor(readonly …)` which strip-only mode rejects →
125
+ `register-startup.bench` rc=1 + `bench-cold-start` strip arm failed since `c1621c20`.
126
+ Converted to plain fields assigned in the constructor body (public API unchanged).
127
+ Verified: register-startup rc 1→0; bench-cold-start strip arm 10/10 iters rc=0.
128
+ - **paths: shared junk-literal guard blocks 'undefined'/'null'/'' (round 3)** — unset-var
129
+ expansion (`PI_CREW_HOME=$UNSET_VAR`) produced literal `"undefined"`/`"null"` that
130
+ anchored the config path (`config.ts resolveHomeDir`) and the run root
131
+ (`state-store createRunPaths`) into the garbage tree `undefined/.pi/…` (the stray
132
+ `pi-crew/undefined/` dir — verified 0 files via `find -type f`, deleted). New
133
+ `isJunkPathLiteral()` in `src/utils/paths.ts` (F4 pattern extended to 'null'); junk env
134
+ home → fallback `os.homedir()`; junk cwd → existing `Invalid cwd` error; legal paths
135
+ unchanged.
136
+ - **surface(herdr): graceful close kills the worker by pid first (C-3 / TODO A2)** —
137
+ `closeSurface` graceful path now SIGTERMs the worker process tree via the existing
138
+ `killProcessTree` (group kill + SIGKILL escalation), waits a 3s grace, then still runs
139
+ `pane.close` as kill-tree fallback. Pid source is an injectable `resolveWorkerPid` seam
140
+ (host wires it from `manifest.surface.workerPids`; `pane.process_info` does not exist on
141
+ wire 0.8.2 — verified). All kill-by-pid steps are best-effort NO-THROW; the force path
142
+ and real `pane.close` error semantics are unchanged; default unwired = old behavior.
143
+ NOTE: the seam is DORMANT until the host wires `resolveWorkerPid` (resolve-surface /
144
+ doctor) — follow-up item.
145
+ - **bench(b13): warm-cache case retired its junk-band query (R3-2)** — the warm query
146
+ ("verify package exports typecheck bundle", 5 abstract tokens) topped out at 0.42 under
147
+ the G23b floor `MIN_SUGGEST_SCORE=0.5`: a single keyword hit scores `(1/5)*0.6+0.3 =
148
+ 0.42`, TIED with 40+ runtime-state grazers (`state/runs/**/03_verify/status.json`
149
+ matching "verify"), so the pre-G23b PASS had been satisfied by exactly the junk suggestions G23b
150
+ exists to block, with no ordering signal in the tie. Measured decision: NO floor value
151
+ separates the bands — real 1-hit gold (0.42) sits BELOW the grazer junk band (0.45–0.47;
152
+ on a 180-keyword real-run goal, 59,281/59,281 files scored >0 with max 0.473, all
153
+ grazers) — so "recalibrate the threshold" is refuted and **the floor stays 0.5**. The
154
+ bench query moved to the regime real per-task queries live in (module-path vocabulary,
155
+ multi-hit; G23b's own tuning note: "useful path-only scores reach ~0.64") and now ranks
156
+ true gold first (`retrieval-orchestrator.test.ts` 0.60 / `retrieval-orchestrator.ts`
157
+ 0.56; 28 files ≥ floor). Regression pinned bench-harness-free in
158
+ `retrieval-orchestrator.test.ts` ("R3-2: warm cache (cached discovery, new keywords)
159
+ stays non-empty" + cached-discovery proof + every suggestion ≥ floor). b13 warm: FAIL
160
+ (files=0) → PASS (18–23ms, budget 400ms), deterministic ×3.
161
+ - **test(goal): re-pin "model env forwards" to the central registry** — the cross-file pin
162
+ read async-runner.ts source for the old allowlist literals; it now asserts the
163
+ registry-consumption anchor + runtime allowlist membership (C-1 fallout, semantics
164
+ unchanged).
165
+ - **chore: cleared pre-existing biome debt** — 5 files failed `format:check` and
166
+ `state-store-sqlite-parity.test.ts` carried 2 unused imports; all committed red at HEAD
167
+ `add29ff3` (left by earlier waves, untouched by Wave A lanes). Formatted + imports
168
+ removed so the release gates run green from a clean tree.
169
+
170
+ ### Changed
171
+
172
+ - **bench baseline replaced: win32/v24.10.0 (2026-05-14) → linux/v22.23.1 (2026-10-11)** —
173
+ the old baseline was captured on another OS/node line and could never arbitrate Linux
174
+ regressions. Captured under residual external load (an out-of-run rustc build had just
175
+ finished; ~5-min load avg ~6 decaying to ~4 on 4 cores) — treat the first 15%-threshold
176
+ comparisons as advisory until re-captured on an idle machine. Full `npm run bench`
177
+ (b1–b13 + legacy suite): 184s, all green — b13 warm 18ms PASS (budget 400ms), cold 85ms.
178
+ - **ci:fast stays bench-free (decision)** — considered adding a bench:smoke subset; NOT
179
+ added: the regression classes this wave hit are already covered by cheaper existing
180
+ gates (strip-types syntax → the `typecheck` strip-types import probe; b13 warm-cache →
181
+ the R3-2 unit pin inside npm test), bench timing assertions are machine-sensitive, and
182
+ the full bench (184s) would roughly triple the fast gate. `bench:check` remains the
183
+ deliberate comparison tool against the (now Linux) baseline.
184
+
185
+ ### Fix round (2026-10-11 C-8 review — 3 MAJOR wiring gaps closed)
186
+
187
+ Post-verdict FIX_THEN_SHIP round: the review caught three "code đúng nhưng không
188
+ wiring" gaps (feature built, producer/consumer never connected) plus two minors.
189
+ All five closed; each fix carries a regression test that fails on the pre-fix tree
190
+ (mutation-checked for MAJOR 1/2).
191
+
192
+ - **fix(child-pi): host-aborted settle marks `exitStatus.cancelled` (MAJOR 1)** —
193
+ `buildExitStatus` reported `cancelled: abortRequested` only, so a pi-1.1.0
194
+ host-cancelled settle (`agent_settled.aborted:true`) kept `exitStatus.cancelled`
195
+ false: `evidenceStatusFor()` (which reads exactly that field, not `result.aborted`)
196
+ classified the worker "completed" and the `worker.cancelled` evidence event in
197
+ child-executor.ts never fired for host aborts. Now `abortRequested || hostAbortedSettle`
198
+ (consistent with the crash classification in the same close handler). Regression:
199
+ `child-pi-rpc-abort-settle.test.ts` asserts `exitStatus.cancelled === true` (fails
200
+ pre-fix) + `assemble-attempt-outcome.test.ts` pins the host-aborted shape
201
+ (exit 0, no error, cancelled flag) → "cancelled".
202
+ - **fix(ui): team-tool progress binder feeds `durationMs` to the formatter (MAJOR 2)**
203
+ — B-3 taught `formatCompactToolProgress` to prefer a producer `durationMs`, but no
204
+ streaming binder supplied one (the field existed only on the render-side path). The
205
+ team tool binder now plumbs `durationMs: Date.now() - startedAt` on every tick.
206
+ Regression: `team-tool-progress-binder.test.ts` pins the spinner clock 600s into the
207
+ future — self-timing would report `elapsed=600s`; the producer value wins (`elapsed=0s`)
208
+ and the test fails the moment the wiring drops.
209
+ - **fix(ui): `team-settings theme*` threads the host ctx into theme discovery
210
+ (MAJOR 3)** — B-4 built host delegation (`ctx.ui.getAllThemes()` wins when non-empty)
211
+ but both theme-branch call-sites in handle-settings.ts called `discoverPiThemes()`
212
+ bare, so the host list could never win from the tool surface. `TeamContext` now
213
+ carries the optional runtime `ui` (the tool-execute ctx is an ExtensionToolContext,
214
+ so `ui` was already riding along at runtime) and both call-sites pass it. Regression:
215
+ `theme-settings-routing.test.ts` pins delegate-when-ctx-nonempty (host-only theme
216
+ listed + switches; fs-only crew theme becomes "Unknown") AND fs-fallback khi ctx
217
+ rỗng (no `ui` / missing API / empty `[]` → on-disk crew themes still listed).
218
+ - **chore(notice): attribution for the vendored OSC 7501 module (MINOR 1)** — NOTICE.md
219
+ now records `src/ui/program-status.ts` as adapted from `@earendil-works/pi-tui` v1.1.0
220
+ `packages/tui/src/program-status.ts` (MIT © 2025 Mario Zechner).
221
+ - **chore: `.gitignore` gains `temp/` (MINOR 2)** — local scratch dir was untracked
222
+ noise (`?? temp/`) on every status; now ignored.
223
+ - **Follow-up (MINOR 3, not fixed this round — deliberately out of fix-round scope):**
224
+ `src/extension/registration/terminal-status-wiring.ts:254-275` —
225
+ `deriveTerminalBlockedSignal` does sync fs reads (≤16 manifests + ≤50 subagent
226
+ JSONs) inside an eval that runs on every runEventBus event (250ms debounce) —
227
+ sync IO on the UI thread when a run is busy. Candidate fix: mtime-keyed cache or
228
+ async evaluation. Low severity (reviewer-flagged MINOR); tracked here for the next
229
+ wave.
230
+
3
231
  ## [0.11.16] — fix(bug #4): steer racing executor start no longer wiped by on-spawn truncate (2026-10-11)
4
232
 
5
233
  Third live-caught fix from the 2026-10-10 full battery (run team_20261010172900).
package/NOTICE.md CHANGED
@@ -36,6 +36,15 @@ pipe).
36
36
 
37
37
  Current scaffold status: no substantial source files have been copied verbatim; implementation is a fresh scaffold based on documented design lessons.
38
38
 
39
+ ### OSC 7501 program-status wire format (2026-10-11)
40
+
41
+ `src/ui/program-status.ts` is VENDORED (adapted) from upstream
42
+ `@earendil-works/pi-tui` v1.1.0 `packages/tui/src/program-status.ts`
43
+ (MIT © 2025 Mario Zechner). Upstream is a pure-declaration module (no
44
+ imports); the vendoring rationale (no peer version floor + the symbol is not
45
+ re-exported from the package root before 1.1.0) is documented in the file
46
+ header and `src/ui/pi-ui-compat.ts`.
47
+
39
48
  ## crew-vibes font assets
40
49
 
41
50
  - `assets/runner-spritesheet.png` and the 16 runner glyphs (U+E700..U+E70F) traced
package/README.md CHANGED
@@ -124,6 +124,7 @@ Most-used keys (full set: [docs/usage.md](docs/usage.md) · [schema.json](schema
124
124
  | Key | What it does |
125
125
  |-----|--------------|
126
126
  | `runtime.mode` 🔒 | `auto \| scaffold \| child-process \| live-session` — how workers execute |
127
+ | `runtime.embeddedWorkers` | U11 hybrid tier, **DEFAULT-OFF**: opt roles into in-process (embedded) workers with 2-fault fallback to subprocess — see [docs/usage.md](docs/usage.md#hybrid-2-tier-workers-embedded-tier-u11-default-off) |
127
128
  | `executeWorkers` 🔒 | `false` = dry-run planning only, no child processes |
128
129
  | `asyncByDefault` 🔒 | detach every run by default (survives session switches) |
129
130
  | `limits.maxConcurrentWorkers` | hard cap on parallel workers |