pi-crew 0.11.21 → 0.11.23
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 +41 -0
- package/dist/index.mjs +542 -531
- package/package.json +2 -1
- package/src/errors.ts +14 -1
- package/src/extension/async-notifier.ts +42 -17
- package/src/extension/cross-extension-rpc.ts +42 -5
- package/src/extension/notification-router.ts +15 -2
- package/src/extension/registration/lifecycle-handlers.ts +36 -13
- package/src/extension/registration/runtime-cleanup.ts +17 -0
- package/src/extension/registration/wire-cross-extension.ts +26 -0
- package/src/extension/rpc-hmac.ts +53 -2
- package/src/extension/team-tool/cancel.ts +34 -21
- package/src/extension/team-tool/dispatch/index.ts +6 -5
- package/src/extension/team-tool/dispatch/status.ts +42 -2
- package/src/extension/team-tool/respond.ts +8 -6
- package/src/extension/team-tool/run.ts +4 -4
- package/src/extension/team-tool.ts +24 -2
- package/src/prompt/inbox-poll.ts +77 -25
- package/src/prompt/message-tool.ts +62 -4
- package/src/prompt/prompt-runtime.ts +82 -32
- package/src/prompt/surface-worker.ts +13 -1
- package/src/runtime/broker/crew-broker-client.ts +74 -16
- package/src/runtime/broker/crew-broker.ts +120 -97
- package/src/runtime/broker/protocol/msg-send-targets.ts +74 -0
- package/src/runtime/broker/protocol/request-parsers.ts +68 -0
- package/src/runtime/broker/wait-status-cache.ts +14 -5
- package/src/runtime/child-pi/child-pi-spawn.ts +47 -9
- package/src/runtime/child-pi/child-pi.ts +20 -2
- package/src/runtime/child-pi/mock-fixtures.ts +23 -0
- package/src/runtime/compaction/compact-stages/truncation-stage.ts +45 -3
- package/src/runtime/compaction/important-line-classifier.ts +85 -11
- package/src/runtime/compaction/tool-output-pruner.ts +35 -11
- package/src/runtime/crew-agent-records.ts +32 -14
- package/src/runtime/delivery-coordinator.ts +30 -0
- package/src/runtime/dispatch-batch.ts +9 -6
- package/src/runtime/dwf-state-store.ts +41 -7
- package/src/runtime/finalize-run.ts +13 -2
- package/src/runtime/goal-workflow/dynamic-workflow-context.ts +192 -64
- package/src/runtime/goal-workflow/goal-loop-runner.ts +130 -3
- package/src/runtime/heartbeat/heartbeat-watcher.ts +7 -0
- package/src/runtime/live-session/embedded-tier.ts +3 -1
- package/src/runtime/live-session/live-session-runtime.ts +54 -1
- package/src/runtime/model/model-fallback.ts +23 -1
- package/src/runtime/output/pi-json-output.ts +26 -1
- package/src/runtime/policy-engine.ts +18 -0
- package/src/runtime/process/zombie-scanner.ts +84 -16
- package/src/runtime/process-status.ts +6 -1
- package/src/runtime/recovery/crash-recovery.ts +170 -28
- package/src/runtime/rpc/rpc-worker.ts +44 -1
- package/src/runtime/scheduling/run-coalesced-task-group.ts +73 -6
- package/src/runtime/scheduling/scheduler.ts +74 -11
- package/src/runtime/scratchpad/engine.ts +26 -3
- package/src/runtime/settings-store.ts +22 -2
- package/src/runtime/stale-reconciler.ts +4 -1
- package/src/runtime/surface/tmux-provider.ts +24 -3
- package/src/runtime/task-health.ts +16 -1
- package/src/runtime/task-output-context.ts +143 -71
- package/src/runtime/task-packet.ts +70 -17
- package/src/runtime/task-runner/child-executor.ts +27 -0
- package/src/runtime/task-runner/output-splitter.ts +79 -16
- package/src/runtime/task-runner/post-execution.ts +75 -15
- package/src/runtime/task-runner/state-helpers.ts +92 -2
- package/src/runtime/usage-tracker.ts +11 -0
- package/src/runtime/verification/green-contract.ts +17 -0
- package/src/runtime/verification/verification-gates.ts +24 -6
- package/src/runtime/workspace-lock.ts +53 -0
- package/src/schema/team-tool-schema.ts +10 -4
- package/src/state/coordination/mailbox.ts +133 -38
- package/src/state/decision-ledger.ts +56 -8
- package/src/state/event-log/cursor.ts +14 -2
- package/src/state/event-log/event-log-rotation.ts +83 -5
- package/src/state/event-log/event-log.ts +181 -12
- package/src/state/stores/active-run-registry.ts +10 -3
- package/src/state/types.ts +9 -1
- package/src/ui/agents-jobs-browser.ts +22 -8
- package/src/ui/dashboard-panes/agents-pane.ts +5 -2
- package/src/ui/events-state-source.ts +67 -28
- package/src/ui/inline-panel/agent-pane.ts +13 -6
- package/src/ui/inline-panel/agent-transcript.ts +33 -21
- package/src/ui/inline-panel/agent-view-overlay.ts +18 -3
- package/src/ui/inline-panel/index.ts +21 -1
- package/src/ui/live-run-sidebar.ts +14 -3
- package/src/ui/overlays/mailbox-compose-overlay.ts +10 -4
- package/src/ui/powerbar-publisher.ts +6 -3
- package/src/ui/rail.ts +7 -1
- package/src/ui/render-scheduler.ts +53 -1
- package/src/ui/run-action-dispatcher.ts +68 -20
- package/src/ui/status-colors.ts +9 -0
- package/src/utils/env-filter.ts +8 -0
|
@@ -13,11 +13,14 @@ async function handleTeamTool(
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
import { isToolError, textFromToolResult } from "../extension/tool-result.ts";
|
|
16
|
+
import { isRunLockBusyError } from "../runtime/broker/protocol/lock-busy.ts";
|
|
16
17
|
import { readCrewAgents } from "../runtime/crew-agent-records.ts";
|
|
17
18
|
import { exportDiagnostic } from "../runtime/diagnostic-export.ts";
|
|
19
|
+
import { withRunLockSync } from "../state/coordination/locks.ts";
|
|
18
20
|
import type { MailboxDirection, MailboxMessage } from "../state/coordination/mailbox.ts";
|
|
19
21
|
import { appendEventBuffered } from "../state/event-log/event-log.ts";
|
|
20
22
|
import { loadRunManifestById, saveRunTasks } from "../state/stores/state-store.ts";
|
|
23
|
+
import type { TeamTaskState } from "../state/types.ts";
|
|
21
24
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
22
25
|
import { formatCount } from "./format-helpers.ts";
|
|
23
26
|
|
|
@@ -120,35 +123,80 @@ export function dispatchHealthRecovery(ctx: ExtensionContext, runId: string): Pr
|
|
|
120
123
|
});
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
/** Staleness window for the kill-stale sweep (R4-6). */
|
|
127
|
+
const KILL_STALE_HEARTBEAT_MS = 60_000;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* R4-6 (DR-02 Wave 2 Cluster C): pure RMW core of the kill-stale sweep —
|
|
131
|
+
* mark running/queued tasks whose heartbeat is older than `staleMs` dead.
|
|
132
|
+
* Exported so the locked dispatcher body stays unit-testable without a
|
|
133
|
+
* harness (repo seam pattern; see state-helpers-cas-contention.test.ts).
|
|
134
|
+
* Predicate is byte-identical to the previous inline map.
|
|
135
|
+
*/
|
|
136
|
+
export function markStaleWorkerHeartbeatsDead(
|
|
137
|
+
tasks: readonly TeamTaskState[],
|
|
138
|
+
currentMs: number,
|
|
139
|
+
staleMs: number = KILL_STALE_HEARTBEAT_MS,
|
|
140
|
+
): { tasks: TeamTaskState[]; count: number } {
|
|
141
|
+
const now = new Date(currentMs).toISOString();
|
|
142
|
+
let count = 0;
|
|
143
|
+
const updated = tasks.map((task) => {
|
|
144
|
+
if ((task.status !== "running" && task.status !== "queued") || !task.heartbeat || task.heartbeat.alive === false) return task;
|
|
145
|
+
const lastSeenMs = Date.parse(task.heartbeat.lastSeenAt);
|
|
146
|
+
if (!Number.isFinite(lastSeenMs) || currentMs - lastSeenMs <= staleMs) return task;
|
|
147
|
+
count += 1;
|
|
148
|
+
return {
|
|
149
|
+
...task,
|
|
150
|
+
heartbeat: { ...task.heartbeat, alive: false, lastSeenAt: now },
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
return { tasks: updated, count };
|
|
154
|
+
}
|
|
155
|
+
|
|
123
156
|
export async function dispatchKillStaleWorkers(ctx: ExtensionContext, runId: string): Promise<RunActionResult> {
|
|
124
157
|
try {
|
|
125
|
-
const loaded = loadRunManifestById(ctx.cwd, runId);
|
|
158
|
+
const loaded = loadRunManifestById(ctx.cwd, runId);
|
|
126
159
|
if (!loaded) return { ok: false, message: `Run '${runId}' not found.` };
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
160
|
+
// R4-6 (DR-02 Wave 2 Cluster C): this sweep used to be an UNLOCKED
|
|
161
|
+
// load→map→save (":125 no withRunLock - best-effort") — a cross-process
|
|
162
|
+
// writer holding the run lock (leader heartbeats, task claims, delegate
|
|
163
|
+
// flushes) could land a fresh tasks.json between our read and write and
|
|
164
|
+
// get clobbered by the STALE array. Now a run-locked RMW with the fresh
|
|
165
|
+
// re-read INSIDE the lock (R13-S1 canonical pattern, team-tool/api/heartbeat.ts).
|
|
166
|
+
// Best-effort semantics are preserved on contention: the UI never blocks —
|
|
167
|
+
// the sweep is skipped with a warn, never a stale write.
|
|
168
|
+
let applied: { tasks: TeamTaskState[]; count: number } | undefined;
|
|
169
|
+
try {
|
|
170
|
+
applied = withRunLockSync(loaded.manifest, () => {
|
|
171
|
+
const fresh = loadRunManifestById(loaded.manifest.cwd, loaded.manifest.runId);
|
|
172
|
+
if (!fresh) return undefined;
|
|
173
|
+
const result = markStaleWorkerHeartbeatsDead(fresh.tasks, Date.now());
|
|
174
|
+
// count=0 → nothing changed; skip the identical-content rewrite.
|
|
175
|
+
if (result.count > 0) saveRunTasks(fresh.manifest, result.tasks);
|
|
176
|
+
return result;
|
|
177
|
+
});
|
|
178
|
+
} catch (error) {
|
|
179
|
+
if (isRunLockBusyError(error)) {
|
|
180
|
+
logInternalError("run-action-dispatcher.killStale", error, `runId=${runId} skipped: run lock busy`, "warn");
|
|
181
|
+
return {
|
|
182
|
+
ok: false,
|
|
183
|
+
message: `Skipped kill-stale for run '${runId}': another operation holds the run lock. Try again in a moment.`,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
if (!applied) return { ok: false, message: `Run '${runId}' not found.` };
|
|
189
|
+
const message = `Marked ${applied.count} stale worker heartbeat(s) dead.`;
|
|
142
190
|
appendEventBuffered(loaded.manifest.eventsPath, {
|
|
143
191
|
type: "worker.kill_stale",
|
|
144
192
|
runId,
|
|
145
|
-
message
|
|
146
|
-
data: { count },
|
|
193
|
+
message,
|
|
194
|
+
data: { count: applied.count },
|
|
147
195
|
}).catch((e) => logInternalError("run_action_dispatcher.buffered", e, "type=worker.kill_stale"));
|
|
148
196
|
return {
|
|
149
197
|
ok: true,
|
|
150
|
-
message
|
|
151
|
-
data: { count },
|
|
198
|
+
message,
|
|
199
|
+
data: { count: applied.count },
|
|
152
200
|
};
|
|
153
201
|
} catch (error) {
|
|
154
202
|
return err(error);
|
package/src/ui/status-colors.ts
CHANGED
|
@@ -19,6 +19,11 @@ export function colorForStatus(status: RunStatus): CrewThemeColor {
|
|
|
19
19
|
return "accent";
|
|
20
20
|
case "waiting":
|
|
21
21
|
return "muted";
|
|
22
|
+
// F4 (DR-02 wave 2): "planning" was missing from BOTH palettes — it
|
|
23
|
+
// fell through to this default, which was correct-by-luck but unsigned.
|
|
24
|
+
// Informational/dim, same tier as queued's default fall-through.
|
|
25
|
+
case "planning":
|
|
26
|
+
return "dim";
|
|
22
27
|
case "completed":
|
|
23
28
|
return "success";
|
|
24
29
|
case "failed":
|
|
@@ -52,6 +57,10 @@ export function iconForStatus(status: RunStatus, options?: { runningGlyph?: stri
|
|
|
52
57
|
return "⏳";
|
|
53
58
|
case "queued":
|
|
54
59
|
return "◦";
|
|
60
|
+
case "planning":
|
|
61
|
+
// F4: informational — the dim dot already used for unknown-but-known
|
|
62
|
+
// states; kept in the colorizeStatusGlyphs vocabulary (dim tier).
|
|
63
|
+
return "·";
|
|
55
64
|
case "blocked":
|
|
56
65
|
return "⏸";
|
|
57
66
|
case "needs_attention":
|
package/src/utils/env-filter.ts
CHANGED
|
@@ -60,6 +60,14 @@ export function providerEnvKeys(modelId: string | undefined): string[] {
|
|
|
60
60
|
* Build a scoped allowlist that includes system vars + only the provider keys
|
|
61
61
|
* relevant to the assigned model (and its fallback chain).
|
|
62
62
|
*
|
|
63
|
+
* R6-8 (DR-03 round-6) contract note: callers SHOULD pass the task's full
|
|
64
|
+
* candidate chain (primary + fallbacks) — child-pi-spawn.ts threads it from
|
|
65
|
+
* the executor's attempt chain. Bare model ids (no "provider/" prefix)
|
|
66
|
+
* contribute ZERO keys here (providerEnvKeys returns [] for them); scoping is
|
|
67
|
+
* never widened to all-providers to compensate — instead the spawn layer warns
|
|
68
|
+
* when a truly-bare single model resolves zero provider keys (see
|
|
69
|
+
* child-pi-spawn.ts R6-8 warn; auth.json users are unaffected).
|
|
70
|
+
*
|
|
63
71
|
* @param baseAllowList - Non-provider system vars to always include
|
|
64
72
|
* @param models - Model IDs to include provider keys for (primary + fallbacks)
|
|
65
73
|
* @returns Combined allowlist with scoped provider keys
|