pi-crew 0.11.15 → 0.11.17

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/CHANGELOG.md CHANGED
@@ -1,5 +1,192 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.11.17] — upgrade wave A: pi-1.1.0 adoption, central env registry, OSC 7501 program-status (2026-10-11)
4
+
5
+ Implements the 10-item Wave A from `pi-crew-upgrade-research-round2.md` +
6
+ `pi-crew-upgrade-research-round3-deep.md` (verification-backed anchors), built by 4
7
+ lanes (W1 env/child-pi, W2 ui, W3 runtime fixes, W4 retrieval) in one shared worktree;
8
+ finalize ran the full gate battery + real-test T1/T3 + a fresh Linux bench baseline.
9
+
10
+ ### Added
11
+
12
+ - **feat(env): central env-forwarding registry (C-1)** — `src/config/env-allowlist-registry.ts`
13
+ now GENERATES `BACKGROUND_RUNNER_ENV_ALLOWLIST` (async-runner.ts) and `BASE_ALLOWLIST`
14
+ (child-pi-spawn.ts) from one decision table seeded from `config/env-vars.ts`; every
15
+ `CREW_ENV_VARS` key must carry an explicit forwarding decision (allowlist / explicit
16
+ channel / child-write / host-only / gap / test-only) — fail-fast at import + unit-tested
17
+ (no orphan entries, no dropped control vars). Content byte-identical to v0.11.16 plus the
18
+ one documented addition `PI_CREW_TOOLS_MODIFIERS`. Closes the incident class behind
19
+ 2026-09-29 (`PI_CREW_MODEL` stripped) and `44d16d94` (STATE_BACKEND trio). Registry gaps
20
+ fixed: `PI_CREW_DELEGATE_ENABLED` + `PI_CREW_ASYNC_RUN` were live read/write sites missing
21
+ from env-vars.ts. 29 runner-read vars are classified known-gaps (surfaced via
22
+ `crewEnvForwardingGapReport()`) for a follow-up wave.
23
+ - **feat(child-pi): adopt pi 1.1.0 `agent_settled.aborted` (L2-1)** — the rpc transport
24
+ feature-detects `record.aborted === true` (absent on ≤1.0.4 hosts → byte-identical legacy):
25
+ a host-cancelled settle now marks the run `aborted:true` / `crashClass:"cancelled"` (was:
26
+ healthy exit 0) and the worker is evicted from / never registered into the rpc pool — a
27
+ cancelled worker can no longer be revived as a healthy reuse candidate.
28
+ - **feat(child-pi): opt-in pi 1.1.0 `+tool` modifier spawn syntax (L2-3)** —
29
+ `PI_CREW_TOOLS_MODIFIERS=1` (default OFF) + probed host pi ≥ 1.1.0 emits declared agent
30
+ tools: as `--tools +a,+b` (additive on the default surface; no CONTROL_TOOLS merge)
31
+ instead of the legacy replacement allowlist. **Decision — default OFF even though version
32
+ detection is reliable** (`probePiVersion()` memoized + threaded into arg build): the
33
+ additive syntax changes `tools:` SEMANTICS from a least-privilege replacement allowlist
34
+ (pinned by tests + the 2026-09-10 battery) to additive on the default surface — i.e. it
35
+ would WIDEN the worker tool surface on every 1.1.0+ host, and this workspace's peer dep
36
+ is still 1.0.4 (mixed fleet). Below-floor/unknown versions keep the legacy syntax
37
+ (strict-parser safety; 1.1.0 also forbids mixing plain names with modifiers).
38
+ - **feat(ui): OSC 7501 program-status channel (B-1)** — `src/ui/program-status.ts` vendors
39
+ the upstream `@earendil-works/pi-tui` v1.1.0 wire format (MIT © 2025 Mario Zechner;
40
+ vendored — the peer dep has no 1.1.0 floor and `PROGRAM_STATUS_QUERY` is not re-exported;
41
+ never imported from the host). terminal-status.ts gains a third best-effort no-throw
42
+ channel (working / blocked+kind+message / idle / clear); the wiring derives blocked state
43
+ from durable runs — plan-approval pending, `ask`/wait park (`manifest.waitState`, 65-min
44
+ freshness matching the 1h broker deadline clamp), stuck-blocked subagent records — kind
45
+ `question` for all sources. Blocked now shows even with zero live-session agents
46
+ (child-process runs). crew-broker emits an in-process `mailbox_updated` wake after a
47
+ successful park (task.waiting / ask.requested never reach the live UI bus). Headless stays
48
+ no-op. Raw tty writer failures no longer propagate from any terminal-status path (no-throw
49
+ hardening, caught by the new C-8 rule-4 test).
50
+ - **feat(ui): host `durationMs` for tool progress (B-3)** — `formatCompactToolProgress`
51
+ prefers an optional host-measured `durationMs` (pi ≥1.1.0 ToolRenderContext.durationMs;
52
+ used only when present + numeric + finite ≥ 0, value never trusted blindly) over
53
+ self-timing; fallback unchanged. Audit result: `outputPad` has 0 usages and no
54
+ `renderShell:"self"` sites exist in src — nothing added (no apply site).
55
+ - **feat(ui): theme discovery delegates to `ctx.ui.getAllThemes()` (B-4)** — host list wins
56
+ when non-empty; empty (RPC-degraded `[]`), throwing, or missing API falls back to the
57
+ unchanged fs scan. Feature-detected shim in pi-ui-compat.ts (undefined = fallback).
58
+
59
+ ### Fixed
60
+
61
+ - **bench: strip-types break from TS parameter properties (R3-1)** —
62
+ `LiveSessionHungToolError` used `constructor(readonly …)` which strip-only mode rejects →
63
+ `register-startup.bench` rc=1 + `bench-cold-start` strip arm failed since `c1621c20`.
64
+ Converted to plain fields assigned in the constructor body (public API unchanged).
65
+ Verified: register-startup rc 1→0; bench-cold-start strip arm 10/10 iters rc=0.
66
+ - **paths: shared junk-literal guard blocks 'undefined'/'null'/'' (round 3)** — unset-var
67
+ expansion (`PI_CREW_HOME=$UNSET_VAR`) produced literal `"undefined"`/`"null"` that
68
+ anchored the config path (`config.ts resolveHomeDir`) and the run root
69
+ (`state-store createRunPaths`) into the garbage tree `undefined/.pi/…` (the stray
70
+ `pi-crew/undefined/` dir — verified 0 files via `find -type f`, deleted). New
71
+ `isJunkPathLiteral()` in `src/utils/paths.ts` (F4 pattern extended to 'null'); junk env
72
+ home → fallback `os.homedir()`; junk cwd → existing `Invalid cwd` error; legal paths
73
+ unchanged.
74
+ - **surface(herdr): graceful close kills the worker by pid first (C-3 / TODO A2)** —
75
+ `closeSurface` graceful path now SIGTERMs the worker process tree via the existing
76
+ `killProcessTree` (group kill + SIGKILL escalation), waits a 3s grace, then still runs
77
+ `pane.close` as kill-tree fallback. Pid source is an injectable `resolveWorkerPid` seam
78
+ (host wires it from `manifest.surface.workerPids`; `pane.process_info` does not exist on
79
+ wire 0.8.2 — verified). All kill-by-pid steps are best-effort NO-THROW; the force path
80
+ and real `pane.close` error semantics are unchanged; default unwired = old behavior.
81
+ NOTE: the seam is DORMANT until the host wires `resolveWorkerPid` (resolve-surface /
82
+ doctor) — follow-up item.
83
+ - **bench(b13): warm-cache case retired its junk-band query (R3-2)** — the warm query
84
+ ("verify package exports typecheck bundle", 5 abstract tokens) topped out at 0.42 under
85
+ the G23b floor `MIN_SUGGEST_SCORE=0.5`: a single keyword hit scores `(1/5)*0.6+0.3 =
86
+ 0.42`, TIED with 40+ runtime-state grazers (`state/runs/**/03_verify/status.json`
87
+ matching "verify"), so the pre-G23b PASS had been satisfied by exactly the junk suggestions G23b
88
+ exists to block, with no ordering signal in the tie. Measured decision: NO floor value
89
+ separates the bands — real 1-hit gold (0.42) sits BELOW the grazer junk band (0.45–0.47;
90
+ on a 180-keyword real-run goal, 59,281/59,281 files scored >0 with max 0.473, all
91
+ grazers) — so "recalibrate the threshold" is refuted and **the floor stays 0.5**. The
92
+ bench query moved to the regime real per-task queries live in (module-path vocabulary,
93
+ multi-hit; G23b's own tuning note: "useful path-only scores reach ~0.64") and now ranks
94
+ true gold first (`retrieval-orchestrator.test.ts` 0.60 / `retrieval-orchestrator.ts`
95
+ 0.56; 28 files ≥ floor). Regression pinned bench-harness-free in
96
+ `retrieval-orchestrator.test.ts` ("R3-2: warm cache (cached discovery, new keywords)
97
+ stays non-empty" + cached-discovery proof + every suggestion ≥ floor). b13 warm: FAIL
98
+ (files=0) → PASS (18–23ms, budget 400ms), deterministic ×3.
99
+ - **test(goal): re-pin "model env forwards" to the central registry** — the cross-file pin
100
+ read async-runner.ts source for the old allowlist literals; it now asserts the
101
+ registry-consumption anchor + runtime allowlist membership (C-1 fallout, semantics
102
+ unchanged).
103
+ - **chore: cleared pre-existing biome debt** — 5 files failed `format:check` and
104
+ `state-store-sqlite-parity.test.ts` carried 2 unused imports; all committed red at HEAD
105
+ `add29ff3` (left by earlier waves, untouched by Wave A lanes). Formatted + imports
106
+ removed so the release gates run green from a clean tree.
107
+
108
+ ### Changed
109
+
110
+ - **bench baseline replaced: win32/v24.10.0 (2026-05-14) → linux/v22.23.1 (2026-10-11)** —
111
+ the old baseline was captured on another OS/node line and could never arbitrate Linux
112
+ regressions. Captured under residual external load (an out-of-run rustc build had just
113
+ finished; ~5-min load avg ~6 decaying to ~4 on 4 cores) — treat the first 15%-threshold
114
+ comparisons as advisory until re-captured on an idle machine. Full `npm run bench`
115
+ (b1–b13 + legacy suite): 184s, all green — b13 warm 18ms PASS (budget 400ms), cold 85ms.
116
+ - **ci:fast stays bench-free (decision)** — considered adding a bench:smoke subset; NOT
117
+ added: the regression classes this wave hit are already covered by cheaper existing
118
+ gates (strip-types syntax → the `typecheck` strip-types import probe; b13 warm-cache →
119
+ the R3-2 unit pin inside npm test), bench timing assertions are machine-sensitive, and
120
+ the full bench (184s) would roughly triple the fast gate. `bench:check` remains the
121
+ deliberate comparison tool against the (now Linux) baseline.
122
+
123
+ ### Fix round (2026-10-11 C-8 review — 3 MAJOR wiring gaps closed)
124
+
125
+ Post-verdict FIX_THEN_SHIP round: the review caught three "code đúng nhưng không
126
+ wiring" gaps (feature built, producer/consumer never connected) plus two minors.
127
+ All five closed; each fix carries a regression test that fails on the pre-fix tree
128
+ (mutation-checked for MAJOR 1/2).
129
+
130
+ - **fix(child-pi): host-aborted settle marks `exitStatus.cancelled` (MAJOR 1)** —
131
+ `buildExitStatus` reported `cancelled: abortRequested` only, so a pi-1.1.0
132
+ host-cancelled settle (`agent_settled.aborted:true`) kept `exitStatus.cancelled`
133
+ false: `evidenceStatusFor()` (which reads exactly that field, not `result.aborted`)
134
+ classified the worker "completed" and the `worker.cancelled` evidence event in
135
+ child-executor.ts never fired for host aborts. Now `abortRequested || hostAbortedSettle`
136
+ (consistent with the crash classification in the same close handler). Regression:
137
+ `child-pi-rpc-abort-settle.test.ts` asserts `exitStatus.cancelled === true` (fails
138
+ pre-fix) + `assemble-attempt-outcome.test.ts` pins the host-aborted shape
139
+ (exit 0, no error, cancelled flag) → "cancelled".
140
+ - **fix(ui): team-tool progress binder feeds `durationMs` to the formatter (MAJOR 2)**
141
+ — B-3 taught `formatCompactToolProgress` to prefer a producer `durationMs`, but no
142
+ streaming binder supplied one (the field existed only on the render-side path). The
143
+ team tool binder now plumbs `durationMs: Date.now() - startedAt` on every tick.
144
+ Regression: `team-tool-progress-binder.test.ts` pins the spinner clock 600s into the
145
+ future — self-timing would report `elapsed=600s`; the producer value wins (`elapsed=0s`)
146
+ and the test fails the moment the wiring drops.
147
+ - **fix(ui): `team-settings theme*` threads the host ctx into theme discovery
148
+ (MAJOR 3)** — B-4 built host delegation (`ctx.ui.getAllThemes()` wins when non-empty)
149
+ but both theme-branch call-sites in handle-settings.ts called `discoverPiThemes()`
150
+ bare, so the host list could never win from the tool surface. `TeamContext` now
151
+ carries the optional runtime `ui` (the tool-execute ctx is an ExtensionToolContext,
152
+ so `ui` was already riding along at runtime) and both call-sites pass it. Regression:
153
+ `theme-settings-routing.test.ts` pins delegate-when-ctx-nonempty (host-only theme
154
+ listed + switches; fs-only crew theme becomes "Unknown") AND fs-fallback khi ctx
155
+ rỗng (no `ui` / missing API / empty `[]` → on-disk crew themes still listed).
156
+ - **chore(notice): attribution for the vendored OSC 7501 module (MINOR 1)** — NOTICE.md
157
+ now records `src/ui/program-status.ts` as adapted from `@earendil-works/pi-tui` v1.1.0
158
+ `packages/tui/src/program-status.ts` (MIT © 2025 Mario Zechner).
159
+ - **chore: `.gitignore` gains `temp/` (MINOR 2)** — local scratch dir was untracked
160
+ noise (`?? temp/`) on every status; now ignored.
161
+ - **Follow-up (MINOR 3, not fixed this round — deliberately out of fix-round scope):**
162
+ `src/extension/registration/terminal-status-wiring.ts:254-275` —
163
+ `deriveTerminalBlockedSignal` does sync fs reads (≤16 manifests + ≤50 subagent
164
+ JSONs) inside an eval that runs on every runEventBus event (250ms debounce) —
165
+ sync IO on the UI thread when a run is busy. Candidate fix: mtime-keyed cache or
166
+ async evaluation. Low severity (reviewer-flagged MINOR); tracked here for the next
167
+ wave.
168
+
169
+ ## [0.11.16] — fix(bug #4): steer racing executor start no longer wiped by on-spawn truncate (2026-10-11)
170
+
171
+ Third live-caught fix from the 2026-10-10 full battery (run team_20261010172900).
172
+
173
+ ### Fixed
174
+
175
+ - **`steer_subagent` claimed "Steer delivered" while the steering file stayed
176
+ 0 bytes** — root cause: the F7 on-spawn truncate's race guard compared the
177
+ file mtime against `taskDispatchStartedAtMs` (captured when the executor's
178
+ attempt loop STARTS), but `steer_subagent` accepts a steer as soon as the
179
+ manifest + subagent record exist — which can be EARLIER (queue/semaphore
180
+ gap; live timeline: manifest 17:29:00.100, steer appended 17:29:05.088,
181
+ executor baseline captured later, truncate wiped it at 17:29:05.753). The
182
+ baseline is now the run's creation time (`steerRaceBaselineMs(manifest, …)`)
183
+ — the earliest instant a steer could have been accepted. Fresh per-run
184
+ artifacts roots cannot hold pre-run residue, so the baseline only moves
185
+ earlier: the original F7 post-dispatch race case is unchanged, pre-run
186
+ residue is still wiped. Regression: `child-executor-steer-race.test.ts`
187
+ (live timeline replay + boundary + legacy-manifest fallback + structural
188
+ wiring pin).
189
+
3
190
  ## [0.11.15] — U8 sqlite async parity: coalesced mirror + runner env allowlist (2026-10-10)
4
191
 
5
192
  Second live-caught pair from the real-test battery (P2/P2b/P2c probes).
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