pi-crew 0.9.42 → 0.9.44
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 +147 -0
- package/README.md +14 -0
- package/dist/build-meta.json +6692 -13022
- package/dist/index.mjs +54585 -65621
- package/dist/index.mjs.map +4 -4
- package/package.json +1 -1
- package/scripts/build-bundle.mjs +2 -1
- package/src/agents/agent-config.ts +1 -1
- package/src/config/config.ts +1 -1
- package/src/config/types.ts +0 -2
- package/src/extension/crew-vibes/config.ts +1 -1
- package/src/extension/crew-vibes/font-detect.ts +16 -3
- package/src/extension/cross-extension-rpc.ts +8 -4
- package/src/extension/registration/commands.ts +5 -1
- package/src/extension/registration/foreground-run-controller.ts +28 -0
- package/src/extension/team-tool.ts +5 -0
- package/src/prompt/prompt-runtime.ts +15 -0
- package/src/runtime/child-pi-constants.ts +42 -0
- package/src/runtime/child-pi-kill.ts +180 -0
- package/src/runtime/child-pi-spawn.ts +234 -0
- package/src/runtime/child-pi-steering.ts +128 -0
- package/src/runtime/child-pi-streams.ts +296 -0
- package/src/runtime/child-pi-transcript.ts +169 -0
- package/src/runtime/child-pi.ts +75 -837
- package/src/runtime/compact-stages/tail-capture-stage.ts +1 -1
- package/src/runtime/dwf-state-store.ts +5 -0
- package/src/runtime/dynamic-workflow-context.ts +78 -18
- package/src/runtime/dynamic-workflow-runner.ts +18 -2
- package/src/runtime/goal-evaluator.ts +59 -27
- package/src/runtime/goal-loop-runner.ts +40 -11
- package/src/runtime/live-agent-manager.ts +18 -0
- package/src/runtime/pi-json-output.ts +2 -1
- package/src/runtime/pi-spawn.ts +7 -1
- package/src/runtime/run-coalesced-task-group.ts +18 -10
- package/src/runtime/task-runner/prompt-builder.ts +2 -2
- package/src/runtime/team-runner.ts +6 -1
- package/src/state/event-log.ts +1 -0
- package/src/state/locks.ts +132 -49
- package/src/state/worker-atomic-writer.ts +1 -0
- package/src/utils/paths.ts +1 -1
- package/src/worktree/worktree-manager.ts +47 -19
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,153 @@
|
|
|
2
2
|
|
|
3
3
|
> **Note:** `atomic-write-v2.ts` / `AtomicWriter` mentioned in historical entries below was consolidated into `atomic-write.ts` as of v0.9.42. This changelog is preserved as historical record — the migration was completed (the v2 class was never adopted; v1 won on simplicity + symlink-safety + link+unlink atomicity). See `docs/migration/atomic-write-v2-migration.md` for the decision rationale.
|
|
4
4
|
|
|
5
|
+
|
|
6
|
+
## [0.9.44] — 3 flaky CI test fixes (2026-07-19)
|
|
7
|
+
|
|
8
|
+
Three pre-existing flaky tests in the CI suite have been fixed, completing
|
|
9
|
+
the CI green-light requirement. All three were verified by repeated
|
|
10
|
+
local runs (≥30 iterations each) and a green CI run on the merge commit
|
|
11
|
+
(ubuntu/macos/windows Node 22 all ✅, fallow audit ✅).
|
|
12
|
+
|
|
13
|
+
### Lock subsystem fixes (`src/state/locks.ts`)
|
|
14
|
+
|
|
15
|
+
- **ENOENT canSteal fix in `readLockSnapshot`** — previously returned
|
|
16
|
+
`canSteal: false` when the lock file was missing between the EEXIST
|
|
17
|
+
signal and the read, causing spurious "locked" errors in
|
|
18
|
+
`parallel-research-dynamic.test.ts` (9/10 local reproduction rate).
|
|
19
|
+
Now returns `canSteal: true` so the holder-released-mid-retry window
|
|
20
|
+
is handled correctly.
|
|
21
|
+
- **New `releaseOwnLock`** — unconditional `fs.rmSync` bypass of the
|
|
22
|
+
token-match check in `releaseLock`. Used by `withRunLockSync` /
|
|
23
|
+
`withRunLock` because same-process re-acquisition uses fresh
|
|
24
|
+
`randomUUID()` tokens that never match the stored token, so
|
|
25
|
+
`releaseLock` was silently never deleting lock files between calls
|
|
26
|
+
(strace showed many `openat(O_CREAT|O_EXCL)` calls but zero
|
|
27
|
+
`unlinkat` calls — lock file accumulation until EEXIST).
|
|
28
|
+
- **`treatOwnPidAsStealable` parameter on `readLockSnapshot`** — only
|
|
29
|
+
the run-lock async path passes `true`. The sync file-lock path
|
|
30
|
+
(`withFileLockSync`, used by `round26-file-locks.test.ts`) keeps
|
|
31
|
+
the default `false` to preserve the multi-process safety guarantee
|
|
32
|
+
("don't steal a fresh lock held by a live process — even if our own
|
|
33
|
+
pid"). Without this option split, the first fix attempt regressed
|
|
34
|
+
the existing `round26-file-locks` test which specifically tests that
|
|
35
|
+
behavior.
|
|
36
|
+
|
|
37
|
+
### Test fix (`test/unit/event-log-seq-uniqueness.test.ts`)
|
|
38
|
+
|
|
39
|
+
- **B7 test 3 uses `appendEventAsync` instead of `appendEventBuffered`**
|
|
40
|
+
— the 20ms buffered-event timer occasionally lost the race against
|
|
41
|
+
`--test-force-exit`'s suite-finalization deadline (~8ms cancellation
|
|
42
|
+
observed on CI), causing `cancelledByParent` failures with error
|
|
43
|
+
`'Promise resolution is still pending but the event loop has already
|
|
44
|
+
resolved'`. Tests 1 and 2 still cover the full sync/async/buffered
|
|
45
|
+
3-path seq-uniqueness contract; test 3 now focuses on the
|
|
46
|
+
explicit-vs-auto seq-assignment contract using only sync + async
|
|
47
|
+
paths. This avoids the buffered timer entirely while preserving the
|
|
48
|
+
original B7 invariant.
|
|
49
|
+
|
|
50
|
+
### Verification
|
|
51
|
+
|
|
52
|
+
- Local: 6184/6187 unit + 177/178 integration tests pass (3+1 skipped).
|
|
53
|
+
- CI: ubuntu/macos/windows Node 22 all ✅, fallow audit ✅.
|
|
54
|
+
- Three independent CI runs after each fix confirmed zero regressions.
|
|
55
|
+
|
|
56
|
+
## [0.9.43] — 4-wave upgrade + live LLM verification (2026-07-19)
|
|
57
|
+
|
|
58
|
+
A comprehensive upgrade pass was completed on top of v0.9.42: 4 implementation waves
|
|
59
|
+
plus H-1 (lock re-entrance) and H-7 step 1–6 (runChildPi decomposition), verified
|
|
60
|
+
end-to-end with real LLM calls on a real pi session (not mocked). All changes
|
|
61
|
+
were driven by an in-depth audit (`UPGRADE_REVIEW.md` — 647 lines, ~112 unique
|
|
62
|
+
findings) with cold-verification and live test feedback catching regressions
|
|
63
|
+
mock tests had missed.
|
|
64
|
+
|
|
65
|
+
### Wave 1 — Security + correctness (16 fixes)
|
|
66
|
+
|
|
67
|
+
- **H-3/H-4** `scripts/build-bundle.mjs` — bundle externalized `acorn` (~225 KB) and fixed `@sinclair/typebox` package name (~245 KB). Total **−481 KB** bundle.
|
|
68
|
+
- **M-23 / COAL-1** `prompt-builder.ts` + `run-coalesced-task-group.ts` — both prompt builders now `sanitizeTaskText` before injection (closes 2 prompt-injection bypasses).
|
|
69
|
+
- **M-22** `cross-extension-rpc.ts` — `pi-crew:live-control` event channel now wrapped with `withHmacVerification` (was the only state-mutating RPC channel without auth).
|
|
70
|
+
- **DISC-1** `dynamic-workflow-runner.ts` — `.dwf.ts` determinism check now transpiles TS→JS via `esbuild` before acorn parse. Restores the round-13 P0-2 enforcement that had been silently no-op'd by acorn's JS-only parser.
|
|
71
|
+
- **NEW-D1** `team-runner.ts` — merge path now calls `flushPendingAtomicWrites()` before `loadRunManifestById`. Closes the coalesced-write-cancellation lost-update window.
|
|
72
|
+
- **M-18 / M-19 / T-S1** — event-log buffered-timer `unref()`, dead-worker `worker = undefined` reset, and `handleSteer` terminal-status guard (rejects steer to completed/failed/cancelled tasks).
|
|
73
|
+
- **NEW-C1 / C5 / C7 / C13 / C17** — config dead-field deleted; token cap covers `max_completion_tokens`/`max_output_tokens`/`generationConfig.max_output_tokens`; tail-capture empty-tail slice fixed; `PI_CREW_HOME` alias added; doc comment env-var name fixed.
|
|
74
|
+
- **CV-NEW-1** `font-detect.ts` — `isWebTerminal()` cached (was 12 sync reads per render tick).
|
|
75
|
+
- **CMD-NEW-2** `commands.ts` — `--var` value split fixed (was `split("=", 2)` which lost values containing `=`).
|
|
76
|
+
|
|
77
|
+
### CP-1 — turn-limit hard-abort escalation
|
|
78
|
+
|
|
79
|
+
`child-pi.ts` turn-limit hard-abort now uses `killProcessTree` (same as abort/noResponseTimer paths) and sets a `hardAbortInitiated` flag so `onJsonEvent` stops restarting the no-response timer. Prevents SIGTERM-ignoring runaway children. `HB-003a` source-contract test updated to verify the new behavior.
|
|
80
|
+
|
|
81
|
+
### Wave 2 — Budget / Worker cap / Worktree / Coalesced (6 fixes)
|
|
82
|
+
|
|
83
|
+
- **BDG-1** `goal-evaluator.ts` — judge token usage now returned and accumulated into `budgetUsed` (was discarded, systematically undercounted budget by 20–30%).
|
|
84
|
+
- **GL-1** `goal-loop-runner.ts` — loop checks `turnResult.manifest.status` after each turn; stops early on `blocked`/`failed` instead of burning the full `maxTurns` budget on a dead-end.
|
|
85
|
+
- **DLOCK-1** `dynamic-workflow-context.ts` — `ctx.agent()` now goes through `withWorkerSlot`, finally respecting the global worker cap (`PI_CREW_MAX_WORKERS`). Docstring claim was previously false.
|
|
86
|
+
- **ERR-1** `dynamic-workflow-runner.ts` — script timeout now aborts a combined `AbortSignal`, so spawned `runChildPi` children are killed instead of leaking.
|
|
87
|
+
- **N-1** `worktree-manager.ts` — `snapshotDirtyWorktree` failure now causes the caller to skip the discard (preserves dirty work instead of losing it). The previous behavior would silently destroy work if the snapshot artifact write failed.
|
|
88
|
+
- **N-2** `live-agent-manager.ts` — `evictStaleLiveAgentHandles` no longer treats `session.pid === undefined` (the in-process case) as dead. Previously every in-process live agent was killed after 30 min idle.
|
|
89
|
+
- **COAL-2** `run-coalesced-task-group.ts` — coalesced dispatch wrapped in `executeWithRetry`. One transient failure no longer fails all N tasks.
|
|
90
|
+
|
|
91
|
+
### Wave 3 — Observability + Budget reserve + DWF resume (4 fixes)
|
|
92
|
+
|
|
93
|
+
- **OBS-NEW-1/2** `foreground-run-controller.ts` — emits per-task `crew.task.completed/failed/needs_attention` events at run completion with `durationMs` and `tokens`. Added `durationMs` to `crew.run.completed`. Fixes task-level metrics that were always zero.
|
|
94
|
+
- **BDG-2** `dynamic-workflow-context.ts` — reserve-then-adjust token budget. Before spawn, reserve estimate (4096 tokens); after spawn, adjust by `actualUsage − estimate`. Prevents N concurrent calls from each overspending by `perCallCost`.
|
|
95
|
+
- **PERS-1** `dynamic-workflow-context.ts` — per-agent-call idempotency cache stored in checkpoint (`completedAgentCalls`). On resume, cached calls are skipped (return cached result). Previously a DWF resume re-ran the entire script, duplicating artifacts/mailbox/tokens.
|
|
96
|
+
|
|
97
|
+
### H-1 — AsyncLocalStorage re-entrance guard (root-cause class)
|
|
98
|
+
|
|
99
|
+
`src/state/locks.ts` — `withRunLock`/`withRunLockSync` now track re-entrance via `AsyncLocalStorage<Set<string>>` instead of a module-global `Map<filePath, token>`. True nested calls in the same async context still bypass (no deadlock). Calls from a DIFFERENT async context (e.g. a child-stdout event handler firing while an async merge holder is awaiting) no longer bypass — they properly serialize against the on-disk lock.
|
|
100
|
+
|
|
101
|
+
### H-7 — `runChildPi` decomposition (6 steps, −572 lines / −31.1%)
|
|
102
|
+
|
|
103
|
+
`src/runtime/child-pi.ts` reduced from **1842 → 1270 lines**. Code extracted into 4 self-contained modules with zero behavior change verified by 147 tests + live LLM:
|
|
104
|
+
|
|
105
|
+
| Step | Module | Lines | Purpose |
|
|
106
|
+
|------|--------|-------|---------|
|
|
107
|
+
| 1 | `child-pi-transcript.ts` | 169 | Transcript batching (50 ms debounce) + compaction helpers |
|
|
108
|
+
| 2 | `child-pi-kill.ts` | 180 | `killProcessTree`, `appendBoundedTail`, active-children bookkeeping |
|
|
109
|
+
| 3 | `child-pi-constants.ts` | 42 | Shared timing/buffer constants |
|
|
110
|
+
| 4 | `child-pi-streams.ts` | 296 | `ChildPiLineObserver` + line-level compaction |
|
|
111
|
+
| 5 | `child-pi-steering.ts` | 128 | `ChildPiSteeringController` state machine (turn-limit, soft/hard abort) |
|
|
112
|
+
| 6 | `child-pi-spawn.ts` | 226 | `buildChildPiSpawnOptions`, `prepareSpawnContext`, env allowlist |
|
|
113
|
+
|
|
114
|
+
Steps 1–4 verified clean on first commit. Step 5 required updating the `HB-003a`
|
|
115
|
+
source-contract test (steering logic moved to its own module). Step 6 required
|
|
116
|
+
updating the assertion to check `builtEnv` (control vars only) rather than
|
|
117
|
+
`mergedEnv` (which includes process.env spread).
|
|
118
|
+
|
|
119
|
+
### Live-test-only bug fixes (caught by real pi binary, missed by mocks)
|
|
120
|
+
|
|
121
|
+
- **Token usage not captured** — `src/runtime/pi-json-output.ts` `extractUsage` now recursively looks into `obj.message.usage` (pi nests usage under `message` for `message_end`/`turn_end` events). Mock tests passed because `PI_TEAMS_MOCK_CHILD_PI` short-circuits the spawn path entirely; only real `--mode json` output exercises `extractUsage`.
|
|
122
|
+
- **child-pi spawns wrong binary** — `src/runtime/pi-spawn.ts` `resolvePiCliScript` previously trusted `process.argv[1]` unconditionally. When invoked from a standalone test script, `argv1` was the test script and child-pi spawned it as if it were pi. Fix: only trust `argv1` when `resolvePiPackageRoot()` succeeds (current process is running from the pi-coding-agent package).
|
|
123
|
+
- **Worktree mode blocked by own .gitignore** — `src/worktree/worktree-manager.ts` `assertCleanLeader` used `git status --porcelain` without `--untracked-files=no`. After pi-crew's `ensureCrewDirectory` auto-creates `.gitignore`, that file shows as untracked and blocks worktree mode. Fix: add `--untracked-files=no` so only tracked changes are checked. Applied to both sync (`assertCleanLeader`) and async (`assertCleanLeaderAsync`) variants.
|
|
124
|
+
|
|
125
|
+
### Live test coverage (real pi binary + real LLM, on session restart)
|
|
126
|
+
|
|
127
|
+
14 live tests run end-to-end across 3 waves — all green:
|
|
128
|
+
|
|
129
|
+
| Wave | Feature | Result |
|
|
130
|
+
|------|---------|--------|
|
|
131
|
+
| A1 | 3 concurrent runs, unique runIds, no state leakage | PASS |
|
|
132
|
+
| A2 | Steer to completed task → rejected with `T-S1` error | PASS |
|
|
133
|
+
| A3 | Long research run (5 key points + explanations) | PASS · 8,302 tokens / 124 s |
|
|
134
|
+
| A4 | Cancel completed run is safe no-op | PASS |
|
|
135
|
+
| A5 | Steer to nonexistent runId → graceful error | PASS |
|
|
136
|
+
| B3a | Invalid model → fallback to `zai/glm-5.2` agent default | PASS |
|
|
137
|
+
| B3b | Empty goal → graceful error | PASS |
|
|
138
|
+
| B3c | Long goal stress (multi-paragraph objective) | PASS · 5,247 tokens / 178 s |
|
|
139
|
+
| C1 | Worktree mode (clean git repo, after fix) | PASS |
|
|
140
|
+
| C2 | Original file preserved across worktree cleanup (N-1 fix) | PASS |
|
|
141
|
+
| C3 | `implementation` workflow creates `math.js` with `subtract` function | PASS |
|
|
142
|
+
| C4 | `plan` action returns 4-step plan | PASS |
|
|
143
|
+
|
|
144
|
+
Mock tests: 30/31 pass (1 pre-existing skip).
|
|
145
|
+
|
|
146
|
+
### Files
|
|
147
|
+
|
|
148
|
+
- `UPGRADE_REVIEW.md` — 647-line audit report (all findings + cold verification + live verification).
|
|
149
|
+
- `test/functional/pi-crew-live.test.ts` + `pi-crew-live-broad.test.ts` — 16 live integration tests run against the real pi binary + real LLM provider.
|
|
150
|
+
|
|
151
|
+
|
|
5
152
|
## [0.9.42] — 107-finding deep review + arch cleanup (2026-07-17)
|
|
6
153
|
|
|
7
154
|
### Deep Review Resolution
|
package/README.md
CHANGED
|
@@ -279,6 +279,20 @@ The advisory is **informational only** — there is no `force:true` flag needed
|
|
|
279
279
|
- `test/unit/topology-analyzer.test.ts` — 13 cases (each topology + edge cases)
|
|
280
280
|
- `test/unit/preflight-validator.test.ts` — 11 cases (each level + advisory contract)
|
|
281
281
|
|
|
282
|
+
|
|
283
|
+
- `test/functional/pi-crew-live.test.ts` + `test/functional/pi-crew-live-broad.test.ts` — 16 live integration tests run against the **real pi binary + real LLM provider** (verified after v0.9.42 audit, ~26 commits). Use these when you want to confirm end-to-end behavior, not just unit-level invariants.
|
|
284
|
+
|
|
285
|
+
## Recent changes (since v0.9.42)
|
|
286
|
+
|
|
287
|
+
A 4-wave audit + fix pass was completed (see `UPGRADE_REVIEW.md` for the full 647-line report and `CHANGELOG.md` for the diff):
|
|
288
|
+
|
|
289
|
+
- **−481 KB** bundle size (externalized `acorn` + fixed `@sinclair/typebox` name).
|
|
290
|
+
- **−31.1%** in `child-pi.ts` (1842 → 1270 lines via 6 decomposition steps).
|
|
291
|
+
- **~30 bug fixes** across security, correctness, budget enforcement, worker cap, observability, and worktree isolation.
|
|
292
|
+
- **Lock re-entrance guard** via `AsyncLocalStorage` (H-1) — fixes a root-cause mutual-exclusion violation.
|
|
293
|
+
- **Task-level metrics now functional** (OBS-NEW-1/2) — `crew.task.{count,duration_ms,tokens_total}` were always zero; now emit on every run completion.
|
|
294
|
+
- **Live-test-only bugs found** (mock tests had passed): token usage not captured (nested `obj.message.usage`), child-pi spawning wrong binary (`argv1` trust heuristic), worktree mode blocked by own `.gitignore`.
|
|
295
|
+
|
|
282
296
|
## Builtin Agents
|
|
283
297
|
|
|
284
298
|
```
|