ultimate-pi 0.23.0 → 0.25.0

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 (62) hide show
  1. package/.pi/extensions/agt-prompt-guard.ts +20 -6
  2. package/.pi/extensions/harness-ask-user.ts +14 -5
  3. package/.pi/extensions/harness-auto-compact.ts +94 -0
  4. package/.pi/extensions/harness-debate-tools.ts +59 -4
  5. package/.pi/extensions/harness-live-widget.ts +25 -0
  6. package/.pi/extensions/harness-plan-approval.ts +65 -15
  7. package/.pi/extensions/harness-plan-orchestration.ts +140 -0
  8. package/.pi/extensions/harness-run-context.ts +501 -48
  9. package/.pi/extensions/harness-telemetry.ts +1 -0
  10. package/.pi/extensions/harness-web-tools.ts +1 -0
  11. package/.pi/extensions/policy-gate.ts +9 -0
  12. package/.pi/extensions/trace-recorder.ts +1 -0
  13. package/.pi/harness/agents.manifest.json +1 -1
  14. package/.pi/harness/docs/adrs/0056-agent-native-speed-wiring.md +26 -0
  15. package/.pi/harness/env.harness.template +14 -0
  16. package/.pi/harness/specs/harness-posthog-event.schema.json +2 -0
  17. package/.pi/harness/specs/sentrux-signal.schema.json +1 -1
  18. package/.pi/lib/harness-auto-approve.ts +140 -0
  19. package/.pi/lib/harness-auto-compact-policy.ts +85 -0
  20. package/.pi/lib/harness-cocoindex-refresh.ts +82 -2
  21. package/.pi/lib/harness-phase-telemetry.ts +81 -0
  22. package/.pi/lib/harness-phase-worker.ts +23 -0
  23. package/.pi/lib/harness-plan-fsm.ts +162 -0
  24. package/.pi/lib/harness-plan-route.ts +134 -0
  25. package/.pi/lib/harness-posthog.ts +6 -1
  26. package/.pi/lib/harness-remediation.ts +79 -0
  27. package/.pi/lib/harness-repair-brief.ts +2 -2
  28. package/.pi/lib/harness-review-parallel.ts +18 -0
  29. package/.pi/lib/harness-run-context.ts +119 -72
  30. package/.pi/lib/harness-spawn-budget.ts +32 -4
  31. package/.pi/lib/harness-spawn-stall-detector.ts +106 -0
  32. package/.pi/lib/harness-spawn-topology.ts +50 -1
  33. package/.pi/lib/harness-subagent-precheck.ts +41 -0
  34. package/.pi/lib/harness-subagent-progress.ts +119 -0
  35. package/.pi/lib/harness-subagent-timeout.ts +81 -0
  36. package/.pi/lib/harness-subagents-bridge.ts +94 -8
  37. package/.pi/lib/harness-ui-state.ts +5 -0
  38. package/.pi/lib/harness-vcc-settings.ts +36 -0
  39. package/.pi/lib/plan-approval-readiness.ts +9 -5
  40. package/.pi/lib/plan-debate-eligibility-snapshot.ts +90 -0
  41. package/.pi/lib/plan-debate-eligibility.ts +16 -9
  42. package/.pi/lib/plan-debate-focus.ts +23 -11
  43. package/.pi/lib/plan-debate-gate.ts +94 -31
  44. package/.pi/lib/plan-debate-round-status.ts +23 -8
  45. package/.pi/lib/plan-debate-wall-clock.ts +57 -0
  46. package/.pi/lib/plan-headless-ux.ts +598 -0
  47. package/.pi/lib/plan-human-gates.ts +24 -85
  48. package/.pi/lib/plan-messenger.ts +3 -3
  49. package/.pi/lib/plan-review-gate.ts +56 -0
  50. package/.pi/prompts/harness-abort.md +1 -0
  51. package/.pi/prompts/harness-auto.md +1 -1
  52. package/.pi/prompts/harness-clear.md +6 -6
  53. package/.pi/prompts/harness-plan.md +15 -2
  54. package/.pi/prompts/harness-review.md +26 -12
  55. package/.pi/scripts/harness-e2e-workflow.mjs +94 -0
  56. package/.pi/scripts/harness-project-toggle.mjs +1 -1
  57. package/.pi/scripts/harness-sentrux-cli.mjs +26 -1
  58. package/.pi/scripts/harness-sentrux-report.mjs +41 -6
  59. package/CHANGELOG.md +16 -0
  60. package/README.md +2 -2
  61. package/package.json +1 -1
  62. package/vendor/pi-subagents/src/subagents.ts +41 -10
@@ -31,7 +31,17 @@ function usage() {
31
31
  process.exit(2);
32
32
  }
33
33
 
34
+ function parseSentruxTimeoutMs() {
35
+ const raw = process.env.HARNESS_SENTRUX_TIMEOUT_MS;
36
+ if (raw?.trim()) {
37
+ const parsed = Number.parseInt(raw, 10);
38
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
39
+ }
40
+ return 300_000;
41
+ }
42
+
34
43
  function runSentrux(args, projectRoot) {
44
+ const timeoutMs = parseSentruxTimeoutMs();
35
45
  return new Promise((resolve, reject) => {
36
46
  const child = spawn("sentrux", args, {
37
47
  cwd: projectRoot,
@@ -39,6 +49,11 @@ function runSentrux(args, projectRoot) {
39
49
  });
40
50
  let stdout = "";
41
51
  let stderr = "";
52
+ let timedOut = false;
53
+ const timer = setTimeout(() => {
54
+ timedOut = true;
55
+ child.kill("SIGTERM");
56
+ }, timeoutMs);
42
57
  child.stdout?.on("data", (c) => {
43
58
  stdout += c.toString();
44
59
  });
@@ -46,6 +61,7 @@ function runSentrux(args, projectRoot) {
46
61
  stderr += c.toString();
47
62
  });
48
63
  child.on("error", (err) => {
64
+ clearTimeout(timer);
49
65
  if (err?.code === "ENOENT") {
50
66
  reject(
51
67
  Object.assign(new Error("sentrux not installed"), { code: 127 }),
@@ -55,7 +71,13 @@ function runSentrux(args, projectRoot) {
55
71
  reject(err);
56
72
  });
57
73
  child.on("close", (code) => {
58
- resolve({ code: code ?? 1, stdout, stderr });
74
+ clearTimeout(timer);
75
+ resolve({
76
+ code: timedOut ? 124 : (code ?? 1),
77
+ stdout,
78
+ stderr,
79
+ timedOut,
80
+ });
59
81
  });
60
82
  });
61
83
  }
@@ -104,11 +126,13 @@ function buildSignal(runId, report) {
104
126
  run_id: runId || "unknown",
105
127
  check_pass: check.check_pass,
106
128
  gate_status:
107
- gate.status === "degraded"
108
- ? "degraded"
109
- : gate.status === "pass"
110
- ? "pass"
111
- : "skipped",
129
+ gate.status === "timeout"
130
+ ? "timeout"
131
+ : gate.status === "degraded"
132
+ ? "degraded"
133
+ : gate.status === "pass"
134
+ ? "pass"
135
+ : "skipped",
112
136
  quality_signal_summary: summaryParts.join(" | ") || undefined,
113
137
  recorded_at: report.captured_at,
114
138
  phase: "review",
@@ -130,6 +154,7 @@ async function captureReport(projectRoot) {
130
154
 
131
155
  const checkRun = await runSentrux(["check", projectRoot], projectRoot);
132
156
  const gateRun = await runSentrux(["gate", projectRoot], projectRoot);
157
+ const timedOut = Boolean(checkRun.timedOut || gateRun.timedOut);
133
158
 
134
159
  const checkFiltered = filterSentruxOutputLines(
135
160
  `${checkRun.stdout}\n${checkRun.stderr}`,
@@ -160,6 +185,15 @@ async function captureReport(projectRoot) {
160
185
 
161
186
  if (checkRun.code === 127) throw Object.assign(new Error("sentrux not installed"), { code: 127 });
162
187
 
188
+ if (timedOut) {
189
+ check.check_pass = false;
190
+ gate.status = "timeout";
191
+ gate.degraded_reasons = [
192
+ ...(gate.degraded_reasons ?? []),
193
+ `sentrux CLI exceeded HARNESS_SENTRUX_TIMEOUT_MS (${parseSentruxTimeoutMs()}ms)`,
194
+ ];
195
+ }
196
+
163
197
  return {
164
198
  schema_version: "1.0.0",
165
199
  captured_at,
@@ -170,6 +204,7 @@ async function captureReport(projectRoot) {
170
204
  check,
171
205
  gate,
172
206
  exit_codes: { check: checkRun.code, gate: gateRun.code },
207
+ timed_out: timedOut || undefined,
173
208
  };
174
209
  }
175
210
 
package/CHANGELOG.md CHANGED
@@ -3,6 +3,22 @@
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
5
 
6
+ ## [v0.25.0] — 2026-06-07
7
+
8
+ ### ✨ Features
9
+
10
+ - Wire agent-native speed program: `parallel_probes` end-to-end, eligibility snapshot, plan FSM (`harness_plan_next_action`), synthesizer routing, auto-approve policy, per-phase spawn caps, review parallel default, 50% VCC auto-compact, ADR 0056.
11
+
12
+ ### 🐛 Fixes
13
+
14
+ - Headless QA E2E: seed planning-context for smoke auto-approve, finalize plan on `agent_end`, write smoke ISO for `/harness-auto`, and exit via `ctx.abort()` without kill-switch false failures.
15
+
16
+ ## [v0.24.0] — 2026-06-06
17
+
18
+ ### ✨ Features
19
+
20
+ - Cut harness workflow latency with phase-aware subagent timeouts, debate wall-clock caps, ccc index debounce, optional parallel review spawns, progress UI with stall detection, and PostHog phase telemetry.
21
+
6
22
  ## [v0.23.0] — 2026-05-28
7
23
 
8
24
  ### ✨ Features
package/README.md CHANGED
@@ -77,7 +77,7 @@ If `/harness-review` returns `implementation_gap`, run:
77
77
  | `/harness-steer [--attempt N]` | Post-review repair pass for `implementation_gap`; executor reads `repair-brief.yaml`, then you re-run `/harness-review`. |
78
78
  | `/harness-abort [reason]` | Safely aborts the active run, clears plan readiness, and re-locks mutation until a fresh plan is approved. |
79
79
 
80
- | `/harness-clear` | Deletes only historical `.pi/harness/runs/<run_id>/` directories after mandatory confirmation; active run is preserved and non-affirmative/outage confirmation paths are no-op. |
80
+ | `/harness-clear` | Deletes all `.pi/harness/runs/<run_id>/` directories, including the active run, after mandatory confirmation; non-affirmative/outage confirmation paths are no-op. |
81
81
  | `/harness-trace [--run <id>] [--phase plan\|execute\|evaluate\|adversary\|merge]` | Summarizes run traces and artifact handoffs for replay/forensics. |
82
82
  | `/harness-incident --trigger <reason> [--run <id>] [--severity low\|med\|high\|critical]` | Records incident, rollback, and override trail for harness failures. |
83
83
  | `/harness-sentrux-steward [--run <id>]` | Ad-hoc architectural intent review for Sentrux manifest/rule alignment. |
@@ -130,7 +130,7 @@ Subagents run isolated from the parent session. They persist canonical YAML thro
130
130
  | Need to inspect handoff | Run `/harness-trace` or inspect `.pi/harness/runs/<run_id>/`. |
131
131
  | Need to restart safely | Run `/harness-abort [reason]`, then create a fresh plan. |
132
132
 
133
- | Need to prune old run history safely | Run `/harness-clear`; only historical run directories are eligible and confirmation failure/cancel deletes nothing. |
133
+ | Need to prune old run history safely | Run `/harness-clear`; all run directories, including the active run, are eligible and confirmation failure/cancel deletes nothing. |
134
134
  | Review says `implementation_gap` | Run `/harness-steer`, then `/harness-review`. |
135
135
  | Review says `plan_gap` | Revise with `/harness-plan "<updated task>"`. |
136
136
  | Sentrux missing | Install/configure Sentrux or keep it skipped; harness verification still reports the status. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-pi",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Governed AI coding harness for pi.dev — bootstrap, plan, execute, review, and steer with deterministic policy gates",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -69,10 +69,18 @@ export interface HarnessSubagentsOptions {
69
69
  ) => Promise<SpawnAuthForward | undefined>;
70
70
  onSpawnStart?: (harnessAgentCount: number) => void;
71
71
  onSpawnEnd?: (harnessAgentCount: number) => void;
72
+ /** Phase-aware default when tool params omit timeoutMs (harness bridge). */
73
+ resolveDefaultTimeoutMs?: (
74
+ params: Record<string, unknown>,
75
+ agents: AgentConfig[],
76
+ ctx: ExtensionContext,
77
+ ) => number | undefined;
72
78
  onCompleted?: (details: {
73
79
  agents: string[];
74
80
  mode: string;
75
81
  durationMs: number;
82
+ timedOut?: boolean;
83
+ stop_reason?: "timeout" | "complete" | "aborted";
76
84
  }) => void;
77
85
  truncateDetails?: boolean;
78
86
  }
@@ -1387,7 +1395,13 @@ export function createSubagentsExtension(
1387
1395
  const agentScope: AgentScope = params.agentScope ?? defaultScope;
1388
1396
  const discovery = discoverAgents(ctx.cwd, agentScope, packageRoot);
1389
1397
  const agents = discovery.agents;
1390
- const defaultTimeoutMs = params.timeoutMs ?? ENV_TIMEOUT_MS;
1398
+ const resolvedDefault = options.resolveDefaultTimeoutMs?.(
1399
+ params as Record<string, unknown>,
1400
+ agents,
1401
+ ctx,
1402
+ );
1403
+ const defaultTimeoutMs =
1404
+ params.timeoutMs ?? resolvedDefault ?? ENV_TIMEOUT_MS;
1391
1405
  const effectiveConfirmProjectAgents =
1392
1406
  params.confirmProjectAgents ?? defaultConfirm;
1393
1407
  const harnessAgents = collectHarnessAgents(params);
@@ -1430,6 +1444,7 @@ export function createSubagentsExtension(
1430
1444
  }
1431
1445
 
1432
1446
  options.onSpawnStart?.(harnessAgents.length);
1447
+ let spawnTimedOut = false;
1433
1448
  try {
1434
1449
  const mode = modeInfo(params);
1435
1450
  if (mode.modeCount !== 1 || (params.aggregator && !mode.hasTasks)) {
@@ -1475,15 +1490,25 @@ export function createSubagentsExtension(
1475
1490
  };
1476
1491
  }
1477
1492
 
1478
- if (mode.hasChain) return executeChainMode(execCtx);
1479
- if (mode.hasTasks) return executeParallelMode(execCtx);
1480
- if (mode.hasSingle) return executeSingleMode(execCtx);
1481
-
1482
- const available = agents.map((a) => `${a.name} (${a.source})`).join(", ") || "none";
1483
- return {
1484
- content: [{ type: "text" as const, text: `Invalid parameters. Available agents: ${available}` }],
1485
- details: makeDetails("single")([]),
1486
- };
1493
+ let toolResult: Awaited<
1494
+ ReturnType<typeof executeSingleMode>
1495
+ >;
1496
+ if (mode.hasChain) toolResult = await executeChainMode(execCtx);
1497
+ else if (mode.hasTasks) toolResult = await executeParallelMode(execCtx);
1498
+ else if (mode.hasSingle) toolResult = await executeSingleMode(execCtx);
1499
+ else {
1500
+ const available = agents.map((a) => `${a.name} (${a.source})`).join(", ") || "none";
1501
+ return {
1502
+ content: [{ type: "text" as const, text: `Invalid parameters. Available agents: ${available}` }],
1503
+ details: makeDetails("single")([]),
1504
+ };
1505
+ }
1506
+ const allResults = [
1507
+ ...(toolResult.details?.results ?? []),
1508
+ ...(toolResult.details?.aggregator ? [toolResult.details.aggregator] : []),
1509
+ ];
1510
+ spawnTimedOut = allResults.some((r) => r.timedOut === true);
1511
+ return toolResult;
1487
1512
  } finally {
1488
1513
  options.onSpawnEnd?.(harnessAgents.length);
1489
1514
  const mode = params.chain?.length
@@ -1495,6 +1520,12 @@ export function createSubagentsExtension(
1495
1520
  agents: harnessAgents,
1496
1521
  mode,
1497
1522
  durationMs: Date.now() - startedAt,
1523
+ timedOut: spawnTimedOut,
1524
+ stop_reason: spawnTimedOut
1525
+ ? "timeout"
1526
+ : signal?.aborted
1527
+ ? "aborted"
1528
+ : "complete",
1498
1529
  });
1499
1530
  }
1500
1531
  },