pi-crew 0.9.58 → 0.9.59
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 +17 -0
- package/dist/index.mjs +139 -58
- package/package.json +1 -1
- package/skills/distill-software/SKILL.md +7 -1
- package/src/extension/async-notifier.ts +10 -2
- package/src/extension/registration/context-builder.ts +5 -2
- package/src/extension/registration/crash-recovery-cache.ts +2 -2
- package/src/extension/registration/lazy-configurers.ts +1 -1
- package/src/extension/registration/lifecycle-handlers.ts +25 -10
- package/src/extension/registration/observability.ts +8 -4
- package/src/extension/registration/registration-types.ts +2 -2
- package/src/extension/registration/runtime-cleanup.ts +5 -2
- package/src/extension/registration/subagent-manager-setup.ts +9 -4
- package/src/extension/registration/subagent-tools.ts +15 -3
- package/src/extension/session-summary.ts +5 -0
- package/src/runtime/delivery-coordinator.ts +24 -3
- package/src/runtime/recovery/crash-recovery.ts +34 -4
- package/src/runtime/subagent-manager.ts +7 -1
- package/src/ui/powerbar-publisher.ts +31 -6
- package/src/ui/run-dashboard.ts +7 -1
- package/src/ui/widget/index.ts +9 -1
- package/src/ui/widget/widget-model.ts +1 -1
- package/src/ui/widget/widget-types.ts +3 -0
- package/src/utils/session-utils.ts +42 -19
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
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
5
|
|
|
6
|
+
## [0.9.59] — cross-session isolation: stop leak of runs/subagents between concurrent pi sessions + stop false-reap of live sessions (2026-08-05)
|
|
7
|
+
|
|
8
|
+
### Bug fixes
|
|
9
|
+
|
|
10
|
+
- **Chạy 2 pi session trên cùng repo → thông tin run/subagent của session A rò rỉ sang B, và crash-recovery của B giết foreground work đang chạy của A.** Hai lỗi gốc: (1) `extractSessionId()` đọc `ctx.sessionId` (own property) — không tồn tại trên pi 0.83.0 `ExtensionContext` → trả `undefined` → mọi session filter vô hiệu thầm lặng; (2) crash-recovery + shared-state listings không có session component, nên session đang sống-but-bận không phân biệt được với session đã crash.
|
|
11
|
+
- **`extractSessionId` (`src/utils/session-utils.ts`)**: giờ dùng `ctx.sessionManager.getSessionId()` (WeakMap cache keyed bởi `sessionManager` ref ổn định — `ctx` được tạo mới mỗi event nên không thể làm cache key), giữ descriptor lookup làm fallback cho test mock/pi cũ.
|
|
12
|
+
- **Crash-recovery (`src/runtime/recovery/crash-recovery.ts`)**: `reconcileAllStaleRuns` / `purgeStaleActiveRunIndex` / `detectInterruptedRuns` nhận `currentSessionId?` và **skip run của chính session đang sống** (`===`, theo pattern `cancelOrphanedRuns`). Session chết vẫn được dọn; back-compat giữ nguyên khi `currentSessionId` undefined. Thread qua tất cả caller incl. path tần suất cao `observability` (`before_agent_start` + interval 5-min) và `lazy-configurers`.
|
|
13
|
+
- **Subagents (`src/runtime/subagent-manager.ts`, `subagent-tools.ts`, `subagent-manager-setup.ts`)**: `SubagentRecord` thêm `ownerSessionId`; `get_subagent_result` từ chối record của session khác (record cũ vẫn serve); `resultConsumed` không còn bị clobber chéo session; agent id thêm entropy tránh collision cross-process; `isOwnerSessionCurrent` check `ownerSessionId` cross-process (giữ generation cho in-process switch).
|
|
14
|
+
- **UI (`src/ui/run-dashboard.ts`, `widget/*`, `powerbar-publisher.ts`)**: dashboard `refreshRuns`, widget render, powerbar re-apply filter `workspaceId` mỗi frame. Powerbar self-derive `workspaceId` qua `extractSessionId(ctx)` nên mọi caller hiện tại đều được.
|
|
15
|
+
- **Notifier/session-summary (`src/extension/async-notifier.ts`, `session-summary.ts`)**: filter `listRuns` theo `ownerSessionId` trước notify — session B không còn toast về run của A.
|
|
16
|
+
- **Health filter (#3)**: `ctx.currentCtx?.sessionManager?.getSessionId()` + bỏ dead clause `ownerSessionGeneration` (field không tồn tại trên `TeamRunManifest`) — trước đó silently drop tất cả owned runs.
|
|
17
|
+
- Verified end-to-end theo skill `real-test-pi-crew`: `test:critical` 101/101, 3-path kill-switch green, typecheck + bundle + md5 sync OK, live TUI (tmux + pty) render không crash, smoke verifier 52s (<300s, no hang), full feature battery (team tool 9a–9f + subagent tools) clean — zero `Unknown type`/`Validation failed`. 6837 unit + 214 integration tests pass.
|
|
18
|
+
- Lưu ý: `#12` (DeliveryCoordinator) infrastructure staged nhưng inert — `deliver*` không có production caller, nên queue không bao giờ được feed. Documented trong `docs/cross-session-leak-fix-plan.md`.
|
|
19
|
+
|
|
20
|
+
### Docs
|
|
21
|
+
- `docs/cross-session-leak-audit.md` (audit re-verify: 2/2 root cause CONFIRMED, 12/13 vector CONFIRMED, #3 REFUTED) + `docs/cross-session-leak-fix-plan.md` (phased plan, reviewed).
|
|
22
|
+
|
|
6
23
|
## [0.9.58] — fix load crash on stale hoisted typebox: defensive guard + bundle vendoring (survives `pi update`) + round-1/round-2 fixes (2026-08-04)
|
|
7
24
|
|
|
8
25
|
### Bug fixes
|
package/dist/index.mjs
CHANGED
|
@@ -12871,14 +12871,23 @@ function toPiSessionId(runId) {
|
|
|
12871
12871
|
}
|
|
12872
12872
|
function extractSessionId(ctx) {
|
|
12873
12873
|
if (typeof ctx !== "object" || ctx === null) return void 0;
|
|
12874
|
-
let raw;
|
|
12875
12874
|
try {
|
|
12876
|
-
|
|
12875
|
+
const sm = ctx.sessionManager;
|
|
12876
|
+
if (sm && typeof sm === "object") {
|
|
12877
|
+
const cached2 = sessionIdCache.get(sm);
|
|
12878
|
+
if (cached2) return cached2;
|
|
12879
|
+
const id = sm.getSessionId?.();
|
|
12880
|
+
if (typeof id === "string" && id.length > 0) {
|
|
12881
|
+
sessionIdCache.set(sm, id);
|
|
12882
|
+
return id;
|
|
12883
|
+
}
|
|
12884
|
+
}
|
|
12885
|
+
const direct = Object.getOwnPropertyDescriptor(ctx, "sessionId")?.value;
|
|
12886
|
+
if (typeof direct === "string" && direct.length > 0) return direct;
|
|
12877
12887
|
} catch {
|
|
12878
12888
|
return void 0;
|
|
12879
12889
|
}
|
|
12880
|
-
|
|
12881
|
-
return raw;
|
|
12890
|
+
return void 0;
|
|
12882
12891
|
}
|
|
12883
12892
|
function extractBrokerSessionId(ctx) {
|
|
12884
12893
|
if (typeof ctx !== "object" || ctx === null) return void 0;
|
|
@@ -12893,9 +12902,11 @@ function extractBrokerSessionId(ctx) {
|
|
|
12893
12902
|
return void 0;
|
|
12894
12903
|
}
|
|
12895
12904
|
}
|
|
12905
|
+
var sessionIdCache;
|
|
12896
12906
|
var init_session_utils = __esm({
|
|
12897
12907
|
"src/utils/session-utils.ts"() {
|
|
12898
12908
|
"use strict";
|
|
12909
|
+
sessionIdCache = /* @__PURE__ */ new WeakMap();
|
|
12899
12910
|
}
|
|
12900
12911
|
});
|
|
12901
12912
|
|
|
@@ -42694,8 +42705,8 @@ function registerPiCrewPowerbarSegments(events, config) {
|
|
|
42694
42705
|
label: "pi-crew workflow steps"
|
|
42695
42706
|
});
|
|
42696
42707
|
}
|
|
42697
|
-
function updatePiCrewPowerbar(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests) {
|
|
42698
|
-
powerbarPublisher.update(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount, preloadedManifests);
|
|
42708
|
+
function updatePiCrewPowerbar(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests, workspaceId) {
|
|
42709
|
+
powerbarPublisher.update(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount, preloadedManifests, workspaceId);
|
|
42699
42710
|
}
|
|
42700
42711
|
function powerbarKey(payload) {
|
|
42701
42712
|
return `${payload.text ?? ""}|${payload.suffix ?? ""}|${payload.bar ?? ""}|${payload.color ?? ""}|${payload.icon ?? ""}|${payload.barSegments ?? ""}`;
|
|
@@ -42739,8 +42750,8 @@ function buildStepsPayload(active, allTasks) {
|
|
|
42739
42750
|
color
|
|
42740
42751
|
};
|
|
42741
42752
|
}
|
|
42742
|
-
function requestPowerbarUpdate(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests) {
|
|
42743
|
-
powerbarPublisher.request(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount, preloadedManifests);
|
|
42753
|
+
function requestPowerbarUpdate(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests, workspaceId) {
|
|
42754
|
+
powerbarPublisher.request(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount, preloadedManifests, workspaceId);
|
|
42744
42755
|
}
|
|
42745
42756
|
function disposePowerbarCoalescer() {
|
|
42746
42757
|
powerbarPublisher.dispose();
|
|
@@ -42762,6 +42773,7 @@ var init_powerbar_publisher = __esm({
|
|
|
42762
42773
|
init_usage();
|
|
42763
42774
|
init_file_coalescer();
|
|
42764
42775
|
init_internal_error();
|
|
42776
|
+
init_session_utils();
|
|
42765
42777
|
init_discover_workflows();
|
|
42766
42778
|
init_render_coalescer();
|
|
42767
42779
|
init_widget_formatters();
|
|
@@ -42777,13 +42789,25 @@ var init_powerbar_publisher = __esm({
|
|
|
42777
42789
|
const a = this.#latestArgs;
|
|
42778
42790
|
this.#latestArgs = null;
|
|
42779
42791
|
if (!a) return;
|
|
42780
|
-
this.update(
|
|
42792
|
+
this.update(
|
|
42793
|
+
a.events,
|
|
42794
|
+
a.cwd,
|
|
42795
|
+
a.config,
|
|
42796
|
+
a.manifestCache,
|
|
42797
|
+
a.snapshotCache,
|
|
42798
|
+
a.ctx,
|
|
42799
|
+
a.notificationCount,
|
|
42800
|
+
a.preloadedManifests,
|
|
42801
|
+
a.workspaceId
|
|
42802
|
+
);
|
|
42781
42803
|
}, 200);
|
|
42782
42804
|
}
|
|
42783
|
-
update(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests) {
|
|
42805
|
+
update(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests, workspaceId) {
|
|
42784
42806
|
if (config?.powerbar === false) return;
|
|
42785
42807
|
const useStatusFallback = !hasPowerbarConsumer(events);
|
|
42786
|
-
const
|
|
42808
|
+
const effectiveWorkspaceId = workspaceId ?? extractSessionId(ctx);
|
|
42809
|
+
const allRuns = preloadedManifests ?? (manifestCache2 ? manifestCache2.list(20) : listRecentRuns(cwd, 20));
|
|
42810
|
+
const runs = effectiveWorkspaceId ? allRuns.filter((run) => !run.ownerSessionId || run.ownerSessionId === effectiveWorkspaceId) : allRuns;
|
|
42787
42811
|
const active = runs.map((run) => {
|
|
42788
42812
|
let snapshot;
|
|
42789
42813
|
try {
|
|
@@ -42839,7 +42863,8 @@ var init_powerbar_publisher = __esm({
|
|
|
42839
42863
|
const tokenTotal = hasUsage ? (usage.input ?? 0) + (usage.output ?? 0) + (usage.cacheRead ?? 0) + (usage.cacheWrite ?? 0) : snapshotTokens;
|
|
42840
42864
|
const model = config?.showModel === false ? void 0 : agents.find((agent) => agent.model)?.model?.split("/").at(-1);
|
|
42841
42865
|
const tokenText = config?.showTokens === false || !tokenTotal ? void 0 : compactTokens(tokenTotal);
|
|
42842
|
-
const
|
|
42866
|
+
const liveAgents2 = effectiveWorkspaceId ? listLiveAgentsByWorkspace(effectiveWorkspaceId) : listLiveAgents();
|
|
42867
|
+
const liveRunning = liveAgents2.filter((a) => a.status === "running").length;
|
|
42843
42868
|
const runningCount = agents.filter((a) => a.status === "running").length;
|
|
42844
42869
|
const queuedCount = active.reduce(
|
|
42845
42870
|
(sum, item) => sum + item.tasks.reduce((s, t2) => s + (t2.status === "queued" || t2.status === "waiting" ? 1 : 0), 0),
|
|
@@ -42893,7 +42918,7 @@ var init_powerbar_publisher = __esm({
|
|
|
42893
42918
|
* into a single render pass within 200ms, preventing UI flicker from
|
|
42894
42919
|
* event bursts.
|
|
42895
42920
|
*/
|
|
42896
|
-
request(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests) {
|
|
42921
|
+
request(events, cwd, config, manifestCache2, snapshotCache, ctx, notificationCount = 0, preloadedManifests, workspaceId) {
|
|
42897
42922
|
if (config?.powerbar === false) return;
|
|
42898
42923
|
this.#latestArgs = {
|
|
42899
42924
|
events,
|
|
@@ -42903,7 +42928,8 @@ var init_powerbar_publisher = __esm({
|
|
|
42903
42928
|
snapshotCache,
|
|
42904
42929
|
ctx,
|
|
42905
42930
|
notificationCount,
|
|
42906
|
-
preloadedManifests
|
|
42931
|
+
preloadedManifests,
|
|
42932
|
+
workspaceId
|
|
42907
42933
|
};
|
|
42908
42934
|
this.#coalescer.request();
|
|
42909
42935
|
}
|
|
@@ -44611,12 +44637,13 @@ function shouldRecoverTask(task, deadMs) {
|
|
|
44611
44637
|
if (!task.heartbeat) return true;
|
|
44612
44638
|
return task.heartbeat.alive === false || isWorkerHeartbeatStale(task.heartbeat, deadMs);
|
|
44613
44639
|
}
|
|
44614
|
-
function detectInterruptedRuns(cwd, manifestCache2, deadMs = 3e5) {
|
|
44640
|
+
function detectInterruptedRuns(cwd, manifestCache2, deadMs = 3e5, currentSessionId) {
|
|
44615
44641
|
const plans = [];
|
|
44616
44642
|
for (const manifest of manifestCache2.list(50)) {
|
|
44617
44643
|
if (manifest.status !== "running" && manifest.status !== "blocked") continue;
|
|
44618
44644
|
if (isPlanApprovalPending(manifest)) continue;
|
|
44619
44645
|
if (manifest.async?.pid !== void 0 && checkProcessLiveness(manifest.async.pid).alive) continue;
|
|
44646
|
+
if (currentSessionId && manifest.ownerSessionId && manifest.ownerSessionId === currentSessionId) continue;
|
|
44620
44647
|
const loaded = loadRunManifestById(cwd, manifest.runId);
|
|
44621
44648
|
if (!loaded) continue;
|
|
44622
44649
|
const resumableTasks = loaded.tasks.filter((task) => shouldRecoverTask(task, deadMs)).map((task) => task.id);
|
|
@@ -44788,7 +44815,7 @@ function hasRecentLifeEvidence(entry, manifestUpdatedAt, now, staleThresholdMs)
|
|
|
44788
44815
|
if (Number.isFinite(hbAge) && hbAge <= staleThresholdMs) return true;
|
|
44789
44816
|
return false;
|
|
44790
44817
|
}
|
|
44791
|
-
function purgeStaleActiveRunIndex(staleThresholdMs = 3e5, now = Date.now()) {
|
|
44818
|
+
function purgeStaleActiveRunIndex(staleThresholdMs = 3e5, now = Date.now(), currentSessionId) {
|
|
44792
44819
|
const purged = [];
|
|
44793
44820
|
const kept = [];
|
|
44794
44821
|
const entries = readActiveRunRegistry();
|
|
@@ -44830,6 +44857,10 @@ function purgeStaleActiveRunIndex(staleThresholdMs = 3e5, now = Date.now()) {
|
|
|
44830
44857
|
purged.push(entry.runId);
|
|
44831
44858
|
continue;
|
|
44832
44859
|
}
|
|
44860
|
+
if (currentSessionId && manifest?.ownerSessionId && manifest.ownerSessionId === currentSessionId) {
|
|
44861
|
+
kept.push(entry.runId);
|
|
44862
|
+
continue;
|
|
44863
|
+
}
|
|
44833
44864
|
if (manifest?.status === "running" && manifest.async?.pid !== void 0) {
|
|
44834
44865
|
const pidAlive = checkProcessLiveness(manifest.async.pid).alive;
|
|
44835
44866
|
if (!pidAlive && !hasRecentLifeEvidence(entry, manifest.updatedAt, now, staleThresholdMs)) {
|
|
@@ -44930,9 +44961,13 @@ function purgeStaleActiveRunIndex(staleThresholdMs = 3e5, now = Date.now()) {
|
|
|
44930
44961
|
}
|
|
44931
44962
|
return { purged, kept };
|
|
44932
44963
|
}
|
|
44933
|
-
function reconcileAllStaleRuns(cwd, manifestCache2, now = Date.now()) {
|
|
44964
|
+
function reconcileAllStaleRuns(cwd, manifestCache2, now = Date.now(), currentSessionId) {
|
|
44934
44965
|
const results = [];
|
|
44935
|
-
const runIds = manifestCache2.list(50).filter((m) =>
|
|
44966
|
+
const runIds = manifestCache2.list(50).filter((m) => {
|
|
44967
|
+
if (m.status !== "running" && m.status !== "blocked") return false;
|
|
44968
|
+
if (currentSessionId && m.ownerSessionId && m.ownerSessionId === currentSessionId) return false;
|
|
44969
|
+
return true;
|
|
44970
|
+
}).map((m) => m.runId);
|
|
44936
44971
|
for (const runId of runIds) {
|
|
44937
44972
|
const cached2 = manifestCache2.get(runId);
|
|
44938
44973
|
if (!cached2) continue;
|
|
@@ -45016,7 +45051,7 @@ function activeWidgetRuns(cwd, manifestCache2, snapshotCache, preloadedManifests
|
|
|
45016
45051
|
if (now - lastStaleReconcileAt > STALE_RECONCILE_INTERVAL_MS && manifestCache2) {
|
|
45017
45052
|
lastStaleReconcileAt = now;
|
|
45018
45053
|
try {
|
|
45019
|
-
reconcileAllStaleRuns(cwd, manifestCache2);
|
|
45054
|
+
reconcileAllStaleRuns(cwd, manifestCache2, Date.now(), workspaceId);
|
|
45020
45055
|
} catch {
|
|
45021
45056
|
}
|
|
45022
45057
|
}
|
|
@@ -45458,7 +45493,8 @@ function updateCrewWidget(ctx, state, config, manifestCache2, snapshotCache, pre
|
|
|
45458
45493
|
notificationCount: state.notificationCount ?? 0,
|
|
45459
45494
|
manifestCache: manifestCache2,
|
|
45460
45495
|
snapshotCache,
|
|
45461
|
-
preloadManifests: preloadedManifests
|
|
45496
|
+
preloadManifests: preloadedManifests,
|
|
45497
|
+
workspaceId
|
|
45462
45498
|
};
|
|
45463
45499
|
else {
|
|
45464
45500
|
state.model.cwd = ctx.cwd;
|
|
@@ -45468,6 +45504,7 @@ function updateCrewWidget(ctx, state, config, manifestCache2, snapshotCache, pre
|
|
|
45468
45504
|
state.model.manifestCache = manifestCache2;
|
|
45469
45505
|
state.model.snapshotCache = snapshotCache;
|
|
45470
45506
|
state.model.preloadManifests = preloadedManifests;
|
|
45507
|
+
state.model.workspaceId = workspaceId;
|
|
45471
45508
|
}
|
|
45472
45509
|
if (needsWidgetInstall) {
|
|
45473
45510
|
const model = state.model;
|
|
@@ -45603,7 +45640,13 @@ var init_widget = __esm({
|
|
|
45603
45640
|
if (activeResizeTarget === this) activeResizeTarget = void 0;
|
|
45604
45641
|
}
|
|
45605
45642
|
render(width) {
|
|
45606
|
-
const runs = activeWidgetRuns(
|
|
45643
|
+
const runs = activeWidgetRuns(
|
|
45644
|
+
this.model.cwd,
|
|
45645
|
+
this.model.manifestCache,
|
|
45646
|
+
this.model.snapshotCache,
|
|
45647
|
+
this.model.preloadManifests,
|
|
45648
|
+
this.model.workspaceId
|
|
45649
|
+
);
|
|
45607
45650
|
const now = Date.now();
|
|
45608
45651
|
let sigBase;
|
|
45609
45652
|
if (this.cachedBuildSignature !== "" && now - this.cachedBuildSignatureAt < SIGNATURE_CACHE_TTL_MS) {
|
|
@@ -64582,7 +64625,8 @@ var init_run_dashboard = __esm({
|
|
|
64582
64625
|
if (!this.options.runProvider) return;
|
|
64583
64626
|
const selectedRunId = this.selectedRunId();
|
|
64584
64627
|
const next = this.options.runProvider();
|
|
64585
|
-
|
|
64628
|
+
const unfiltered = Array.isArray(next) ? next : this.runs;
|
|
64629
|
+
this.runs = this.options.workspaceId ? unfiltered.filter((run) => !run.ownerSessionId || run.ownerSessionId === this.options.workspaceId) : unfiltered;
|
|
64586
64630
|
if (selectedRunId) {
|
|
64587
64631
|
const nextIndex = groupedRuns(this.runs, this.options.snapshotCache).filter((row) => row.run).findIndex((row) => row.run?.runId === selectedRunId);
|
|
64588
64632
|
if (nextIndex >= 0) this.selected = nextIndex;
|
|
@@ -67808,6 +67852,7 @@ var init_commands = __esm({
|
|
|
67808
67852
|
});
|
|
67809
67853
|
|
|
67810
67854
|
// src/runtime/subagent-manager.ts
|
|
67855
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
67811
67856
|
import * as fs100 from "node:fs";
|
|
67812
67857
|
import * as path81 from "node:path";
|
|
67813
67858
|
function isValidSubagentId(id) {
|
|
@@ -67926,6 +67971,7 @@ var init_subagent_manager = __esm({
|
|
|
67926
67971
|
"resultConsumed",
|
|
67927
67972
|
"background",
|
|
67928
67973
|
"ownerSessionGeneration",
|
|
67974
|
+
"ownerSessionId",
|
|
67929
67975
|
"stuckNotified",
|
|
67930
67976
|
"blockedAt",
|
|
67931
67977
|
"turnCount",
|
|
@@ -67952,7 +67998,7 @@ var init_subagent_manager = __esm({
|
|
|
67952
67998
|
}
|
|
67953
67999
|
spawn(options, runner, signal) {
|
|
67954
68000
|
const record = {
|
|
67955
|
-
id: `agent_${Date.now().toString(36)}_${(++this.counter).toString(36)}`,
|
|
68001
|
+
id: `agent_${Date.now().toString(36)}_${randomUUID8().slice(0, 8)}_${(++this.counter).toString(36)}`,
|
|
67956
68002
|
type: options.type,
|
|
67957
68003
|
description: options.description,
|
|
67958
68004
|
prompt: options.prompt,
|
|
@@ -67962,6 +68008,7 @@ var init_subagent_manager = __esm({
|
|
|
67962
68008
|
skill: options.skill,
|
|
67963
68009
|
background: options.background,
|
|
67964
68010
|
ownerSessionGeneration: options.ownerSessionGeneration,
|
|
68011
|
+
ownerSessionId: options.ownerSessionId,
|
|
67965
68012
|
batchId: options.batchId
|
|
67966
68013
|
};
|
|
67967
68014
|
this.records.set(record.id, record);
|
|
@@ -68214,7 +68261,8 @@ var init_subagent_manager = __esm({
|
|
|
68214
68261
|
id: current.id,
|
|
68215
68262
|
runId: current.runId,
|
|
68216
68263
|
durationMs: Math.max(0, Date.now() - current.blockedAt),
|
|
68217
|
-
ownerSessionGeneration: current.ownerSessionGeneration
|
|
68264
|
+
ownerSessionGeneration: current.ownerSessionGeneration,
|
|
68265
|
+
ownerSessionId: current.ownerSessionId
|
|
68218
68266
|
});
|
|
68219
68267
|
savePersistedSubagentRecord(cwd, current);
|
|
68220
68268
|
};
|
|
@@ -68878,7 +68926,9 @@ function startAsyncRunNotifier(ctx, state, intervalMs = 5e3, options = {}) {
|
|
|
68878
68926
|
state.generation = generation;
|
|
68879
68927
|
const startedAtMs = Date.now();
|
|
68880
68928
|
const staleBeforeMs = state.lastStoppedAtMs ?? startedAtMs;
|
|
68881
|
-
|
|
68929
|
+
const sid = extractSessionId(ctx);
|
|
68930
|
+
const ownsRun = (run) => !sid || !run.ownerSessionId || run.ownerSessionId === sid;
|
|
68931
|
+
for (const run of listRuns(ctx.cwd).filter(ownsRun)) {
|
|
68882
68932
|
const updatedAtMs = timeMs(run.updatedAt) ?? 0;
|
|
68883
68933
|
if (isFinished2(run.status) && updatedAtMs < staleBeforeMs) state.seenFinishedRunIds.add(run.runId);
|
|
68884
68934
|
}
|
|
@@ -68888,7 +68938,7 @@ function startAsyncRunNotifier(ctx, state, intervalMs = 5e3, options = {}) {
|
|
|
68888
68938
|
if (options.isCurrent && !options.isCurrent(generation)) return;
|
|
68889
68939
|
const nowMs3 = Date.now();
|
|
68890
68940
|
if (cachedRuns === void 0 || nowMs3 - (state.lastListRunsMs ?? 0) > LIST_RUNS_DEBOUNCE_MS) {
|
|
68891
|
-
cachedRuns = listRuns(ctx.cwd).slice(0, 20);
|
|
68941
|
+
cachedRuns = listRuns(ctx.cwd).filter(ownsRun).slice(0, 20);
|
|
68892
68942
|
state.lastListRunsMs = nowMs3;
|
|
68893
68943
|
}
|
|
68894
68944
|
for (const run of cachedRuns) {
|
|
@@ -68925,6 +68975,7 @@ var init_async_notifier = __esm({
|
|
|
68925
68975
|
init_event_log();
|
|
68926
68976
|
init_state_store();
|
|
68927
68977
|
init_internal_error();
|
|
68978
|
+
init_session_utils();
|
|
68928
68979
|
init_run_index();
|
|
68929
68980
|
LIST_RUNS_DEBOUNCE_MS = 3e4;
|
|
68930
68981
|
}
|
|
@@ -69137,11 +69188,15 @@ var init_delivery_coordinator = __esm({
|
|
|
69137
69188
|
deps;
|
|
69138
69189
|
ttlTimer;
|
|
69139
69190
|
timerStarted = false;
|
|
69191
|
+
/** The session id passed to the most recent activate(); used by flushQueuedResults
|
|
69192
|
+
* to park deliveries owned by a different session (vector #12). */
|
|
69193
|
+
activeSessionId;
|
|
69140
69194
|
constructor(deps) {
|
|
69141
69195
|
this.deps = deps;
|
|
69142
69196
|
}
|
|
69143
69197
|
activate(sessionId) {
|
|
69144
69198
|
this.active = true;
|
|
69199
|
+
this.activeSessionId = sessionId;
|
|
69145
69200
|
this.flushQueuedResults();
|
|
69146
69201
|
}
|
|
69147
69202
|
deactivate() {
|
|
@@ -69154,7 +69209,7 @@ var init_delivery_coordinator = __esm({
|
|
|
69154
69209
|
getPendingCount() {
|
|
69155
69210
|
return this.pending.length;
|
|
69156
69211
|
}
|
|
69157
|
-
deliverResult(runId, result4) {
|
|
69212
|
+
deliverResult(runId, result4, ownerSessionId) {
|
|
69158
69213
|
if (this.active && this.deps.emit) {
|
|
69159
69214
|
try {
|
|
69160
69215
|
this.deps.emit("pi-crew:run-result", result4);
|
|
@@ -69168,10 +69223,11 @@ var init_delivery_coordinator = __esm({
|
|
|
69168
69223
|
runId,
|
|
69169
69224
|
payload: result4,
|
|
69170
69225
|
timestamp: Date.now(),
|
|
69171
|
-
type: "result"
|
|
69226
|
+
type: "result",
|
|
69227
|
+
ownerSessionId
|
|
69172
69228
|
});
|
|
69173
69229
|
}
|
|
69174
|
-
deliverNotification(notification) {
|
|
69230
|
+
deliverNotification(notification, ownerSessionId) {
|
|
69175
69231
|
let delivered = false;
|
|
69176
69232
|
if (this.active && this.deps.sendFollowUp) {
|
|
69177
69233
|
try {
|
|
@@ -69195,10 +69251,11 @@ var init_delivery_coordinator = __esm({
|
|
|
69195
69251
|
runId: notification.runId ?? "",
|
|
69196
69252
|
payload: notification,
|
|
69197
69253
|
timestamp: Date.now(),
|
|
69198
|
-
type: "notification"
|
|
69254
|
+
type: "notification",
|
|
69255
|
+
ownerSessionId
|
|
69199
69256
|
});
|
|
69200
69257
|
}
|
|
69201
|
-
deliverSteer(runId, message) {
|
|
69258
|
+
deliverSteer(runId, message, ownerSessionId) {
|
|
69202
69259
|
if (this.active && this.deps.sendWakeUp) {
|
|
69203
69260
|
try {
|
|
69204
69261
|
this.deps.sendWakeUp(message);
|
|
@@ -69212,7 +69269,8 @@ var init_delivery_coordinator = __esm({
|
|
|
69212
69269
|
runId,
|
|
69213
69270
|
payload: message,
|
|
69214
69271
|
timestamp: Date.now(),
|
|
69215
|
-
type: "steer"
|
|
69272
|
+
type: "steer",
|
|
69273
|
+
ownerSessionId
|
|
69216
69274
|
});
|
|
69217
69275
|
}
|
|
69218
69276
|
flushQueuedResults() {
|
|
@@ -69223,6 +69281,10 @@ var init_delivery_coordinator = __esm({
|
|
|
69223
69281
|
try {
|
|
69224
69282
|
const retryLater = [];
|
|
69225
69283
|
for (const delivery of batch) {
|
|
69284
|
+
if (delivery.ownerSessionId && this.activeSessionId && delivery.ownerSessionId !== this.activeSessionId) {
|
|
69285
|
+
retryLater.push(delivery);
|
|
69286
|
+
continue;
|
|
69287
|
+
}
|
|
69226
69288
|
if (delivery.type === "steer" && delivery.generation !== void 0 && delivery.generation !== this.generation) {
|
|
69227
69289
|
logInternalError("delivery-coordinator.flush.stale", void 0, `runId=${delivery.runId} type=${delivery.type}`);
|
|
69228
69290
|
continue;
|
|
@@ -70659,7 +70721,7 @@ async function configureObservability(ctx, state, deps) {
|
|
|
70659
70721
|
deps.pi.on?.("before_agent_start", () => {
|
|
70660
70722
|
if (deps.isCleanedUp()) return;
|
|
70661
70723
|
try {
|
|
70662
|
-
deps.reconcileStaleRuns(ctx.cwd, deps.getManifestCache(ctx.cwd));
|
|
70724
|
+
deps.reconcileStaleRuns(ctx.cwd, deps.getManifestCache(ctx.cwd), extractSessionId(ctx));
|
|
70663
70725
|
} catch (error) {
|
|
70664
70726
|
logInternalError("register.autoRepair.turnHook", error);
|
|
70665
70727
|
}
|
|
@@ -70671,7 +70733,7 @@ async function configureObservability(ctx, state, deps) {
|
|
|
70671
70733
|
state.autoRepairTimer = setInterval(() => {
|
|
70672
70734
|
if (deps.isCleanedUp()) return;
|
|
70673
70735
|
try {
|
|
70674
|
-
const staleResults = deps.reconcileStaleRuns(ctx.cwd, deps.getManifestCache(ctx.cwd));
|
|
70736
|
+
const staleResults = deps.reconcileStaleRuns(ctx.cwd, deps.getManifestCache(ctx.cwd), extractSessionId(ctx));
|
|
70675
70737
|
if (Array.isArray(staleResults) && staleResults.length > 0) {
|
|
70676
70738
|
for (const result4 of staleResults) {
|
|
70677
70739
|
const repaired = result4.repaired;
|
|
@@ -70729,7 +70791,8 @@ async function configureObservability(ctx, state, deps) {
|
|
|
70729
70791
|
const cacheSnapshot = deps.getManifestCache(cwdSnapshot);
|
|
70730
70792
|
void deps.importCrashRecovery().then(({ detectInterruptedRuns: detectInterruptedRuns2 }) => {
|
|
70731
70793
|
if (deps.isCleanedUp()) return;
|
|
70732
|
-
|
|
70794
|
+
const sid = extractSessionId(ctx);
|
|
70795
|
+
for (const plan of detectInterruptedRuns2(cwdSnapshot, cacheSnapshot, 3e5, sid)) {
|
|
70733
70796
|
deps.notifyOperator({
|
|
70734
70797
|
id: `recovery_prompt_${plan.runId}`,
|
|
70735
70798
|
severity: "warning",
|
|
@@ -70769,6 +70832,7 @@ var init_observability = __esm({
|
|
|
70769
70832
|
init_config();
|
|
70770
70833
|
init_internal_error();
|
|
70771
70834
|
init_paths();
|
|
70835
|
+
init_session_utils();
|
|
70772
70836
|
}
|
|
70773
70837
|
});
|
|
70774
70838
|
|
|
@@ -74346,7 +74410,10 @@ function buildRegistrationContext(pi) {
|
|
|
74346
74410
|
globalStore: globalThis,
|
|
74347
74411
|
runtimeCleanupStoreKey: RUNTIME_CLEANUP_STORE_KEY,
|
|
74348
74412
|
captureSessionGeneration: () => ctx.sessionGeneration,
|
|
74349
|
-
isOwnerSessionCurrent: (gen) =>
|
|
74413
|
+
isOwnerSessionCurrent: (gen, oid) => {
|
|
74414
|
+
const currentSid = ctx.currentCtx?.sessionManager?.getSessionId?.();
|
|
74415
|
+
return !ctx.cleanedUp && (oid === void 0 || oid === currentSid) && (gen === void 0 || gen === ctx.sessionGeneration);
|
|
74416
|
+
},
|
|
74350
74417
|
isContextCurrent: (c, gen) => !ctx.cleanedUp && ctx.currentCtx === c && ctx.sessionGeneration === gen,
|
|
74351
74418
|
telemetryEnabled: () => loadConfig(ctx.currentCtx?.cwd ?? process.cwd()).config.telemetry?.enabled !== false,
|
|
74352
74419
|
notifyOperator: void 0,
|
|
@@ -74358,7 +74425,7 @@ function buildRegistrationContext(pi) {
|
|
|
74358
74425
|
configureObservability: () => void 0,
|
|
74359
74426
|
configureDeliveryCoordinator: () => void 0,
|
|
74360
74427
|
importCrashRecovery: void 0,
|
|
74361
|
-
purgeStaleActiveRunIndexSyncIfLoaded: () => void 0,
|
|
74428
|
+
purgeStaleActiveRunIndexSyncIfLoaded: (_currentSessionId) => void 0,
|
|
74362
74429
|
startForegroundRun: void 0,
|
|
74363
74430
|
abortForegroundRun: () => false,
|
|
74364
74431
|
openLiveSidebar: () => void 0,
|
|
@@ -74405,10 +74472,10 @@ async function importCrashRecovery() {
|
|
|
74405
74472
|
}
|
|
74406
74473
|
return _cachedCrashRecovery;
|
|
74407
74474
|
}
|
|
74408
|
-
function purgeStaleActiveRunIndexSyncIfLoaded() {
|
|
74475
|
+
function purgeStaleActiveRunIndexSyncIfLoaded(currentSessionId) {
|
|
74409
74476
|
if (!_cachedCrashRecovery) return;
|
|
74410
74477
|
try {
|
|
74411
|
-
_cachedCrashRecovery.purgeStaleActiveRunIndex();
|
|
74478
|
+
_cachedCrashRecovery.purgeStaleActiveRunIndex(3e5, Date.now(), currentSessionId);
|
|
74412
74479
|
} catch (error) {
|
|
74413
74480
|
logInternalError("register.cleanupRuntime.purgeStale", error);
|
|
74414
74481
|
}
|
|
@@ -74761,7 +74828,7 @@ async function configureObservabilityImpl(pi, ctx, extCtx) {
|
|
|
74761
74828
|
getManifestCache: ctx.getManifestCache,
|
|
74762
74829
|
notifyOperator: ctx.notifyOperator,
|
|
74763
74830
|
isCleanedUp: () => ctx.cleanedUp,
|
|
74764
|
-
reconcileStaleRuns: (cwd, cache3) => reconcileAllStaleRuns(cwd, cache3),
|
|
74831
|
+
reconcileStaleRuns: (cwd, cache3, currentSessionId) => reconcileAllStaleRuns(cwd, cache3, void 0, currentSessionId),
|
|
74765
74832
|
reconcileOrphanedTempWorkspaces: (now, opts) => reconcileOrphanedTempWorkspaces(now, opts),
|
|
74766
74833
|
cleanupOrphanTempDirs,
|
|
74767
74834
|
cleanupLegacyOrphanTempDirs,
|
|
@@ -74805,9 +74872,9 @@ import * as fsp3 from "node:fs/promises";
|
|
|
74805
74872
|
import * as net2 from "node:net";
|
|
74806
74873
|
|
|
74807
74874
|
// src/runtime/broker/crew-broker-tokens.ts
|
|
74808
|
-
import { randomUUID as
|
|
74875
|
+
import { randomUUID as randomUUID9, timingSafeEqual as timingSafeEqual3 } from "node:crypto";
|
|
74809
74876
|
function newBrokerToken() {
|
|
74810
|
-
return
|
|
74877
|
+
return randomUUID9();
|
|
74811
74878
|
}
|
|
74812
74879
|
var BrokerTokenRegistry = class _BrokerTokenRegistry {
|
|
74813
74880
|
map = /* @__PURE__ */ new Map();
|
|
@@ -76312,9 +76379,12 @@ function registerCrewAutocomplete(ctx) {
|
|
|
76312
76379
|
// src/extension/session-summary.ts
|
|
76313
76380
|
init_crew_agent_records();
|
|
76314
76381
|
init_process_status();
|
|
76382
|
+
init_session_utils();
|
|
76315
76383
|
init_run_index();
|
|
76316
76384
|
function notifyActiveRuns(ctx) {
|
|
76385
|
+
const sid = extractSessionId(ctx);
|
|
76317
76386
|
const active = listRuns(ctx.cwd).filter((run) => {
|
|
76387
|
+
if (sid && run.ownerSessionId && run.ownerSessionId !== sid) return false;
|
|
76318
76388
|
if (run.status !== "queued" && run.status !== "planning" && run.status !== "running") return false;
|
|
76319
76389
|
const agents = readCrewAgents(run);
|
|
76320
76390
|
return isDisplayActiveRun(run, agents);
|
|
@@ -76537,7 +76607,7 @@ async function runDeferredSessionCleanup(pi, ctx, ownerGeneration, currentSessio
|
|
|
76537
76607
|
logInternalError("register.sessionStart.orphanWorkers", error);
|
|
76538
76608
|
}
|
|
76539
76609
|
try {
|
|
76540
|
-
const { purged } = purgeStaleActiveRunIndexFn();
|
|
76610
|
+
const { purged } = purgeStaleActiveRunIndexFn(3e5, Date.now(), currentSessionId);
|
|
76541
76611
|
if (purged.length > 0) {
|
|
76542
76612
|
ctx.notifyOperator({
|
|
76543
76613
|
id: `active_index_purge`,
|
|
@@ -76551,7 +76621,7 @@ async function runDeferredSessionCleanup(pi, ctx, ownerGeneration, currentSessio
|
|
|
76551
76621
|
logInternalError("register.sessionStart.globalIndexPurge", error);
|
|
76552
76622
|
}
|
|
76553
76623
|
try {
|
|
76554
|
-
const staleResults = reconcileAllStaleRuns(extensionCtx.cwd, ctx.getManifestCache(extensionCtx.cwd)) ?? [];
|
|
76624
|
+
const staleResults = reconcileAllStaleRuns(extensionCtx.cwd, ctx.getManifestCache(extensionCtx.cwd), Date.now(), currentSessionId) ?? [];
|
|
76555
76625
|
if (staleResults.length > 0) {
|
|
76556
76626
|
ctx.notifyOperator({
|
|
76557
76627
|
id: "stale_reconcile",
|
|
@@ -76671,6 +76741,9 @@ function setupCrewScheduler(pi, ctx, extensionCtx, sessionId) {
|
|
|
76671
76741
|
});
|
|
76672
76742
|
return crewScheduler;
|
|
76673
76743
|
}
|
|
76744
|
+
function filterManifestsForHealthNotifications(manifests, currentSessionId) {
|
|
76745
|
+
return manifests.filter((run) => !run.ownerSessionId || run.ownerSessionId === currentSessionId);
|
|
76746
|
+
}
|
|
76674
76747
|
function setupRenderLoop(pi, ctx, extensionCtx, loadedConfig) {
|
|
76675
76748
|
ctx.disposeRenderSchedulerSubscriptions();
|
|
76676
76749
|
ctx.renderScheduler?.dispose();
|
|
@@ -76764,11 +76837,8 @@ function setupRenderLoop(pi, ctx, extensionCtx, loadedConfig) {
|
|
|
76764
76837
|
ctx.widgetState.notificationCount ?? 0,
|
|
76765
76838
|
manifests
|
|
76766
76839
|
);
|
|
76767
|
-
const
|
|
76768
|
-
const
|
|
76769
|
-
const sessionManifests = manifests.filter(
|
|
76770
|
-
(run) => !run.ownerSessionId || run.ownerSessionId === currentSessionId || run.ownerSessionGeneration === currentSessionGen
|
|
76771
|
-
);
|
|
76840
|
+
const currentSessionId = ctx.currentCtx?.sessionManager?.getSessionId();
|
|
76841
|
+
const sessionManifests = filterManifestsForHealthNotifications(manifests, currentSessionId);
|
|
76772
76842
|
const now = Date.now();
|
|
76773
76843
|
for (const run of sessionManifests) {
|
|
76774
76844
|
if (run.status !== "running") continue;
|
|
@@ -76998,6 +77068,7 @@ init_powerbar_publisher();
|
|
|
76998
77068
|
init_widget();
|
|
76999
77069
|
init_internal_error();
|
|
77000
77070
|
init_paths();
|
|
77071
|
+
init_session_utils();
|
|
77001
77072
|
init_async_notifier();
|
|
77002
77073
|
init_team_tool2();
|
|
77003
77074
|
init_lifecycle();
|
|
@@ -77021,6 +77092,7 @@ function buildCleanupSessionResourcesOnly(ctx) {
|
|
|
77021
77092
|
return () => {
|
|
77022
77093
|
if (ctx.cleanedUp) return;
|
|
77023
77094
|
ctx.cleanedUp = true;
|
|
77095
|
+
const sid = extractSessionId(ctx.currentCtx);
|
|
77024
77096
|
if (ctx.preloadTimer) {
|
|
77025
77097
|
clearTimeout(ctx.preloadTimer);
|
|
77026
77098
|
ctx.preloadTimer = void 0;
|
|
@@ -77032,7 +77104,7 @@ function buildCleanupSessionResourcesOnly(ctx) {
|
|
|
77032
77104
|
ctx.stopSessionBoundSubagents();
|
|
77033
77105
|
ctx.crewScheduler?.stop();
|
|
77034
77106
|
stopAsyncRunNotifier(ctx.notifierState);
|
|
77035
|
-
ctx.purgeStaleActiveRunIndexSyncIfLoaded();
|
|
77107
|
+
ctx.purgeStaleActiveRunIndexSyncIfLoaded(sid);
|
|
77036
77108
|
stopCrewWidget(ctx.currentCtx, ctx.widgetState, ctx.currentCtx ? loadConfig(ctx.currentCtx.cwd).config.ui : void 0);
|
|
77037
77109
|
clearPiCrewPowerbar(ctx.pi.events);
|
|
77038
77110
|
disposePowerbarCoalescer();
|
|
@@ -77064,6 +77136,7 @@ function buildCleanupRuntime(ctx) {
|
|
|
77064
77136
|
return () => {
|
|
77065
77137
|
if (ctx.cleanedUp) return;
|
|
77066
77138
|
ctx.cleanedUp = true;
|
|
77139
|
+
const sid = extractSessionId(ctx.currentCtx);
|
|
77067
77140
|
if (ctx.preloadTimer) {
|
|
77068
77141
|
clearTimeout(ctx.preloadTimer);
|
|
77069
77142
|
ctx.preloadTimer = void 0;
|
|
@@ -77078,7 +77151,7 @@ function buildCleanupRuntime(ctx) {
|
|
|
77078
77151
|
stopAllWatchdogs();
|
|
77079
77152
|
ctx.crewScheduler?.stop();
|
|
77080
77153
|
stopAsyncRunNotifier(ctx.notifierState);
|
|
77081
|
-
ctx.purgeStaleActiveRunIndexSyncIfLoaded();
|
|
77154
|
+
ctx.purgeStaleActiveRunIndexSyncIfLoaded(sid);
|
|
77082
77155
|
stopCrewWidget(ctx.currentCtx, ctx.widgetState, ctx.currentCtx ? loadConfig(ctx.currentCtx.cwd).config.ui : void 0);
|
|
77083
77156
|
clearPiCrewPowerbar(ctx.pi.events);
|
|
77084
77157
|
disposePowerbarCoalescer();
|
|
@@ -77155,7 +77228,7 @@ function createCompletionCoalescer(pi, ctx) {
|
|
|
77155
77228
|
const f = ctx.subagentManager.getRecord(c.agentId);
|
|
77156
77229
|
const p = ctx.currentCtx ? readPersistedSubagentRecord(ctx.currentCtx.cwd, c.agentId) : void 0;
|
|
77157
77230
|
if (f?.resultConsumed || p?.resultConsumed) return false;
|
|
77158
|
-
if (!ctx.isOwnerSessionCurrent(f?.ownerSessionGeneration ?? c.ownerGen)) return false;
|
|
77231
|
+
if (!ctx.isOwnerSessionCurrent(f?.ownerSessionGeneration ?? c.ownerGen, f?.ownerSessionId)) return false;
|
|
77159
77232
|
return true;
|
|
77160
77233
|
};
|
|
77161
77234
|
const flush = () => {
|
|
@@ -77263,7 +77336,7 @@ function onTerminalStatus(pi, ctx, record, coalescer) {
|
|
|
77263
77336
|
});
|
|
77264
77337
|
}
|
|
77265
77338
|
if (!record.background) return;
|
|
77266
|
-
if (!ctx.isOwnerSessionCurrent(record.ownerSessionGeneration)) return;
|
|
77339
|
+
if (!ctx.isOwnerSessionCurrent(record.ownerSessionGeneration, record.ownerSessionId)) return;
|
|
77267
77340
|
if (record.status !== "completed" && record.status !== "failed" && record.status !== "cancelled" && record.status !== "blocked" && record.status !== "error")
|
|
77268
77341
|
return;
|
|
77269
77342
|
const agentId = record.id;
|
|
@@ -77279,7 +77352,7 @@ function onTerminalStatus(pi, ctx, record, coalescer) {
|
|
|
77279
77352
|
const fresh = ctx.subagentManager.getRecord(agentId);
|
|
77280
77353
|
const persisted = ctx.currentCtx ? readPersistedSubagentRecord(ctx.currentCtx.cwd, agentId) : void 0;
|
|
77281
77354
|
if (fresh?.resultConsumed || persisted?.resultConsumed) return;
|
|
77282
|
-
if (!ctx.isOwnerSessionCurrent(fresh?.ownerSessionGeneration ?? ownerGen)) return;
|
|
77355
|
+
if (!ctx.isOwnerSessionCurrent(fresh?.ownerSessionGeneration ?? ownerGen, fresh?.ownerSessionId)) return;
|
|
77283
77356
|
const member = {
|
|
77284
77357
|
id: agentId,
|
|
77285
77358
|
description: agentDescription,
|
|
@@ -77314,7 +77387,8 @@ function onTerminalStatus(pi, ctx, record, coalescer) {
|
|
|
77314
77387
|
}
|
|
77315
77388
|
function onInternalEvent(pi, ctx, event, payload) {
|
|
77316
77389
|
const ownerGeneration = typeof payload?.ownerSessionGeneration === "number" ? payload.ownerSessionGeneration : void 0;
|
|
77317
|
-
|
|
77390
|
+
const ownerSessionId = typeof payload?.ownerSessionId === "string" ? payload.ownerSessionId : void 0;
|
|
77391
|
+
if (ownerGeneration !== void 0 && !ctx.isOwnerSessionCurrent(ownerGeneration, ownerSessionId)) return;
|
|
77318
77392
|
if (event === "subagent.stuck-blocked") {
|
|
77319
77393
|
const p = payload;
|
|
77320
77394
|
const id = typeof p.id === "string" ? p.id : "unknown";
|
|
@@ -77428,6 +77502,7 @@ function registerSubagentTools(pi, subagentManager, options = {}) {
|
|
|
77428
77502
|
spawnOptions.ownerSessionGeneration = options.ownerSessionGeneration?.();
|
|
77429
77503
|
if (!spawnOptions.prompt.trim()) return subagentToolResult(t("agent.requiresPrompt"), {}, true);
|
|
77430
77504
|
const ctxWithSession = withSessionId(ctx);
|
|
77505
|
+
spawnOptions.ownerSessionId = ctxWithSession.sessionId;
|
|
77431
77506
|
const runner = async (currentOptions, childSignal) => handleTeamTool6(
|
|
77432
77507
|
{
|
|
77433
77508
|
action: "run",
|
|
@@ -77549,6 +77624,10 @@ function registerSubagentTools(pi, subagentManager, options = {}) {
|
|
|
77549
77624
|
const inMemory = subagentManager.getRecord(p.agent_id);
|
|
77550
77625
|
const record = inMemory ?? readPersistedSubagentRecord(ctx.cwd, p.agent_id);
|
|
77551
77626
|
if (!record) return subagentToolResult(t("result.notFound", { id: p.agent_id }), {}, true);
|
|
77627
|
+
const currentSessionId = withSessionId(ctx).sessionId;
|
|
77628
|
+
if (record.ownerSessionId && record.ownerSessionId !== currentSessionId) {
|
|
77629
|
+
return subagentToolResult("Agent belongs to another session.", {}, true);
|
|
77630
|
+
}
|
|
77552
77631
|
let current = refreshPersistedSubagentRecord(ctx, record);
|
|
77553
77632
|
if (inMemory && current !== inMemory) Object.assign(inMemory, current);
|
|
77554
77633
|
if (!inMemory && !current.runId && (current.status === "running" || current.status === "queued")) {
|
|
@@ -77599,9 +77678,11 @@ function registerSubagentTools(pi, subagentManager, options = {}) {
|
|
|
77599
77678
|
}
|
|
77600
77679
|
const output = readSubagentRunResult(ctx, current);
|
|
77601
77680
|
if (current.status !== "running" && current.status !== "queued" && current.status !== "blocked") {
|
|
77602
|
-
current.
|
|
77603
|
-
|
|
77604
|
-
|
|
77681
|
+
if (!current.ownerSessionId || current.ownerSessionId === currentSessionId) {
|
|
77682
|
+
current.resultConsumed = true;
|
|
77683
|
+
if (inMemory) inMemory.resultConsumed = true;
|
|
77684
|
+
savePersistedSubagentRecord(ctx.cwd, current);
|
|
77685
|
+
}
|
|
77605
77686
|
}
|
|
77606
77687
|
const text = [
|
|
77607
77688
|
p.verbose ? formatSubagentRecord(current) : void 0,
|