pi-crew 0.11.7 → 0.11.9
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/.githooks/pre-commit +22 -0
- package/.githooks/pre-push +56 -0
- package/CHANGELOG.md +196 -1
- package/dist/index.mjs +533 -515
- package/docs/publishing.md +29 -0
- package/docs/usage.md +1 -1
- package/index.ts +3 -3
- package/install.mjs +4 -1
- package/package.json +8 -5
- package/scripts/install-hooks.mjs +32 -0
- package/skills/real-test-pi-crew/SKILL.md +57 -18
- package/src/config/config-validation.ts +8 -1
- package/src/config/defaults.ts +8 -1
- package/src/config/env-vars.ts +16 -1
- package/src/config/types.ts +28 -4
- package/src/extension/command-completions.ts +44 -22
- package/src/extension/registration/foreground-run-controller.ts +19 -10
- package/src/extension/registration/lifecycle-handlers.ts +6 -491
- package/src/extension/registration/lifecycle.ts +7 -90
- package/src/extension/registration/render-loop.ts +532 -0
- package/src/extension/team-tool/doctor.ts +6 -0
- package/src/extension/team-tool/handle-settings.ts +4 -1
- package/src/runtime/child-pi/child-pi-spawn.ts +7 -0
- package/src/runtime/child-pi/child-pi.ts +37 -2
- package/src/runtime/child-pi/pi-version.ts +187 -0
- package/src/runtime/classifier/classifier-service.ts +298 -0
- package/src/runtime/dispatch-batch.ts +4 -0
- package/src/runtime/live-session/live-session-runtime.ts +31 -0
- package/src/runtime/model/pi-args.ts +62 -3
- package/src/runtime/process/zombie-scanner.ts +168 -7
- package/src/runtime/rpc/README.md +64 -25
- package/src/runtime/rpc/rpc-worker.ts +146 -26
- package/src/runtime/run-worker.ts +89 -15
- package/src/runtime/scheduling/run-coalesced-task-group.ts +3 -0
- package/src/runtime/skill-instructions.ts +66 -1
- package/src/runtime/surface/resolve-surface.ts +34 -19
- package/src/runtime/task-runner/child-executor.ts +132 -0
- package/src/runtime/task-runner/pre-execution.ts +8 -0
- package/src/runtime/task-runner.ts +6 -0
- package/src/schema/config-schema.ts +20 -8
- package/src/schema/team-tool-schema.ts +4 -2
- package/src/state/contracts.ts +5 -0
- package/src/ui/dashboard-panes/agents-pane.ts +3 -2
- package/src/ui/dashboard-panes/health-pane.ts +6 -1
- package/src/ui/dashboard-panes/mailbox-pane.ts +12 -7
- package/src/ui/dashboard-panes/plan-pane.ts +5 -2
- package/src/ui/dashboard-panes/progress-pane.ts +8 -2
- package/src/ui/format-helpers.ts +11 -0
- package/src/ui/live-conversation-overlay.ts +5 -3
- package/src/ui/live-duration.ts +5 -4
- package/src/ui/live-run-sidebar.ts +90 -20
- package/src/ui/overlays/mailbox-compose-overlay.ts +31 -1
- package/src/ui/rail.ts +14 -1
- package/src/ui/run-action-dispatcher.ts +2 -1
- package/src/ui/run-dashboard.ts +62 -22
- package/src/ui/run-snapshot-cache.ts +32 -0
- package/src/ui/settings-overlay.ts +36 -3
- package/src/ui/tool-renderers/brief-mode.ts +2 -2
- package/src/ui/transcript-viewer.ts +4 -1
- package/src/ui/widget/index.ts +10 -2
- package/src/ui/widget/task-list.ts +22 -7
- package/src/ui/widget/widget-model.ts +5 -4
- package/src/ui/widget/widget-renderer.ts +212 -37
- package/src/utils/relative-time.ts +11 -3
- package/src/utils/socket-path.ts +48 -8
- package/src/utils/visual.ts +32 -2
|
@@ -53,31 +53,53 @@ function statusIcon(status: TeamRunManifest["status"]): string {
|
|
|
53
53
|
* process cwd matches the session cwd.
|
|
54
54
|
*/
|
|
55
55
|
export function suggestRunIds(_prefix: string, cwd?: string): AutocompleteItem[] | null {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
// L-crash (2026-10-08): completion callbacks run inside pi's autocomplete
|
|
57
|
+
// provider, which does not catch extension errors — never throw here.
|
|
58
|
+
try {
|
|
59
|
+
const resolvedCwd = cwd ?? process.cwd();
|
|
60
|
+
const runs = listRecentRuns(resolvedCwd, MAX_RUN_SUGGESTIONS);
|
|
61
|
+
if (runs.length === 0) return null;
|
|
62
|
+
const items: AutocompleteItem[] = runs.map((run) => ({
|
|
63
|
+
value: run.runId,
|
|
64
|
+
label: run.runId,
|
|
65
|
+
description: `${statusIcon(run.status)} ${run.status} · ${run.team} · ${(run.goal ?? "").slice(0, 48)}`,
|
|
66
|
+
}));
|
|
67
|
+
return filterByPrefix(items, _prefix);
|
|
68
|
+
} catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
65
71
|
}
|
|
66
72
|
|
|
67
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Suggest task IDs within a specific run (for /team-result <runId> <taskId>).
|
|
75
|
+
*
|
|
76
|
+
* L-crash (2026-10-08, P0): this runs inside pi's autocomplete provider
|
|
77
|
+
* (`CombinedAutocompleteProvider.getSuggestions`), which does NOT catch
|
|
78
|
+
* extension errors — a throw here kills the whole pi process (live-caught:
|
|
79
|
+
* uncaught_exception "Invalid runId: team_x/team-transcript" after the
|
|
80
|
+
* autocomplete popup raced typed input and glued a "/…" suffix onto the
|
|
81
|
+
* runId token; assertSafePathId correctly rejected it, but the throw
|
|
82
|
+
* escaped). Completion callbacks must NEVER throw: any failure -> null.
|
|
83
|
+
*/
|
|
68
84
|
export async function suggestTaskIds(runId: string, prefix: string, cwd?: string): Promise<AutocompleteItem[] | null> {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
try {
|
|
86
|
+
const resolvedCwd = cwd ?? process.cwd();
|
|
87
|
+
// Dynamic import to avoid pulling state-store into the hot command-registration path.
|
|
88
|
+
// LAZY: defer dynamic import of ../state/stores/state-store.ts to its call site.
|
|
89
|
+
const { loadRunManifestById } = await import("../state/stores/state-store.ts");
|
|
90
|
+
const loaded = loadRunManifestById(resolvedCwd, runId);
|
|
91
|
+
if (!loaded) return null;
|
|
92
|
+
const items: AutocompleteItem[] = loaded.tasks.map((task) => ({
|
|
93
|
+
value: task.id,
|
|
94
|
+
label: task.id,
|
|
95
|
+
description: `${task.status} · ${task.role} · ${task.title?.slice(0, 40) ?? ""}`,
|
|
96
|
+
}));
|
|
97
|
+
return filterByPrefix(items, prefix);
|
|
98
|
+
} catch {
|
|
99
|
+
// Invalid runId (path-unsafe chars), import/state-store/cache failure —
|
|
100
|
+
// degrade to "no suggestions" instead of crashing the host process.
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
81
103
|
}
|
|
82
104
|
|
|
83
105
|
/** Suggest available teams for /team-run <team>. */
|
|
@@ -92,6 +92,15 @@ function startForegroundRunImpl(
|
|
|
92
92
|
runId?: string,
|
|
93
93
|
): void {
|
|
94
94
|
const ownerGeneration = ctx.captureSessionGeneration();
|
|
95
|
+
// Issue #62: tool-dispatched runs receive a SPREAD COPY of the session
|
|
96
|
+
// context (withSessionId() always returns { ...ctx }), so the object-
|
|
97
|
+
// identity check (isContextCurrent) was false from the very first moment
|
|
98
|
+
// and the whole completion block below was silently skipped for every
|
|
99
|
+
// foreground run started via the team/subagent tools — stale working
|
|
100
|
+
// message, no crew:run-completed entry, no crew.run.* metrics. Liveness
|
|
101
|
+
// for the reporting half is therefore session-ID based; the UI clear is
|
|
102
|
+
// unconditional (try/catch guards a disposed ctx).
|
|
103
|
+
const ownerSessionId = extensionCtx.sessionManager?.getSessionId?.();
|
|
95
104
|
const controller = new AbortController();
|
|
96
105
|
const key = runId ?? Symbol();
|
|
97
106
|
ctx.foregroundTeamRunControllers.set(key, controller);
|
|
@@ -130,7 +139,7 @@ function startForegroundRunImpl(
|
|
|
130
139
|
logInternalError("register.foreground-run-failure", statusError, `runId=${runId}`);
|
|
131
140
|
}
|
|
132
141
|
}
|
|
133
|
-
if (ctx.
|
|
142
|
+
if (ctx.isOwnerSessionCurrent(ownerGeneration, ownerSessionId)) {
|
|
134
143
|
extensionCtx.ui.notify(`pi-crew foreground run failed: ${message}`, "error");
|
|
135
144
|
} else {
|
|
136
145
|
logInternalError("register.foreground-run-failure", error, `runId=${runId} context disposed`);
|
|
@@ -145,18 +154,18 @@ function startForegroundRunImpl(
|
|
|
145
154
|
})
|
|
146
155
|
.catch((error) => logInternalError("register.foreground-watchdog", error, `runId=${runId}`));
|
|
147
156
|
}
|
|
148
|
-
const ownerCurrent = ctx.
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
const ownerCurrent = ctx.isOwnerSessionCurrent(ownerGeneration, ownerSessionId);
|
|
158
|
+
// Issue #62: clear the working message UNCONDITIONALLY. The `hasUI`
|
|
159
|
+
// getter THROWS on a disposed ctx, so touch it inside try/catch —
|
|
160
|
+
// a stale ctx just means the host already reset its UI; a live one
|
|
161
|
+
// must never keep spinning a finished run's label.
|
|
162
|
+
try {
|
|
163
|
+
if (extensionCtx.hasUI) {
|
|
155
164
|
setWorkingIndicator(extensionCtx);
|
|
156
165
|
extensionCtx.ui.setWorkingMessage();
|
|
157
|
-
} catch {
|
|
158
|
-
/* ignore */
|
|
159
166
|
}
|
|
167
|
+
} catch {
|
|
168
|
+
/* disposed ctx — host-side UI reset already happened */
|
|
160
169
|
}
|
|
161
170
|
if (ownerCurrent && runId) {
|
|
162
171
|
const loaded = loadRunManifestById(extensionCtx.cwd, runId);
|