ultimate-pi 0.22.1 → 0.22.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 (42) hide show
  1. package/.pi/extensions/agt-kill-switch.ts +7 -1
  2. package/.pi/extensions/harness-plan-approval.ts +9 -1
  3. package/.pi/extensions/harness-run-context.ts +529 -84
  4. package/.pi/extensions/policy-gate.ts +15 -2
  5. package/.pi/harness/agents.manifest.json +3 -3
  6. package/.pi/harness/agents.policy.yaml +82 -3
  7. package/.pi/harness/specs/plan-task-clarification.schema.json +10 -1
  8. package/.pi/lib/agents-policy.mjs +42 -1
  9. package/.pi/lib/agt/build-evaluation-context.ts +3 -1
  10. package/.pi/lib/agt/kill-switch-state.ts +14 -0
  11. package/.pi/lib/agt/legacy-evaluate.ts +3 -1
  12. package/.pi/lib/ask-user/index.ts +2 -0
  13. package/.pi/lib/ask-user/merge-task-clarification.ts +5 -0
  14. package/.pi/lib/ask-user/policy.ts +23 -0
  15. package/.pi/lib/ask-user/presenters/glimpse.ts +8 -1
  16. package/.pi/lib/ask-user/presenters/headless.ts +15 -0
  17. package/.pi/lib/ask-user/presenters/select.ts +11 -2
  18. package/.pi/lib/ask-user/validate-core.mjs +16 -0
  19. package/.pi/lib/harness-artifact-gate.ts +75 -5
  20. package/.pi/lib/harness-repair-brief.ts +30 -4
  21. package/.pi/lib/harness-run-context.ts +804 -17
  22. package/.pi/lib/harness-schema-validate.ts +147 -38
  23. package/.pi/lib/harness-spawn-policy.ts +9 -0
  24. package/.pi/lib/harness-spawn-topology.ts +109 -7
  25. package/.pi/lib/harness-subagent-precheck.ts +21 -0
  26. package/.pi/lib/harness-subagent-submit-pipeline.ts +95 -21
  27. package/.pi/lib/harness-subagent-submit-register.ts +6 -1
  28. package/.pi/lib/harness-subagents-bridge.ts +3 -0
  29. package/.pi/lib/harness-yaml.ts +11 -3
  30. package/.pi/lib/plan-approval/create-plan.ts +2 -6
  31. package/.pi/lib/plan-debate-gate.ts +87 -0
  32. package/.pi/lib/plan-debate-lane.ts +8 -2
  33. package/.pi/lib/plan-human-gates.ts +322 -0
  34. package/.pi/prompts/harness-clear.md +25 -0
  35. package/.pi/prompts/harness-plan.md +4 -0
  36. package/.pi/scripts/generate-agents-policy-yaml.mjs +73 -7
  37. package/.pi/scripts/harness-reconcile-run-context.mjs +62 -0
  38. package/.pi/scripts/harness-schema-compile-verify.mjs +29 -0
  39. package/.pi/scripts/harness-verify.mjs +27 -0
  40. package/CHANGELOG.md +6 -0
  41. package/README.md +4 -0
  42. package/package.json +1 -1
@@ -7,11 +7,19 @@ import { access, readFile, stat } from "node:fs/promises";
7
7
  import { join } from "node:path";
8
8
  import { parse as parseYaml } from "yaml";
9
9
  import { validateAgainstHarnessSchema } from "./harness-schema-validate.js";
10
+ import { validateTaskClarificationHumanGate } from "./plan-human-gates.js";
10
11
  import {
11
12
  TASK_CLARIFICATION_ARTIFACT,
12
13
  validateTaskClarificationDoc,
13
14
  } from "./plan-task-clarification.js";
14
15
 
16
+ export interface ArtifactGateContext {
17
+ entries?: unknown[];
18
+ quick?: boolean;
19
+ taskSummary?: string;
20
+ lastOutcome?: string | null;
21
+ }
22
+
15
23
  export interface ArtifactGateResult {
16
24
  ok: boolean;
17
25
  errors: string[];
@@ -25,11 +33,50 @@ const ARTIFACT_SCHEMA: Record<string, string> = {
25
33
  "artifacts/stack.yaml": "plan-stack-brief.schema.json",
26
34
  "artifacts/task-clarification.yaml": "plan-task-clarification.schema.json",
27
35
  "artifacts/planning-context.yaml": "plan-planning-context.schema.json",
36
+ "artifacts/execution-plan-draft.yaml":
37
+ "plan-execution-plan-brief.schema.json",
28
38
  "artifacts/eval-verdict.yaml": "eval-verdict.schema.json",
29
39
  "artifacts/adversary-report.yaml": "adversary-report.schema.json",
30
40
  "artifacts/sentrux-repair-plan.yaml": "sentrux-repair-plan.schema.json",
41
+ "artifacts/review-round-consolidated.yaml":
42
+ "plan-review-round-draft.schema.json",
31
43
  };
32
44
 
45
+ /** Round-indexed debate artifacts (submit_* output). */
46
+ const ROUND_ARTIFACT_SCHEMA: Array<{ pattern: RegExp; schemaFile: string }> = [
47
+ {
48
+ pattern: /^artifacts\/hypothesis-validation-r\d+\.yaml$/,
49
+ schemaFile: "plan-hypothesis-eval.schema.json",
50
+ },
51
+ {
52
+ pattern: /^artifacts\/validation-turn-r\d+\.yaml$/,
53
+ schemaFile: "plan-validation-turn.schema.json",
54
+ },
55
+ {
56
+ pattern: /^artifacts\/adversary-brief-r\d+\.yaml$/,
57
+ schemaFile: "plan-adversary-brief.schema.json",
58
+ },
59
+ {
60
+ pattern: /^artifacts\/sprint-audit-r\d+\.yaml$/,
61
+ schemaFile: "plan-sprint-audit-turn.schema.json",
62
+ },
63
+ {
64
+ pattern: /^artifacts\/review-round-r\d+\.yaml$/,
65
+ schemaFile: "plan-review-round-draft.schema.json",
66
+ },
67
+ ];
68
+
69
+ export function resolveArtifactSchemaFile(
70
+ normalizedPath: string,
71
+ ): string | undefined {
72
+ const exact = ARTIFACT_SCHEMA[normalizedPath];
73
+ if (exact) return exact;
74
+ for (const entry of ROUND_ARTIFACT_SCHEMA) {
75
+ if (entry.pattern.test(normalizedPath)) return entry.schemaFile;
76
+ }
77
+ return undefined;
78
+ }
79
+
33
80
  const PREREQUISITE_ORDER: Record<string, string[]> = {
34
81
  "artifacts/planning-context.yaml": [TASK_CLARIFICATION_ARTIFACT],
35
82
  "artifacts/hypothesis.yaml": ["artifacts/decomposition.yaml"],
@@ -41,6 +88,12 @@ const PREREQUISITE_ORDER: Record<string, string[]> = {
41
88
  "artifacts/decomposition.yaml",
42
89
  "artifacts/hypothesis.yaml",
43
90
  ],
91
+ "artifacts/execution-plan-draft.yaml": [
92
+ "artifacts/decomposition.yaml",
93
+ "artifacts/hypothesis.yaml",
94
+ "artifacts/implementation-research.yaml",
95
+ "artifacts/stack.yaml",
96
+ ],
44
97
  };
45
98
 
46
99
  async function fileExists(path: string): Promise<boolean> {
@@ -121,6 +174,7 @@ export async function validateHarnessArtifactFile(
121
174
  runRoot: string,
122
175
  relPath: string,
123
176
  specsDir: string,
177
+ gateCtx?: ArtifactGateContext & { skipPrerequisites?: boolean },
124
178
  ): Promise<ArtifactGateResult> {
125
179
  const normalized = relPath.replace(/\\/g, "/");
126
180
  const abs = join(runRoot, normalized);
@@ -152,7 +206,7 @@ export async function validateHarnessArtifactFile(
152
206
  );
153
207
  }
154
208
 
155
- const schemaFile = ARTIFACT_SCHEMA[normalized];
209
+ const schemaFile = resolveArtifactSchemaFile(normalized);
156
210
  if (doc && schemaFile) {
157
211
  const validation = await validateAgainstHarnessSchema(
158
212
  specsDir,
@@ -171,16 +225,30 @@ export async function validateHarnessArtifactFile(
171
225
  if (!clar.ok) {
172
226
  errors.push(...clar.errors.map((e) => `${normalized}: ${e}`));
173
227
  }
228
+ const human = validateTaskClarificationHumanGate(
229
+ gateCtx?.entries ?? [],
230
+ doc,
231
+ {
232
+ quick: gateCtx?.quick,
233
+ taskSummary: gateCtx?.taskSummary,
234
+ allowFollowUpMessage: gateCtx?.lastOutcome === "needs_clarification",
235
+ },
236
+ );
237
+ if (!human.ok) {
238
+ errors.push(...human.errors.map((e) => `${normalized}: ${e}`));
239
+ }
174
240
  }
175
241
 
176
242
  if (doc) {
177
243
  errors.push(...(await validatePlanningContextArtifact(normalized, doc)));
178
244
  }
179
245
 
180
- const prereqs = PREREQUISITE_ORDER[normalized] ?? [];
181
- errors.push(
182
- ...(await validateArtifactPrerequisites(runRoot, normalized, prereqs)),
183
- );
246
+ if (!gateCtx?.skipPrerequisites) {
247
+ const prereqs = PREREQUISITE_ORDER[normalized] ?? [];
248
+ errors.push(
249
+ ...(await validateArtifactPrerequisites(runRoot, normalized, prereqs)),
250
+ );
251
+ }
184
252
 
185
253
  return { ok: errors.length === 0, errors };
186
254
  }
@@ -189,6 +257,7 @@ export async function validateHarnessArtifactPaths(
189
257
  runRoot: string,
190
258
  paths: string[],
191
259
  specsDir: string,
260
+ gateCtx?: ArtifactGateContext,
192
261
  ): Promise<{
193
262
  ok: boolean;
194
263
  present: string[];
@@ -205,6 +274,7 @@ export async function validateHarnessArtifactPaths(
205
274
  runRoot,
206
275
  normalized,
207
276
  specsDir,
277
+ gateCtx,
208
278
  );
209
279
  if (gate.errors.some((e) => e.startsWith("missing file"))) {
210
280
  missing.push(normalized);
@@ -3,8 +3,12 @@
3
3
  */
4
4
 
5
5
  import { join } from "node:path";
6
- import { harnessRunsRoot } from "./harness-run-context.js";
7
- import { readYamlFile } from "./harness-yaml.js";
6
+ import {
7
+ harnessRunsRoot,
8
+ type RemediationClass,
9
+ remediationClassFromEvalVerdict,
10
+ } from "./harness-run-context.js";
11
+ import { readYamlFile, writeYamlFile } from "./harness-yaml.js";
8
12
 
9
13
  const REPAIR_BRIEF_SCHEMA = "1.0.0";
10
14
 
@@ -72,8 +76,15 @@ export async function synthesizeRepairBrief(
72
76
 
73
77
  const remediation =
74
78
  (typeof review?.remediation_class === "string" &&
75
- review.remediation_class) ||
76
- "implementation_gap";
79
+ (review.remediation_class as RemediationClass)) ||
80
+ remediationClassFromEvalVerdict(
81
+ evalDoc as {
82
+ status?: string;
83
+ recommended_action?: string;
84
+ failed_checks?: string[];
85
+ },
86
+ ) ||
87
+ "inconclusive";
77
88
 
78
89
  const sourceArtifacts = buildSourceArtifacts(input, planRel, {
79
90
  evalDoc,
@@ -132,6 +143,21 @@ export async function synthesizeRepairBrief(
132
143
  return brief;
133
144
  }
134
145
 
146
+ export async function ensureRepairBriefOnDisk(
147
+ input: SynthesizeRepairBriefInput,
148
+ ): Promise<boolean> {
149
+ const runRoot = join(harnessRunsRoot(input.projectRoot), input.runId);
150
+ const rel = "artifacts/repair-brief.yaml";
151
+ try {
152
+ await readYamlFile(join(runRoot, rel), "repair-brief");
153
+ return false;
154
+ } catch {
155
+ const brief = await synthesizeRepairBrief(input);
156
+ await writeYamlFile(join(runRoot, rel), brief);
157
+ return true;
158
+ }
159
+ }
160
+
135
161
  function buildSourceArtifacts(
136
162
  input: SynthesizeRepairBriefInput,
137
163
  planRel: string,