pi-crew 0.11.1 → 0.11.2

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.
Files changed (121) hide show
  1. package/CHANGELOG.md +39 -9
  2. package/README.md +161 -1036
  3. package/agents/verifier.md +18 -7
  4. package/dist/index.mjs +744 -91462
  5. package/docs/README.md +57 -46
  6. package/docs/architecture.md +87 -33
  7. package/docs/commands-reference.md +9 -5
  8. package/docs/troubleshooting.md +3 -2
  9. package/package.json +1 -3
  10. package/schema.json +29 -0
  11. package/skills/real-test-pi-crew/SKILL.md +193 -36
  12. package/src/agents/agent-config.ts +1 -1
  13. package/src/agents/discover-agents.ts +1 -1
  14. package/src/config/config-validation.ts +15 -0
  15. package/src/config/config.ts +47 -13
  16. package/src/config/env-vars.ts +35 -0
  17. package/src/config/types.ts +19 -0
  18. package/src/errors.ts +2 -2
  19. package/src/extension/async-notifier.ts +23 -0
  20. package/src/extension/help.ts +21 -10
  21. package/src/extension/knowledge-injection.ts +2 -1
  22. package/src/extension/management.ts +8 -3
  23. package/src/extension/notification-sink.ts +17 -0
  24. package/src/extension/registration/command-utils.ts +28 -2
  25. package/src/extension/registration/commands/dashboard.ts +11 -1
  26. package/src/extension/registration/commands/manage.ts +31 -15
  27. package/src/extension/registration/commands/run.ts +24 -2
  28. package/src/extension/registration/commands/shared.ts +23 -0
  29. package/src/extension/registration/commands/status.ts +25 -2
  30. package/src/extension/registration/context-builder.ts +8 -2
  31. package/src/extension/registration/health-notify-policy.ts +100 -0
  32. package/src/extension/registration/lazy-configurers.ts +35 -0
  33. package/src/extension/registration/lifecycle-handlers.ts +91 -30
  34. package/src/extension/registration/lifecycle.ts +75 -10
  35. package/src/extension/registration/observability.ts +98 -35
  36. package/src/extension/registration/registration-types.ts +7 -5
  37. package/src/extension/registration/runtime-cleanup.ts +9 -3
  38. package/src/extension/registration/subagent-helpers.ts +38 -0
  39. package/src/extension/registration/wire-cross-extension.ts +28 -0
  40. package/src/extension/run-compare.ts +220 -0
  41. package/src/extension/run-export.ts +37 -5
  42. package/src/extension/run-maintenance.ts +155 -5
  43. package/src/extension/team-tool/dispatch/index.ts +3 -2
  44. package/src/extension/team-tool/dispatch/manage.ts +5 -2
  45. package/src/extension/team-tool/goal.ts +4 -1
  46. package/src/extension/team-tool/handle-settings.ts +19 -2
  47. package/src/extension/team-tool/health-monitor.ts +21 -7
  48. package/src/extension/team-tool/lifecycle-actions.ts +49 -1
  49. package/src/extension/team-tool/plan.ts +10 -0
  50. package/src/extension/team-tool/routing-hint.ts +63 -0
  51. package/src/extension/team-tool/status.ts +4 -0
  52. package/src/extension/team-tool.ts +52 -6
  53. package/src/extension/webhook-notify.ts +382 -0
  54. package/src/observability/metric-sink.ts +12 -2
  55. package/src/prompt/prompt-runtime.ts +82 -31
  56. package/src/prompt/worker-events-channel.ts +12 -0
  57. package/src/runtime/README.md +1 -1
  58. package/src/runtime/async-runner.ts +87 -1
  59. package/src/runtime/background-runner.ts +313 -234
  60. package/src/runtime/broker/crew-broker.ts +17 -11
  61. package/src/runtime/broker/delegate/shadow-lifecycle.ts +92 -0
  62. package/src/runtime/broker/wait-status-cache.ts +1 -1
  63. package/src/runtime/child-pi/child-pi-timers.ts +1 -1
  64. package/src/runtime/child-pi/mock-fixtures.ts +48 -0
  65. package/src/runtime/crew-agent-records.ts +337 -45
  66. package/src/runtime/deadletter.ts +43 -1
  67. package/src/runtime/delegate-spawn.ts +5 -1
  68. package/src/runtime/dispatch-batch.ts +72 -5
  69. package/src/runtime/goal-workflow/goal-loop-runner.ts +73 -4
  70. package/src/runtime/heartbeat/heartbeat-watcher.ts +7 -0
  71. package/src/runtime/model/model-fallback.ts +21 -1
  72. package/src/runtime/model/pi-args.ts +8 -10
  73. package/src/runtime/recovery/crash-recovery.ts +25 -1
  74. package/src/runtime/run-worker.ts +12 -1
  75. package/src/runtime/scheduling/global-worker-cap.ts +13 -6
  76. package/src/runtime/scheduling/run-coalesced-task-group.ts +27 -1
  77. package/src/runtime/scheduling/scheduler.ts +49 -13
  78. package/src/runtime/scheduling/semaphore.ts +148 -20
  79. package/src/runtime/scratchpad/README.md +1 -1
  80. package/src/runtime/scratchpad/protocol.ts +1 -1
  81. package/src/runtime/settings-store.ts +1 -1
  82. package/src/runtime/skill-instructions.ts +22 -0
  83. package/src/runtime/stale-reconciler.ts +85 -13
  84. package/src/runtime/task-runner/pre-execution.ts +26 -2
  85. package/src/runtime/task-runner/prompt-builder.ts +142 -45
  86. package/src/runtime/task-runner.ts +21 -1
  87. package/src/runtime/team-runner.ts +38 -1
  88. package/src/runtime/workspace-lock.ts +4 -1
  89. package/src/schema/config-schema.ts +14 -0
  90. package/src/schema/team-tool-schema.ts +17 -0
  91. package/src/state/atomic-write.ts +53 -0
  92. package/src/state/contracts.ts +109 -0
  93. package/src/state/coordination/locks.ts +191 -33
  94. package/src/state/coordination/mailbox.ts +140 -15
  95. package/src/state/crew-init.ts +87 -12
  96. package/src/state/event-log/cursor.ts +37 -1
  97. package/src/state/event-log/event-log-rotation.ts +72 -7
  98. package/src/state/stores/active-run-registry.ts +13 -1
  99. package/src/state/stores/state-store.ts +112 -22
  100. package/src/state/types.ts +4 -0
  101. package/src/ui/dashboard-panes/agents-pane.ts +11 -2
  102. package/src/ui/heartbeat-aggregator.ts +34 -0
  103. package/src/ui/keybinding-map.ts +22 -4
  104. package/src/ui/live-conversation-overlay.ts +6 -3
  105. package/src/ui/run-dashboard.ts +98 -5
  106. package/src/ui/run-snapshot-cache.ts +18 -1
  107. package/src/ui/spinner.ts +26 -2
  108. package/src/ui/tool-progress-formatter.ts +2 -1
  109. package/src/ui/tool-renderers/brief-mode.ts +2 -1
  110. package/src/ui/tool-renderers/index.ts +3 -3
  111. package/src/utils/incremental-reader.ts +11 -3
  112. package/src/utils/paths.ts +94 -12
  113. package/src/utils/project-markers.ts +40 -0
  114. package/src/worktree/worktree-manager.ts +206 -26
  115. package/workflows/distill.workflow.md +3 -3
  116. package/workflows/fast-fix.workflow.md +1 -1
  117. package/workflows/plan-execute.workflow.md +1 -1
  118. package/workflows/review.workflow.md +1 -1
  119. package/workflows/strict-fast-fix.workflow.md +1 -1
  120. package/docs/migration-v0.4-v0.5.md +0 -208
  121. package/docs/runtime-flow.md +0 -148
@@ -32,4 +32,4 @@ clusters are extracted into subdirectories; the remaining files stay at the root
32
32
  - **observability** — `effectiveness.ts`, `agent-observability.ts`, `command-trace.ts`
33
33
  - **misc** — `stale-reconciler.ts`, `parent-guard.ts`, `manifest-cache.ts`, `event-stream-bridge.ts`, `policy-engine.ts`, `role-permission.ts`, `workspace-lock.ts`, `workspace-tree.ts`, `session-*.ts`, ...
34
34
 
35
- See `docs/COVERAGE-ASSESSMENT-2026-08-01.md` § "Source reorganization" for the reorg history + remaining-cluster plan.
35
+ See `docs/archive/COVERAGE-ASSESSMENT-2026-08-01.md` § "Source reorganization" for the reorg history + remaining-cluster plan.
@@ -209,6 +209,9 @@ export const BACKGROUND_RUNNER_ENV_ALLOWLIST: string[] = [
209
209
  "PI_TEAMS_PI_BIN",
210
210
  "PI_TEAMS_MOCK_CHILD_PI",
211
211
  "PI_CREW_ALLOW_MOCK",
212
+ // Entry guard for the detached runner main() (background-runner.ts skips main()
213
+ // on plain imports — the inline async test seam lazy-imports it).
214
+ "PI_CREW_BACKGROUND_RUNNER_ENTRY",
212
215
  // Phase 1.5: worker-thread atomic writer opt-in (RFC 15).
213
216
  "PI_CREW_WORKER_ATOMIC_WRITER",
214
217
  "PI_TEAMS_WORKER_ATOMIC_WRITER",
@@ -262,7 +265,87 @@ export function buildBrokerStdinLine(runId: string, socketPath: string, tasks: R
262
265
  return `${JSON.stringify({ v: 2, runId, socketPath, tasks })}\n`;
263
266
  }
264
267
 
268
+ /**
269
+ * IN-PROCESS ASYNC TEST SEAM (kills two classes of test pain):
270
+ * 1. Windows Defender first-spawn stall — CI ground truth (run 36093514388
271
+ * attempt 3): the detached background-runner spawn stalled >300s with the
272
+ * task left "queued" while the event loop stayed healthy. No second
273
+ * process to come up = no per-file-hash AV scan inside a test deadline.
274
+ * 2. Orphan-tmpdir leak — a detached runner survives the test's rmSync and
275
+ * keeps writing run state into a deleted tree (source of the ~3.4k
276
+ * pi-crew-* debris, 2026-09-26 triage). In-process, the run dies with the
277
+ * test process.
278
+ *
279
+ * Gated by BOTH PI_CREW_TEST_ASYNC_INLINE=1 AND the existing test-fixture
280
+ * gate PI_CREW_ALLOW_MOCK=1 (defense-in-depth: production never sets either).
281
+ * The inline host reuses background-runner's executeBackgroundRun core —
282
+ * same code path as the detached runner, no drift.
283
+ */
284
+ export function isInlineAsyncTestSeamActive(): boolean {
285
+ return getCrewEnv("PI_CREW_TEST_ASYNC_INLINE") === "1" && getCrewEnv("PI_CREW_ALLOW_MOCK") === "1";
286
+ }
287
+
288
+ async function runInlineBackgroundTeamRun(manifest: TeamRunManifest, logPath: string): Promise<SpawnBackgroundTeamRunResult> {
289
+ const log = (message: string): void => {
290
+ try {
291
+ fs.appendFileSync(logPath, `${message}\n`, "utf-8");
292
+ } catch {
293
+ /* best-effort */
294
+ }
295
+ };
296
+ log(`[pi-crew] inline test seam: executing run ${manifest.runId} in-process (no detached runner) pid=${process.pid}`);
297
+ await appendEventAsync(manifest.eventsPath, {
298
+ type: "async.spawned",
299
+ runId: manifest.runId,
300
+ data: { pid: process.pid, logPath, inline: true },
301
+ });
302
+ // Fire-and-forget — spawn() semantics: the caller must NOT await the run.
303
+ // Catch-all: a late rejection after the test ended must not become an
304
+ // unhandledRejection that fails the whole file.
305
+ void (async () => {
306
+ try {
307
+ // LAZY: defer the core import — background-runner must not load in the
308
+ // normal spawn path (and its module-scope main() is entry-guarded).
309
+ const { executeBackgroundRun } = await import("./background-runner.ts"); // LAZY: defer the core import — background-runner must not load in the normal spawn path
310
+ const { loadRunManifestById } = await import("../state/stores/state-store.ts"); // LAZY: state-store pulls the whole stores chain
311
+ const { withRunLockSync } = await import("../state/coordination/locks.ts"); // LAZY: coordination locks only needed on the inline path
312
+ const loaded = withRunLockSync(manifest, () => loadRunManifestById(manifest.cwd, manifest.runId), { staleMs: 30_000 });
313
+ const effectiveManifest = loaded?.manifest ?? manifest;
314
+ const tasks = loaded?.tasks ?? [];
315
+ await executeBackgroundRun({ manifest: effectiveManifest, tasks }, { log: (message) => log(`[inline] ${message}`) });
316
+ } catch (error) {
317
+ const message = error instanceof Error ? error.message : String(error);
318
+ log(`[pi-crew] inline test seam run ${manifest.runId} FAILED: ${message}`);
319
+ try {
320
+ const { loadRunManifestByIdAsync: reload, updateRunStatus } = await import("../state/stores/state-store.ts"); // LAZY: failure-path imports only
321
+ const fresh = (await reload(manifest.cwd, manifest.runId))?.manifest;
322
+ if (fresh) updateRunStatus(fresh, "failed", `inline test seam: ${message}`);
323
+ else
324
+ await appendEventAsync(manifest.eventsPath, {
325
+ type: "async.failed",
326
+ runId: manifest.runId,
327
+ message: `inline test seam: ${message}`,
328
+ });
329
+ if (fresh)
330
+ await appendEventAsync(fresh.eventsPath, {
331
+ type: "async.failed",
332
+ runId: fresh.runId,
333
+ message: `inline test seam: ${message}`,
334
+ });
335
+ } catch {
336
+ /* best-effort */
337
+ }
338
+ }
339
+ })();
340
+ return { pid: process.pid, logPath };
341
+ }
342
+
265
343
  export async function spawnBackgroundTeamRun(manifest: TeamRunManifest): Promise<SpawnBackgroundTeamRunResult> {
344
+ if (isInlineAsyncTestSeamActive()) {
345
+ const logPath = path.join(manifest.stateRoot, "background.log");
346
+ fs.mkdirSync(manifest.stateRoot, { recursive: true });
347
+ return runInlineBackgroundTeamRun(manifest, logPath);
348
+ }
266
349
  // FIX (2026-07-02, perf review F-critical): use packageRoot() instead of
267
350
  // import.meta.url-relative path. The previous path.resolve walks
268
351
  // <bundleDir>/background-runner.ts, which is correct in src/ but BROKEN
@@ -291,7 +374,10 @@ export async function spawnBackgroundTeamRun(manifest: TeamRunManifest): Promise
291
374
  // `npm root -g` probe. No-op when pi-crew and pi are co-located. See
292
375
  // src/runtime/peer-dep.ts.
293
376
  const peerDepDir = resolvePeerDepDir();
294
- const childEnv = buildBackgroundRunnerEnv(peerDepDir ? { ...filteredEnv, [PEER_DEP_DIR_ENV]: peerDepDir } : filteredEnv);
377
+ const childEnv = buildBackgroundRunnerEnv({
378
+ ...(peerDepDir ? { ...filteredEnv, [PEER_DEP_DIR_ENV]: peerDepDir } : filteredEnv),
379
+ PI_CREW_BACKGROUND_RUNNER_ENTRY: "1",
380
+ });
295
381
 
296
382
  const loader = resolveTypeScriptLoader();
297
383
  if (!loader) {