pi-crew 0.9.39 → 0.9.41
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 +48 -0
- package/dist/build-meta.json +19 -19
- package/dist/index.mjs +141 -56
- package/dist/index.mjs.map +3 -3
- package/docs/optimization-plan-2026-07.md +366 -0
- package/docs/phase4-triage.md +58 -0
- package/package.json +1 -1
- package/src/runtime/adaptive-plan.ts +7 -7
- package/src/runtime/child-pi.ts +135 -69
- package/src/runtime/heartbeat-watcher.ts +5 -0
- package/src/runtime/live-agent-manager.ts +0 -27
- package/src/runtime/run-coalesced-task-group.ts +6 -6
- package/src/runtime/stale-reconciler.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.9.41] — communication-layer optimization (2026-07-16)
|
|
4
|
+
|
|
5
|
+
### Performance
|
|
6
|
+
|
|
7
|
+
- **Eliminated double `JSON.parse` in `child-pi.ts` `emitLine` hot path** — `src/runtime/child-pi.ts`. The observer previously parsed each stdout line twice (once for raw assistant-text extraction, once inside `compactChildPiLine`). Now parses once and passes the result to both paths via a `preParsed` parameter. Benchmark: **2.0 → 1.0 JSON.parse/line** (~25% faster at 1000 events). Extracted shared `nonJsonLineResult` helper for the non-JSON fallback.
|
|
8
|
+
- **Batched transcript writes** — `src/runtime/child-pi.ts`. Replaced per-line `open/write/close` (3 syscalls × N lines) with a module-scoped batch buffer that flushes all accumulated lines per path in a single `open/write/close` every 50ms or on lifecycle boundaries. Added `resetTranscriptBatchState()` for test isolation.
|
|
9
|
+
- **Migrated non-terminal event writes to fire-and-forget** — `src/runtime/adaptive-plan.ts`. 4 diagnostic `adaptive.plan_*` events migrated to `appendEventFireAndForget`; 1 audit-critical event (`plan_injected`) upgraded to `await appendEventAsync` to prevent ordering inversion with subsequent task events.
|
|
10
|
+
|
|
11
|
+
### Cleanup
|
|
12
|
+
|
|
13
|
+
- **Removed dead code in `live-agent-manager.ts`** — deleted `drainIrcMessages`, `removeLiveAgentHandle`, and `listActiveLiveAgentsByWorkspace`, three internal functions with zero callers (verified via repo-wide grep; `removeLiveAgentHandle` logic was already inlined into `terminateLiveAgent`). Updated stale test comments.
|
|
14
|
+
- **Stale-comment cleanup in `child-pi.ts`** — 3 comments still referenced the removed `pendingTranscriptWrites` Set after the Phase 3 batching change; updated to describe the new batch-buffer mechanism.
|
|
15
|
+
|
|
16
|
+
### Documentation
|
|
17
|
+
|
|
18
|
+
- **Added `docs/optimization-plan-2026-07.md`** — detailed 8-phase communication-layer optimization plan with verification gates, risk assessments, and rollback procedures.
|
|
19
|
+
- **Added `docs/phase4-triage.md`** — documents the sync/async event-log migration triage, including the ordering risk between sync (filesystem lock) and async (in-process promise chain) write paths.
|
|
20
|
+
- **Added `bench/child-pi-parse.bench.ts`** + baseline/final/session-verify measurement files — reproducible benchmark for the parse-count optimization.
|
|
21
|
+
|
|
22
|
+
### Notes
|
|
23
|
+
|
|
24
|
+
- Phase 5 (`pollRunToTerminal` → fs.watch) was attempted but reverted before review rounds. The async watcher coordination is too risky for a small win. Documented as a follow-up in `docs/optimization-plan-2026-07.md`.
|
|
25
|
+
- Phases 6 (steer+control poll coalesce) and 7 (redaction trust-boundary) were skipped per the plan — Phase 6 is optional, Phase 7 was explicitly DEFER until a benchmark proves redaction is a bottleneck.
|
|
26
|
+
|
|
27
|
+
### Tests
|
|
28
|
+
|
|
29
|
+
- 6072 unit tests pass (was 6038 before)
|
|
30
|
+
- 15+ integration tests pass
|
|
31
|
+
- Lint + format:check clean (CI green on ubuntu + windows + macos)
|
|
32
|
+
- New regression tests:
|
|
33
|
+
- `test/unit/child-pi-single-parse.test.ts` — 6 tests verifying single-parse invariant and preParsed path equivalence
|
|
34
|
+
- `test/unit/transcript-batch.test.ts` — 5 tests verifying batched write correctness, ordering, and timer-path flush
|
|
35
|
+
- Updated `test/unit/live-agent-manager-cov.test.ts` — stale comments removed
|
|
36
|
+
|
|
37
|
+
## [0.9.40] — stale-reconciler fix + async dispatch + gitignore cleanup (2026-07-16)
|
|
38
|
+
|
|
39
|
+
### Fixes
|
|
40
|
+
|
|
41
|
+
- **Stale-reconciler `needs_attention` status inference** — `src/runtime/stale-reconciler.ts`. When all tasks end in `needs_attention` (no explicit failure), `reconcileStaleRun` previously marked the run `completed`. This contradicted the codebase convention in `chain-executor.ts:147` (treating `needs_attention` as a non-clean terminal). Now includes `needs_attention` in the `hasFailed` predicate, marking the run `failed` instead. Tests cover: all-`needs_attention` → failed; mix `needs_attention`+completed → failed.
|
|
42
|
+
|
|
43
|
+
### Performance
|
|
44
|
+
|
|
45
|
+
- **Async `saveRunTasks` in `runCoalescedTaskGroup`** — `src/runtime/run-coalesced-task-group.ts`. Replaced 4 synchronous `saveRunTasks` calls with `await saveRunTasksAsync` (from `state-store.ts:493`). The heartbeat `setInterval` callback was promoted to `async () =>` to support the await. With many coalesced groups running in parallel these sync writes blocked the event loop briefly; the async version uses `withRunLock` (non-blocking). No behavioral change.
|
|
46
|
+
|
|
47
|
+
### Cleanup
|
|
48
|
+
|
|
49
|
+
- **`src/**/*.js` gitignored** — `.gitignore`. 290 strip-types companion files in `src/` were untracked noise in `git status`. Added `src/**/*.js` rule. No runtime impact.
|
|
50
|
+
|
|
3
51
|
## [0.9.39] — foreground abort fix + security hardening (2026-07-15)
|
|
4
52
|
|
|
5
53
|
### Fixes
|
package/dist/build-meta.json
CHANGED
|
@@ -6175,7 +6175,7 @@
|
|
|
6175
6175
|
"format": "esm"
|
|
6176
6176
|
},
|
|
6177
6177
|
"src/state/locks.ts": {
|
|
6178
|
-
"bytes":
|
|
6178
|
+
"bytes": 17045,
|
|
6179
6179
|
"imports": [
|
|
6180
6180
|
{
|
|
6181
6181
|
"path": "node:crypto",
|
|
@@ -6598,7 +6598,7 @@
|
|
|
6598
6598
|
"format": "esm"
|
|
6599
6599
|
},
|
|
6600
6600
|
"src/state/state-store.ts": {
|
|
6601
|
-
"bytes":
|
|
6601
|
+
"bytes": 40424,
|
|
6602
6602
|
"imports": [
|
|
6603
6603
|
{
|
|
6604
6604
|
"path": "node:fs",
|
|
@@ -6751,7 +6751,7 @@
|
|
|
6751
6751
|
"format": "esm"
|
|
6752
6752
|
},
|
|
6753
6753
|
"src/runtime/live-agent-manager.ts": {
|
|
6754
|
-
"bytes":
|
|
6754
|
+
"bytes": 23837,
|
|
6755
6755
|
"imports": [
|
|
6756
6756
|
{
|
|
6757
6757
|
"path": "src/utils/internal-error.ts",
|
|
@@ -6794,7 +6794,7 @@
|
|
|
6794
6794
|
"format": "esm"
|
|
6795
6795
|
},
|
|
6796
6796
|
"src/runtime/stale-reconciler.ts": {
|
|
6797
|
-
"bytes":
|
|
6797
|
+
"bytes": 28694,
|
|
6798
6798
|
"imports": [
|
|
6799
6799
|
{
|
|
6800
6800
|
"path": "node:fs",
|
|
@@ -7387,7 +7387,7 @@
|
|
|
7387
7387
|
"format": "esm"
|
|
7388
7388
|
},
|
|
7389
7389
|
"src/runtime/child-pi.ts": {
|
|
7390
|
-
"bytes":
|
|
7390
|
+
"bytes": 73980,
|
|
7391
7391
|
"imports": [
|
|
7392
7392
|
{
|
|
7393
7393
|
"path": "node:child_process",
|
|
@@ -14343,7 +14343,7 @@
|
|
|
14343
14343
|
"format": "esm"
|
|
14344
14344
|
},
|
|
14345
14345
|
"src/runtime/run-coalesced-task-group.ts": {
|
|
14346
|
-
"bytes":
|
|
14346
|
+
"bytes": 9281,
|
|
14347
14347
|
"imports": [
|
|
14348
14348
|
{
|
|
14349
14349
|
"path": "node:fs/promises",
|
|
@@ -15133,7 +15133,7 @@
|
|
|
15133
15133
|
"format": "esm"
|
|
15134
15134
|
},
|
|
15135
15135
|
"src/runtime/adaptive-plan.ts": {
|
|
15136
|
-
"bytes":
|
|
15136
|
+
"bytes": 18395,
|
|
15137
15137
|
"imports": [
|
|
15138
15138
|
{
|
|
15139
15139
|
"path": "node:fs",
|
|
@@ -17643,7 +17643,7 @@
|
|
|
17643
17643
|
"format": "esm"
|
|
17644
17644
|
},
|
|
17645
17645
|
"src/runtime/heartbeat-watcher.ts": {
|
|
17646
|
-
"bytes":
|
|
17646
|
+
"bytes": 8429,
|
|
17647
17647
|
"imports": [
|
|
17648
17648
|
{
|
|
17649
17649
|
"path": "node:fs",
|
|
@@ -18003,7 +18003,7 @@
|
|
|
18003
18003
|
"format": "esm"
|
|
18004
18004
|
},
|
|
18005
18005
|
"src/extension/register.ts": {
|
|
18006
|
-
"bytes":
|
|
18006
|
+
"bytes": 70731,
|
|
18007
18007
|
"imports": [
|
|
18008
18008
|
{
|
|
18009
18009
|
"path": "node:fs",
|
|
@@ -18425,7 +18425,7 @@
|
|
|
18425
18425
|
"imports": [],
|
|
18426
18426
|
"exports": [],
|
|
18427
18427
|
"inputs": {},
|
|
18428
|
-
"bytes":
|
|
18428
|
+
"bytes": 6712404
|
|
18429
18429
|
},
|
|
18430
18430
|
"dist/index.mjs": {
|
|
18431
18431
|
"imports": [
|
|
@@ -20704,7 +20704,7 @@
|
|
|
20704
20704
|
"bytesInOutput": 1803
|
|
20705
20705
|
},
|
|
20706
20706
|
"src/state/state-store.ts": {
|
|
20707
|
-
"bytesInOutput":
|
|
20707
|
+
"bytesInOutput": 20475
|
|
20708
20708
|
},
|
|
20709
20709
|
"src/utils/file-coalescer.ts": {
|
|
20710
20710
|
"bytesInOutput": 1204
|
|
@@ -20725,7 +20725,7 @@
|
|
|
20725
20725
|
"bytesInOutput": 4162
|
|
20726
20726
|
},
|
|
20727
20727
|
"src/runtime/stale-reconciler.ts": {
|
|
20728
|
-
"bytesInOutput":
|
|
20728
|
+
"bytesInOutput": 16532
|
|
20729
20729
|
},
|
|
20730
20730
|
"src/runtime/worker-heartbeat.ts": {
|
|
20731
20731
|
"bytesInOutput": 580
|
|
@@ -20815,7 +20815,7 @@
|
|
|
20815
20815
|
"bytesInOutput": 1801
|
|
20816
20816
|
},
|
|
20817
20817
|
"src/runtime/child-pi.ts": {
|
|
20818
|
-
"bytesInOutput":
|
|
20818
|
+
"bytesInOutput": 48865
|
|
20819
20819
|
},
|
|
20820
20820
|
"src/runtime/heartbeat-gradient.ts": {
|
|
20821
20821
|
"bytesInOutput": 953
|
|
@@ -21472,7 +21472,7 @@
|
|
|
21472
21472
|
"bytesInOutput": 4743
|
|
21473
21473
|
},
|
|
21474
21474
|
"src/runtime/live-session-runtime.ts": {
|
|
21475
|
-
"bytesInOutput":
|
|
21475
|
+
"bytesInOutput": 30987
|
|
21476
21476
|
},
|
|
21477
21477
|
"src/subagents/live/session-runtime.ts": {
|
|
21478
21478
|
"bytesInOutput": 140
|
|
@@ -21733,7 +21733,7 @@
|
|
|
21733
21733
|
"bytesInOutput": 7286
|
|
21734
21734
|
},
|
|
21735
21735
|
"src/runtime/run-coalesced-task-group.ts": {
|
|
21736
|
-
"bytesInOutput":
|
|
21736
|
+
"bytesInOutput": 6363
|
|
21737
21737
|
},
|
|
21738
21738
|
"src/runtime/runtime-policy.ts": {
|
|
21739
21739
|
"bytesInOutput": 575
|
|
@@ -21820,7 +21820,7 @@
|
|
|
21820
21820
|
"bytesInOutput": 3799
|
|
21821
21821
|
},
|
|
21822
21822
|
"src/runtime/adaptive-plan.ts": {
|
|
21823
|
-
"bytesInOutput":
|
|
21823
|
+
"bytesInOutput": 15523
|
|
21824
21824
|
},
|
|
21825
21825
|
"src/workflows/topology-analyzer.ts": {
|
|
21826
21826
|
"bytesInOutput": 4262
|
|
@@ -22009,7 +22009,7 @@
|
|
|
22009
22009
|
"bytesInOutput": 2463
|
|
22010
22010
|
},
|
|
22011
22011
|
"src/runtime/heartbeat-watcher.ts": {
|
|
22012
|
-
"bytesInOutput":
|
|
22012
|
+
"bytesInOutput": 5993
|
|
22013
22013
|
},
|
|
22014
22014
|
"src/extension/registration/observability.ts": {
|
|
22015
22015
|
"bytesInOutput": 7512
|
|
@@ -22030,7 +22030,7 @@
|
|
|
22030
22030
|
"bytesInOutput": 3150
|
|
22031
22031
|
},
|
|
22032
22032
|
"src/extension/register.ts": {
|
|
22033
|
-
"bytesInOutput":
|
|
22033
|
+
"bytesInOutput": 47211
|
|
22034
22034
|
},
|
|
22035
22035
|
"src/runtime/batch-barrier.ts": {
|
|
22036
22036
|
"bytesInOutput": 3060
|
|
@@ -22135,7 +22135,7 @@
|
|
|
22135
22135
|
"bytesInOutput": 81
|
|
22136
22136
|
}
|
|
22137
22137
|
},
|
|
22138
|
-
"bytes":
|
|
22138
|
+
"bytes": 3178836
|
|
22139
22139
|
}
|
|
22140
22140
|
}
|
|
22141
22141
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -13483,6 +13483,9 @@ function validateRunManifestPaths(cwd, runId, manifest, stateRoot, tasksPath) {
|
|
|
13483
13483
|
return true;
|
|
13484
13484
|
}
|
|
13485
13485
|
function createRunPaths(cwd, runId = createRunId()) {
|
|
13486
|
+
if (!cwd || typeof cwd !== "string") {
|
|
13487
|
+
throw new Error(`Invalid cwd: ${cwd}`);
|
|
13488
|
+
}
|
|
13486
13489
|
assertSafePathId("runId", runId);
|
|
13487
13490
|
const baseRoot = scopeBaseRoot(cwd);
|
|
13488
13491
|
const stateRoot = resolveContainedRelativePath(path11.join(baseRoot, DEFAULT_PATHS.state.runsSubdir), runId, "runId");
|
|
@@ -14998,7 +15001,7 @@ function checkResultFile(manifest, tasks) {
|
|
|
14998
15001
|
(t2) => t2.status === "completed" || t2.status === "failed" || t2.status === "cancelled" || t2.status === "skipped" || t2.status === "needs_attention"
|
|
14999
15002
|
);
|
|
15000
15003
|
if (allTerminal) {
|
|
15001
|
-
const hasFailed = tasks.some((t2) => t2.status === "failed");
|
|
15004
|
+
const hasFailed = tasks.some((t2) => t2.status === "failed" || t2.status === "needs_attention");
|
|
15002
15005
|
const onlyCancelledOrSkipped = tasks.every((t2) => t2.status === "cancelled" || t2.status === "skipped");
|
|
15003
15006
|
manifest.status = hasFailed ? "failed" : onlyCancelledOrSkipped ? "cancelled" : "completed";
|
|
15004
15007
|
saveRunManifest(manifest);
|
|
@@ -18696,34 +18699,56 @@ function appendTranscript(input, line4) {
|
|
|
18696
18699
|
}
|
|
18697
18700
|
trackTranscriptWrite(safePath, line4);
|
|
18698
18701
|
}
|
|
18699
|
-
|
|
18702
|
+
function scheduleTranscriptFlush() {
|
|
18703
|
+
if (transcriptFlushTimer) return;
|
|
18704
|
+
transcriptFlushTimer = setTimeout(() => {
|
|
18705
|
+
transcriptFlushTimer = void 0;
|
|
18706
|
+
void flushTranscriptBatches();
|
|
18707
|
+
}, TRANSCRIPT_FLUSH_MS);
|
|
18708
|
+
transcriptFlushTimer.unref?.();
|
|
18709
|
+
}
|
|
18710
|
+
async function flushTranscriptBatches() {
|
|
18711
|
+
const entries = [...transcriptBatches.entries()];
|
|
18712
|
+
transcriptBatches.clear();
|
|
18713
|
+
await Promise.allSettled(
|
|
18714
|
+
entries.map(async ([safePath, lines]) => {
|
|
18715
|
+
if (lines.length === 0) return;
|
|
18716
|
+
const content = lines.join("");
|
|
18717
|
+
try {
|
|
18718
|
+
const fd = await fs28.promises.open(
|
|
18719
|
+
safePath,
|
|
18720
|
+
fs28.constants.O_WRONLY | fs28.constants.O_NOFOLLOW | fs28.constants.O_CREAT | fs28.constants.O_APPEND,
|
|
18721
|
+
384
|
|
18722
|
+
);
|
|
18723
|
+
try {
|
|
18724
|
+
await fd.write(content, void 0, "utf-8");
|
|
18725
|
+
} finally {
|
|
18726
|
+
await fd.close();
|
|
18727
|
+
}
|
|
18728
|
+
} catch (error) {
|
|
18729
|
+
logInternalError("child-pi.transcript-write-failed", error, `path=${safePath}`);
|
|
18730
|
+
}
|
|
18731
|
+
})
|
|
18732
|
+
);
|
|
18733
|
+
}
|
|
18734
|
+
function trackTranscriptWrite(safePath, line4) {
|
|
18700
18735
|
const content = `${redactJsonLine(line4)}
|
|
18701
18736
|
`;
|
|
18702
|
-
|
|
18703
|
-
|
|
18704
|
-
|
|
18705
|
-
|
|
18706
|
-
384
|
|
18707
|
-
);
|
|
18708
|
-
try {
|
|
18709
|
-
await fd.write(content, void 0, "utf-8");
|
|
18710
|
-
} finally {
|
|
18711
|
-
await fd.close();
|
|
18712
|
-
}
|
|
18713
|
-
} catch (error) {
|
|
18714
|
-
logInternalError("child-pi.transcript-write-failed", error, `path=${safePath}`);
|
|
18737
|
+
let batch = transcriptBatches.get(safePath);
|
|
18738
|
+
if (!batch) {
|
|
18739
|
+
batch = [];
|
|
18740
|
+
transcriptBatches.set(safePath, batch);
|
|
18715
18741
|
}
|
|
18716
|
-
|
|
18717
|
-
|
|
18718
|
-
const p = appendTranscriptAsync(safePath, line4).finally(() => {
|
|
18719
|
-
pendingTranscriptWrites.delete(p);
|
|
18720
|
-
});
|
|
18721
|
-
pendingTranscriptWrites.add(p);
|
|
18742
|
+
batch.push(content);
|
|
18743
|
+
scheduleTranscriptFlush();
|
|
18722
18744
|
}
|
|
18723
18745
|
async function flushPendingTranscriptWrites() {
|
|
18724
|
-
|
|
18725
|
-
|
|
18726
|
-
|
|
18746
|
+
if (transcriptFlushTimer) {
|
|
18747
|
+
clearTimeout(transcriptFlushTimer);
|
|
18748
|
+
transcriptFlushTimer = void 0;
|
|
18749
|
+
}
|
|
18750
|
+
while (transcriptBatches.size > 0) {
|
|
18751
|
+
await flushTranscriptBatches();
|
|
18727
18752
|
}
|
|
18728
18753
|
}
|
|
18729
18754
|
function compactString(value, maxChars = MAX_COMPACT_CONTENT_CHARS, opts = {}) {
|
|
@@ -18829,19 +18854,27 @@ function displayTextFromCompactEvent(event) {
|
|
|
18829
18854
|
}).join("\n").trim();
|
|
18830
18855
|
return text || (typeof record.text === "string" ? record.text : void 0);
|
|
18831
18856
|
}
|
|
18832
|
-
function
|
|
18833
|
-
|
|
18834
|
-
|
|
18835
|
-
|
|
18836
|
-
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
|
|
18843
|
-
|
|
18857
|
+
function nonJsonLineResult(line4) {
|
|
18858
|
+
return { json: false, persistedLine: line4, displayLine: line4 };
|
|
18859
|
+
}
|
|
18860
|
+
function compactChildPiLine(line4, preParsed) {
|
|
18861
|
+
let parsed;
|
|
18862
|
+
if (preParsed !== void 0) {
|
|
18863
|
+
parsed = preParsed;
|
|
18864
|
+
} else {
|
|
18865
|
+
try {
|
|
18866
|
+
parsed = JSON.parse(line4);
|
|
18867
|
+
} catch {
|
|
18868
|
+
return nonJsonLineResult(line4);
|
|
18869
|
+
}
|
|
18844
18870
|
}
|
|
18871
|
+
const compact = compactChildPiEvent(parsed);
|
|
18872
|
+
return {
|
|
18873
|
+
json: true,
|
|
18874
|
+
event: compact,
|
|
18875
|
+
persistedLine: compact ? JSON.stringify(compact) : "",
|
|
18876
|
+
displayLine: displayTextFromCompactEvent(compact)
|
|
18877
|
+
};
|
|
18845
18878
|
}
|
|
18846
18879
|
async function observeStdoutChunk(input, text) {
|
|
18847
18880
|
const observer = new ChildPiLineObserver(input);
|
|
@@ -19608,7 +19641,7 @@ ${JSON.stringify({ type: "message_end", usage: { input: 10, output: 5, cost: 1e-
|
|
|
19608
19641
|
}
|
|
19609
19642
|
}
|
|
19610
19643
|
}
|
|
19611
|
-
var POST_EXIT_STDIO_GUARD_MS, FINAL_DRAIN_MS, HARD_KILL_MS, RESPONSE_TIMEOUT_MS, MAX_CAPTURE_BYTES, MAX_ASSISTANT_TEXT_CHARS, MAX_TOOL_RESULT_CHARS, MAX_TOOL_INPUT_CHARS, MAX_COMPACT_CONTENT_CHARS, activeChildProcesses, childHardKillTimers, BASE_ALLOWLIST,
|
|
19644
|
+
var POST_EXIT_STDIO_GUARD_MS, FINAL_DRAIN_MS, HARD_KILL_MS, RESPONSE_TIMEOUT_MS, MAX_CAPTURE_BYTES, MAX_ASSISTANT_TEXT_CHARS, MAX_TOOL_RESULT_CHARS, MAX_TOOL_INPUT_CHARS, MAX_COMPACT_CONTENT_CHARS, activeChildProcesses, childHardKillTimers, BASE_ALLOWLIST, transcriptBatches, transcriptFlushTimer, TRANSCRIPT_FLUSH_MS, ChildPiLineObserver;
|
|
19612
19645
|
var init_child_pi = __esm({
|
|
19613
19646
|
"src/runtime/child-pi.ts"() {
|
|
19614
19647
|
"use strict";
|
|
@@ -19690,7 +19723,8 @@ var init_child_pi = __esm({
|
|
|
19690
19723
|
"PI_CREW_MAX_OUTPUT",
|
|
19691
19724
|
"PI_CREW_STEERING_FILE"
|
|
19692
19725
|
];
|
|
19693
|
-
|
|
19726
|
+
transcriptBatches = /* @__PURE__ */ new Map();
|
|
19727
|
+
TRANSCRIPT_FLUSH_MS = 50;
|
|
19694
19728
|
ChildPiLineObserver = class _ChildPiLineObserver {
|
|
19695
19729
|
buffer = "";
|
|
19696
19730
|
input;
|
|
@@ -19750,9 +19784,14 @@ var init_child_pi = __esm({
|
|
|
19750
19784
|
}
|
|
19751
19785
|
emitLine(line4) {
|
|
19752
19786
|
if (!line4.trim()) return;
|
|
19787
|
+
let parsed;
|
|
19753
19788
|
try {
|
|
19754
|
-
|
|
19755
|
-
|
|
19789
|
+
parsed = JSON.parse(line4);
|
|
19790
|
+
} catch {
|
|
19791
|
+
parsed = void 0;
|
|
19792
|
+
}
|
|
19793
|
+
if (parsed !== void 0) {
|
|
19794
|
+
const rawTexts = extractText(parsed);
|
|
19756
19795
|
if (rawTexts.length > 0) {
|
|
19757
19796
|
this.rawTextEvents.push(...rawTexts);
|
|
19758
19797
|
const rawOverflow = this.rawTextEvents.length - _ChildPiLineObserver.MAX_RAW_TEXT_EVENTS;
|
|
@@ -19764,9 +19803,8 @@ var init_child_pi = __esm({
|
|
|
19764
19803
|
if (findingsOverflow > 0) this.intermediateFindings.splice(0, findingsOverflow);
|
|
19765
19804
|
}
|
|
19766
19805
|
}
|
|
19767
|
-
} catch {
|
|
19768
19806
|
}
|
|
19769
|
-
const compact = compactChildPiLine(line4);
|
|
19807
|
+
const compact = parsed !== void 0 ? compactChildPiLine(line4, parsed) : nonJsonLineResult(line4);
|
|
19770
19808
|
if (compact.event !== void 0) {
|
|
19771
19809
|
try {
|
|
19772
19810
|
this.input.onJsonEvent?.(compact.event);
|
|
@@ -42508,9 +42546,9 @@ function loadLiveSessionModule() {
|
|
|
42508
42546
|
}
|
|
42509
42547
|
function appendTranscript2(filePath, event) {
|
|
42510
42548
|
if (!filePath) return;
|
|
42511
|
-
void
|
|
42549
|
+
void appendTranscriptAsync(filePath, event);
|
|
42512
42550
|
}
|
|
42513
|
-
async function
|
|
42551
|
+
async function appendTranscriptAsync(filePath, event) {
|
|
42514
42552
|
try {
|
|
42515
42553
|
await fs49.promises.mkdir(path42.dirname(filePath), { recursive: true });
|
|
42516
42554
|
const content = `${JSON.stringify(redactSecrets(event))}
|
|
@@ -55557,7 +55595,7 @@ async function runCoalescedTaskGroup(input) {
|
|
|
55557
55595
|
}
|
|
55558
55596
|
return t2;
|
|
55559
55597
|
});
|
|
55560
|
-
|
|
55598
|
+
await saveRunTasksAsync(manifest, updatedTasks);
|
|
55561
55599
|
await appendEventAsync(manifest.eventsPath, {
|
|
55562
55600
|
type: "task.coalesced_dispatch_start",
|
|
55563
55601
|
runId: manifest.runId,
|
|
@@ -55572,14 +55610,14 @@ async function runCoalescedTaskGroup(input) {
|
|
|
55572
55610
|
heartbeat: t2.heartbeat ?? createWorkerHeartbeat(t2.id)
|
|
55573
55611
|
};
|
|
55574
55612
|
});
|
|
55575
|
-
|
|
55613
|
+
await saveRunTasksAsync(manifest, updatedTasks);
|
|
55576
55614
|
let rawOutput = "";
|
|
55577
55615
|
let success = false;
|
|
55578
55616
|
if (!executeWorkers) {
|
|
55579
55617
|
rawOutput = buildScaffoldOutput(groupTasks);
|
|
55580
55618
|
success = true;
|
|
55581
55619
|
} else {
|
|
55582
|
-
const heartbeatTimer = setInterval(() => {
|
|
55620
|
+
const heartbeatTimer = setInterval(async () => {
|
|
55583
55621
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
55584
55622
|
updatedTasks = updatedTasks.map((t2) => {
|
|
55585
55623
|
if (!taskIds.includes(t2.id)) return t2;
|
|
@@ -55589,7 +55627,7 @@ async function runCoalescedTaskGroup(input) {
|
|
|
55589
55627
|
};
|
|
55590
55628
|
});
|
|
55591
55629
|
try {
|
|
55592
|
-
|
|
55630
|
+
await saveRunTasksAsync(manifest, updatedTasks);
|
|
55593
55631
|
} catch {
|
|
55594
55632
|
}
|
|
55595
55633
|
}, 15e3);
|
|
@@ -55639,7 +55677,7 @@ async function runCoalescedTaskGroup(input) {
|
|
|
55639
55677
|
resultArtifact
|
|
55640
55678
|
};
|
|
55641
55679
|
});
|
|
55642
|
-
|
|
55680
|
+
await saveRunTasksAsync(manifest, updatedTasks);
|
|
55643
55681
|
let updatedManifest = {
|
|
55644
55682
|
...manifest,
|
|
55645
55683
|
artifacts: mergeArtifacts([...manifest.artifacts, ...newArtifacts])
|
|
@@ -60051,7 +60089,7 @@ async function injectAdaptivePlanIfReady(input) {
|
|
|
60051
60089
|
missingPlan: false
|
|
60052
60090
|
};
|
|
60053
60091
|
if (!completedAssess.resultArtifact?.path) {
|
|
60054
|
-
|
|
60092
|
+
appendEventFireAndForget(input.manifest.eventsPath, {
|
|
60055
60093
|
type: "adaptive.plan_missing",
|
|
60056
60094
|
runId: input.manifest.runId,
|
|
60057
60095
|
taskId: completedAssess.id,
|
|
@@ -60070,7 +60108,7 @@ async function injectAdaptivePlanIfReady(input) {
|
|
|
60070
60108
|
try {
|
|
60071
60109
|
text = fs85.readFileSync(resultPath, "utf-8");
|
|
60072
60110
|
} catch {
|
|
60073
|
-
|
|
60111
|
+
appendEventFireAndForget(input.manifest.eventsPath, {
|
|
60074
60112
|
type: "adaptive.plan_missing",
|
|
60075
60113
|
runId: input.manifest.runId,
|
|
60076
60114
|
taskId: assessTask.id,
|
|
@@ -60101,7 +60139,7 @@ async function injectAdaptivePlanIfReady(input) {
|
|
|
60101
60139
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
60102
60140
|
artifacts: [...input.manifest.artifacts, repairArtifact]
|
|
60103
60141
|
});
|
|
60104
|
-
|
|
60142
|
+
appendEventFireAndForget(input.manifest.eventsPath, {
|
|
60105
60143
|
type: "adaptive.plan_repaired",
|
|
60106
60144
|
runId: input.manifest.runId,
|
|
60107
60145
|
taskId: assessTask.id,
|
|
@@ -60109,14 +60147,14 @@ async function injectAdaptivePlanIfReady(input) {
|
|
|
60109
60147
|
data: { reason: repair.reason }
|
|
60110
60148
|
});
|
|
60111
60149
|
} else {
|
|
60112
|
-
|
|
60150
|
+
appendEventFireAndForget(input.manifest.eventsPath, {
|
|
60113
60151
|
type: "adaptive.plan_repair_failed",
|
|
60114
60152
|
runId: input.manifest.runId,
|
|
60115
60153
|
taskId: assessTask.id,
|
|
60116
60154
|
message: "Adaptive planner output could not be repaired.",
|
|
60117
60155
|
data: { reason: repair.reason }
|
|
60118
60156
|
});
|
|
60119
|
-
|
|
60157
|
+
appendEventFireAndForget(input.manifest.eventsPath, {
|
|
60120
60158
|
type: "adaptive.plan_missing",
|
|
60121
60159
|
runId: input.manifest.runId,
|
|
60122
60160
|
taskId: assessTask.id,
|
|
@@ -60183,7 +60221,7 @@ async function injectAdaptivePlanIfReady(input) {
|
|
|
60183
60221
|
} : task.graph
|
|
60184
60222
|
}));
|
|
60185
60223
|
const allTasks = refreshTaskGraphQueues([...input.tasks, ...withGraph]);
|
|
60186
|
-
|
|
60224
|
+
await appendEventAsync(input.manifest.eventsPath, {
|
|
60187
60225
|
type: "adaptive.plan_injected",
|
|
60188
60226
|
runId: input.manifest.runId,
|
|
60189
60227
|
taskId: assessTask.id,
|
|
@@ -79029,6 +79067,7 @@ var init_heartbeat_watcher = __esm({
|
|
|
79029
79067
|
if (!fs99.existsSync(run.stateRoot)) continue;
|
|
79030
79068
|
const loaded = loadRunManifestById(this.opts.cwd, run.runId);
|
|
79031
79069
|
if (!loaded) continue;
|
|
79070
|
+
if (loaded.manifest.status !== "running") continue;
|
|
79032
79071
|
for (const task of loaded.tasks) {
|
|
79033
79072
|
if (task.status !== "running") continue;
|
|
79034
79073
|
const key = `${run.runId}:${task.id}`;
|
|
@@ -85061,6 +85100,45 @@ Subagent may need manual intervention.`
|
|
|
85061
85100
|
return loaded.tasks.some((t2) => t2.status === "running" || t2.status === "queued");
|
|
85062
85101
|
};
|
|
85063
85102
|
});
|
|
85103
|
+
const cleanupSessionResourcesOnly = () => {
|
|
85104
|
+
if (cleanedUp) return;
|
|
85105
|
+
cleanedUp = true;
|
|
85106
|
+
if (preloadTimer) {
|
|
85107
|
+
clearTimeout(preloadTimer);
|
|
85108
|
+
preloadTimer = void 0;
|
|
85109
|
+
}
|
|
85110
|
+
crewRunWatchers?.closeAll();
|
|
85111
|
+
crewRunWatchers = void 0;
|
|
85112
|
+
userCrewWatchers?.closeAll();
|
|
85113
|
+
userCrewWatchers = void 0;
|
|
85114
|
+
stopSessionBoundSubagents();
|
|
85115
|
+
crewScheduler?.stop();
|
|
85116
|
+
stopAsyncRunNotifier(notifierState);
|
|
85117
|
+
purgeStaleActiveRunIndexSyncIfLoaded();
|
|
85118
|
+
stopCrewWidget(currentCtx, widgetState, currentCtx ? loadConfig(currentCtx.cwd).config.ui : void 0);
|
|
85119
|
+
clearPiCrewPowerbar(pi.events);
|
|
85120
|
+
disposePowerbarCoalescer();
|
|
85121
|
+
disposeObservability(observabilityState, cleanedUp);
|
|
85122
|
+
lifecycleState.deliveryCoordinator?.dispose();
|
|
85123
|
+
clearHooksScoped();
|
|
85124
|
+
uninstallCrewGlobalRegistry();
|
|
85125
|
+
lifecycleState.overflowTracker?.dispose();
|
|
85126
|
+
lifecycleState.deliveryCoordinator = void 0;
|
|
85127
|
+
lifecycleState.overflowTracker = void 0;
|
|
85128
|
+
manifestCache2.dispose();
|
|
85129
|
+
runSnapshotCache.dispose?.();
|
|
85130
|
+
clearProjectRootCache();
|
|
85131
|
+
renderScheduler?.dispose();
|
|
85132
|
+
renderScheduler = void 0;
|
|
85133
|
+
autoRecoveryLast.clear();
|
|
85134
|
+
disposeNotifications(lifecycleState);
|
|
85135
|
+
rpcHandle?.unsubscribe();
|
|
85136
|
+
rpcHandle = void 0;
|
|
85137
|
+
disposeI18n();
|
|
85138
|
+
sessionGeneration += 1;
|
|
85139
|
+
currentCtx = void 0;
|
|
85140
|
+
if (globalStore[runtimeCleanupStoreKey] === cleanupSessionResourcesOnly) delete globalStore[runtimeCleanupStoreKey];
|
|
85141
|
+
};
|
|
85064
85142
|
const cleanupRuntime = () => {
|
|
85065
85143
|
if (cleanedUp) return;
|
|
85066
85144
|
cleanedUp = true;
|
|
@@ -85103,6 +85181,14 @@ Subagent may need manual intervention.`
|
|
|
85103
85181
|
if (globalStore[runtimeCleanupStoreKey] === cleanupRuntime) delete globalStore[runtimeCleanupStoreKey];
|
|
85104
85182
|
};
|
|
85105
85183
|
globalStore[runtimeCleanupStoreKey] = cleanupRuntime;
|
|
85184
|
+
pi.on("session_shutdown", (event) => {
|
|
85185
|
+
const reason = typeof event === "object" && event !== null && "reason" in event ? event.reason : void 0;
|
|
85186
|
+
if (reason === "quit" || reason === "reload") {
|
|
85187
|
+
cleanupRuntime();
|
|
85188
|
+
} else {
|
|
85189
|
+
cleanupSessionResourcesOnly();
|
|
85190
|
+
}
|
|
85191
|
+
});
|
|
85106
85192
|
pi.on("session_start", (_event, ctx) => {
|
|
85107
85193
|
runArtifactCleanup(ctx.cwd);
|
|
85108
85194
|
try {
|
|
@@ -85583,7 +85669,6 @@ Subagent may need manual intervention.`
|
|
|
85583
85669
|
stopAsyncRunNotifier(notifierState);
|
|
85584
85670
|
stopSessionBoundSubagents();
|
|
85585
85671
|
});
|
|
85586
|
-
pi.on("session_shutdown", () => cleanupRuntime());
|
|
85587
85672
|
try {
|
|
85588
85673
|
pi.on("resources_discover", () => {
|
|
85589
85674
|
const sessionCwd = currentCtx?.cwd ?? process.cwd();
|