pi-crew 0.9.17 → 0.9.19

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,118 @@
1
1
  # Changelog
2
2
 
3
+ ## [v0.9.19] — plan-execute workflow + main-session→planner analysis handoff (2026-07-03)
4
+
5
+ New builtin workflow for the common "I already analyzed this — just plan + execute + verify it" case, plus a generic `analysis`/`analysisPath` channel on `team action='run'` for handing caller-session context to planner child workers.
6
+
7
+ ### Highlights
8
+
9
+ - **`plan-execute` builtin workflow.** 3-step sequential (plan → execute → verify), no explore step. Designed for callers who have already done the analysis and want the planner to build directly on it. The `plan` step declares `reads: analysis.md` so the caller's pre-analysis is injected via the standard sharedReads dependency-context pipeline. Workflow count: 8 → 9 (`test/unit/discovery.test.ts` updated).
10
+ - **`analysis` / `analysisPath` channel on `team action='run'`.** Two new optional params (mutually exclusive):
11
+ - `analysis` (string, ≤100 000 chars) — inline pre-analysis from the calling session
12
+ - `analysisPath` (string, file path within project) — pre-analysis loaded from a markdown file
13
+ - Both go through `sanitizeTaskText()` (SEC-007 prompt-injection stripper from `buildTaskPacket`) before being injected, so the analysis can never smuggle a directive past the planner. The text is persisted to `artifacts/{runId}/shared/analysis.md` as an audit trail. Mutual exclusivity, path containment (`resolveContainedPath` with null-byte + symlink realpath), and file-not-found / 100 KB cap are all fail-fast, checked BEFORE `createRunManifest` so validation errors never leave orphan run state. Goal-wrapped runs emit a clear `console.warn` if `analysis` is set but ignored (chain dispatch + goal-wrap don't honor v1).
14
+ - **`reads` injection is correctly step-scoped.** Verified live: only the `plan` step (which declares `reads: analysis.md`) receives the analysis content; `execute` and `verify` prompts contain zero unique analysis headings even though the goal text references the analysis file path. This is the intended behavior — the filter limits *dependency-injected* content, not the goal itself.
15
+
16
+ ### Cross-platform fix (was blocking Windows CI)
17
+
18
+ `run-analysis.test.ts` failed on macOS + Windows because `writeArtifact` stores canonicalized paths via `resolveInside`, while the test compared against a path built from raw `mkdtempSync` cwd. Two fixes:
19
+ 1. `fs.realpathSync` the test cwd in `makeRunCwd` — closes the macOS symlink (`/var` → `/private/var`) case.
20
+ 2. Switched the `manifest.artifacts[]` lookup to a normalized suffix compare (`a.path.replace(/\\/g, "/").endsWith("shared/analysis.md")`) — closes the Windows drive-letter-case + separator case. Robust against both realpath drift and Windows path normalization.
21
+
22
+ ### Defense-in-depth
23
+
24
+ - `analysisPath` file size is `statSync`-checked against the same 100 KB cap as the inline channel (prevents prompt-size blowup via the file route).
25
+ - `sanitizeTaskText` applied to both inline AND file content before any persistence or injection.
26
+ - Path traversal on `analysisPath` is rejected with the same `resolveContainedPath` machinery used by other path-taking params (symlink-canonicalized + null-byte guarded).
27
+
28
+ ### Verification
29
+
30
+ | Gate | Result |
31
+ |---|---|
32
+ | TSC | ✅ |
33
+ | Lint | ✅ |
34
+ | format:check | ✅ |
35
+ | check:conflict-markers | ✅ |
36
+ | check:lazy-imports | ✅ |
37
+ | check:bundle-staleness | ✅ (dist rebuilt at 3011.0 KB) |
38
+ | test:unit (run-analysis) | ✅ 9/9 (with --test-timeout=120000) |
39
+ | test:unit (plan-execute-workflow) | ✅ 3/3 |
40
+ | test:unit (discovery, +1 workflow) | ✅ updated assert 8→9 |
41
+ | Live E2E plan-execute + inline analysis | ✅ 3/3 tasks, consistency=1 |
42
+ | Live E2E plan-execute + analysisPath (file) | ✅ planner + executor passed; verifier hit pre-existing child-Pi hang (unrelated) |
43
+ | CI Ubuntu / Node 22 | ✅ |
44
+ | CI macOS / Node 22 | ✅ |
45
+ | CI Windows / Node 22 | ✅ |
46
+ | CI fallow audit | ✅ |
47
+
48
+ ### Changed
49
+
50
+ - `workflows/plan-execute.workflow.md` — new builtin workflow (30 lines).
51
+ - `src/schema/team-tool-schema.ts:264-279` — new `analysis` + `analysisPath` params on `TeamToolParams` + matching interface fields.
52
+ - `src/extension/team-tool/run.ts` — new `resolveAnalysisText()` helper (fail-fast validation + sanitize); analysis artifact write before `atomicWriteJson` of updated manifest; `reads: ["analysis.md"]` injected into direct-agent synthetic workflow when analysis is set; goal-wrap path emits a warning when analysis is provided but ignored.
53
+ - `test/unit/discovery.test.ts:17` — workflows count 8 → 9.
54
+ - `test/unit/plan-execute-workflow.test.ts` — new (46 lines, 3 tests).
55
+ - `test/unit/run-analysis.test.ts` — new (242 lines, 9 tests including size cap, path traversal, mutual exclusion, file-missing).
56
+
57
+ ### Migration notes
58
+
59
+ - Existing `team` tool callers are unaffected — both `analysis` and `analysisPath` are optional. Workflow count is `discoverWorkflows`-reflected, so `team action='list', resource='workflow'` now shows 9 builtin entries instead of 8.
60
+ - No new dependencies. All new code uses existing `sanitizeTaskText`, `resolveContainedPath`, and `writeArtifact` machinery.
61
+ - `plan-execute` joins the builtin workflow family alongside `default`, `fast-fix`, `research`, `review`, `implementation`, `pipeline`, `parallel-research`, and `chain`.
62
+
63
+ ### Known limitation (out of scope for v0.9.19)
64
+
65
+ - Goal-wrapped runs and chain dispatch ignore the `analysis` param in v1 (with a `console.warn`). If callers need analysis in those modes, file an issue and we can plumb it through `goal.ts` / `chain-dispatch.ts` in a follow-up.
66
+
67
+ ## [v0.9.18] — perf fix bundle-mode spawn + config cache (2026-07-02)
68
+
69
+ Five commits addressing items from the v0.9.17 performance review (`docs/perf/performance-review-2026-07.md`):
70
+
71
+ ### Highlights
72
+
73
+ - **CRITICAL — fix bundle-mode background runner spawn.** `spawnBackgroundTeamRun` in `src/runtime/async-runner.ts:226` was computing the `background-runner.ts` path via `import.meta.url-relative` resolution. The path landed correctly in source (strip-types loader) but BROKE in the bundle (default v0.9.17+): esbuild's `__esm` helper does not preserve per-module `import.meta.url`, so the path resolved to `<pi-crew>/background-runner.ts` (missing `src/runtime/`). Spawned runners then ENOENTed at ~4s into every team run. Fixed with `packageRoot()` from `utils/paths.ts` — mirrors the same pattern as the v0.9.17 fix in `pi-args.ts:10` (commit `0dd93e0`). Verified live: 3 E2E team runs after the fix (test-coalesce-static, fast-fix, research) all spawned the background runner cleanly.
74
+ - **F4 mitigation — wire `saveRunTasksCoalesced` into the checkpoint path.** The 50ms-debounce coalescer in `state-store.ts:428` had been dormant (0 callers). Now called from `persistSingleTaskUpdate` (called ~5× per task from `task-runner.ts:233, 424, 538, 617, 1347`). Two safety guards: `flushPendingAtomicWrites()` at the top of the mtime-CAS retry loop (defeats the stale-read window under concurrent coalesced writers) and the mtime CAS itself still guards against concurrent non-coalesced writers. Trade-off: checkpoint writes are now best-effort within a 50ms window — terminal writes still use full fsync via `saveRunTasks`.
75
+ - **F16 quick win — 2s TTL+mtime cache for `loadConfig`.** `loadConfig` had 78 callers (top: `register.ts` 11, `registration/ui.ts` 6, `team-tool.ts` 5) and was called 1 Hz idle / 6 Hz active with zero cache. Each call reads up to 4 files (legacy, user, `.crew/config.json`, `.pi/pi-crew.json`), parses JSON, runs full TypeBox `Value.Check` validation, and merges. New cache follows the same pattern as `manifest-cache.ts`. Cache key is a deterministic JSON encoding of `(filePath, legacyPath, projectPath, projectPiCrewJsonPath, cwd)`. On hit, return cached value without parsing; on miss or mtime change, re-parse. New exports for tests/ops: `__test__setConfigCacheTtlMs`, `__test__getConfigCacheTtlMs`, `__test__getConfigCacheEntry`, `__test__configCacheSize`, `invalidateConfigCache`, `flushConfigCache`. Caveat documented: caches for 2s even if the user just edited their config in a separate process — acceptable for the perf win.
76
+ - **D — documented atomic-write-v2 migration plan.** New `docs/migration/atomic-write-v2-migration.md` (297 lines) covers why migrate (F3, F4, F6: drop the dir-fsync cost added by 13f4490), API differences, 3-phase migration plan (dual-write behind feature flag → switch default → deprecate v1), risks + mitigations, effort estimate (M = 3-5 days), and a MIGRATE decision. Existing `atomic-write-v2.ts` (0 callers today) is the v2 surface; v1 (`atomic-write.ts`) keeps symlink-safety + link+unlink atomicity. Phase 1 is gated by `PI_CREW_ATOMIC_WRITER` env flag with instant rollback.
77
+
78
+ ### Verification
79
+
80
+ | Gate | Result |
81
+ |---|---|
82
+ | TSC | ✅ |
83
+ | Lint | ✅ |
84
+ | format:check | ✅ |
85
+ | check:conflict-markers | ✅ |
86
+ | check:lazy-imports | ✅ |
87
+ | check:bundle-staleness | ✅ |
88
+ | test:unit local (config-cache) | ✅ 7/7 |
89
+ | test:unit local (safe-bash, post-style-fix) | ✅ 26/26 |
90
+ | test:unit local (coalesce + atomic-write-coalesced + file-coalescer + progress-event-coalescer) | ✅ 26/26 |
91
+ | Live E2E: test-coalesce-static (3 tasks) | ✅ all 3 resultArtifacts + heartbeats + clean closeout |
92
+ | Live E2E: fast-fix (explore→execute→verify) | ✅ consistency=1, 14 min |
93
+ | Live E2E: research (explore→analyze→write) | ✅ consistency=1, summary 4.7KB |
94
+ | CI Ubuntu / Node 22 | ✅ (post-push) |
95
+ | CI macOS / Node 22 | ✅ (post-push) |
96
+ | CI Windows / Node 22 | ✅ (post-push) |
97
+
98
+ ### Changed
99
+
100
+ - `src/runtime/async-runner.ts:224-235` — `runnerPath` now uses `packageRoot()` (1 import added at line 11).
101
+ - `src/runtime/task-runner/state-helpers.ts:1-2, 57-69, 121-127` — wire `saveRunTasksCoalesced` + `flushPendingAtomicWrites` guard.
102
+ - `src/state/state-store.ts:425-434` — export `saveRunTasksCoalesced` (was local), update doc comment.
103
+ - `src/config/config.ts:69-166, 1077-1100` — new cache module + cache-aware `loadConfig`.
104
+ - `test/unit/config-cache.test.ts` (new, 242 lines, 7 tests).
105
+ - `docs/migration/atomic-write-v2-migration.md` (new, 297 lines) — migration plan + decision.
106
+ - `docs/perf/performance-review-2026-07.md` — verification report (added in v0.9.18 cycle).
107
+ - 31 files via biome auto-fix (`style: biome auto-fixes` commit `299338e`) — import-sort + minor semantic.
108
+
109
+ ### Migration notes
110
+
111
+ - No public-API breaking changes. Existing workflows and configs continue to work without modification.
112
+ - The `loadConfig` cache is transparent — first call hits disk, subsequent calls within 2s return cached value. To force a refresh (e.g. after a config edit), call `invalidateConfigCache()` from a custom integration or just wait 2s.
113
+ - The `saveRunTasksCoalesced` swap is checkpoint-only; terminal writes remain fully durable. If a process crashes mid-50ms-buffer, the last checkpoint may be lost but the on-disk `manifest.json` + `tasks.json` source of truth is preserved.
114
+ - The atomic-write-v2 migration plan describes a 3-phase rollout behind `PI_CREW_ATOMIC_WRITER=v1|v2` flag (default v1 until Phase 2). Users on critical/durability-sensitive deployments can opt into v2 after Phase 1 stabilizes.
115
+
3
116
  ## [v0.9.17] — coalesced micro-tasks (M6) ships + closeout race fix (2026-07-02)
4
117
 
5
118
  Two end-to-end correctness fixes for the M6 real-dispatch path + one workload-sizing refinement, plus a startup-latency fix discovered during user testing.