@claudexor/orchestrator 3.0.4 → 3.1.1

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 (83) hide show
  1. package/dist/attemptFinalize.d.ts +200 -0
  2. package/dist/attemptFinalize.d.ts.map +1 -0
  3. package/dist/attemptFinalize.js +412 -0
  4. package/dist/attemptFinalize.js.map +1 -0
  5. package/dist/attemptTelemetry.d.ts +88 -7
  6. package/dist/attemptTelemetry.d.ts.map +1 -1
  7. package/dist/attemptTelemetry.js +276 -14
  8. package/dist/attemptTelemetry.js.map +1 -1
  9. package/dist/budgetFailure.d.ts +70 -0
  10. package/dist/budgetFailure.d.ts.map +1 -0
  11. package/dist/budgetFailure.js +114 -0
  12. package/dist/budgetFailure.js.map +1 -0
  13. package/dist/candidateEvidence.d.ts +55 -1
  14. package/dist/candidateEvidence.d.ts.map +1 -1
  15. package/dist/candidateEvidence.js +72 -0
  16. package/dist/candidateEvidence.js.map +1 -1
  17. package/dist/continuation.d.ts +77 -0
  18. package/dist/continuation.d.ts.map +1 -0
  19. package/dist/continuation.js +92 -0
  20. package/dist/continuation.js.map +1 -0
  21. package/dist/deepScanReducer.d.ts +148 -0
  22. package/dist/deepScanReducer.d.ts.map +1 -0
  23. package/dist/deepScanReducer.js +348 -0
  24. package/dist/deepScanReducer.js.map +1 -0
  25. package/dist/effortGovernance.d.ts +49 -0
  26. package/dist/effortGovernance.d.ts.map +1 -0
  27. package/dist/effortGovernance.js +35 -0
  28. package/dist/effortGovernance.js.map +1 -0
  29. package/dist/harnessFailure.d.ts +27 -0
  30. package/dist/harnessFailure.d.ts.map +1 -0
  31. package/dist/harnessFailure.js +61 -0
  32. package/dist/harnessFailure.js.map +1 -0
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js.map +1 -1
  36. package/dist/orchestrator.d.ts +103 -16
  37. package/dist/orchestrator.d.ts.map +1 -1
  38. package/dist/orchestrator.js +1245 -327
  39. package/dist/orchestrator.js.map +1 -1
  40. package/dist/planQuestions.d.ts.map +1 -1
  41. package/dist/planQuestions.js +105 -50
  42. package/dist/planQuestions.js.map +1 -1
  43. package/dist/planRun.d.ts +15 -7
  44. package/dist/planRun.d.ts.map +1 -1
  45. package/dist/planRun.js +88 -42
  46. package/dist/planRun.js.map +1 -1
  47. package/dist/planTerminal.d.ts +36 -0
  48. package/dist/planTerminal.d.ts.map +1 -0
  49. package/dist/planTerminal.js +63 -0
  50. package/dist/planTerminal.js.map +1 -0
  51. package/dist/reviewerPanel.d.ts +4 -0
  52. package/dist/reviewerPanel.d.ts.map +1 -1
  53. package/dist/reviewerPanel.js +54 -9
  54. package/dist/reviewerPanel.js.map +1 -1
  55. package/dist/revisePrompt.d.ts +17 -0
  56. package/dist/revisePrompt.d.ts.map +1 -0
  57. package/dist/revisePrompt.js +15 -0
  58. package/dist/revisePrompt.js.map +1 -0
  59. package/dist/runSupport.d.ts +67 -2
  60. package/dist/runSupport.d.ts.map +1 -1
  61. package/dist/runSupport.js +86 -6
  62. package/dist/runSupport.js.map +1 -1
  63. package/dist/runTelemetryWriter.d.ts +6 -1
  64. package/dist/runTelemetryWriter.d.ts.map +1 -1
  65. package/dist/runTelemetryWriter.js +2 -0
  66. package/dist/runTelemetryWriter.js.map +1 -1
  67. package/dist/runTerminals.d.ts +15 -4
  68. package/dist/runTerminals.d.ts.map +1 -1
  69. package/dist/runTerminals.js +16 -1
  70. package/dist/runTerminals.js.map +1 -1
  71. package/dist/structuredOutput.d.ts +27 -0
  72. package/dist/structuredOutput.d.ts.map +1 -1
  73. package/dist/structuredOutput.js +65 -7
  74. package/dist/structuredOutput.js.map +1 -1
  75. package/dist/transientClassify.d.ts +59 -0
  76. package/dist/transientClassify.d.ts.map +1 -0
  77. package/dist/transientClassify.js +109 -0
  78. package/dist/transientClassify.js.map +1 -0
  79. package/dist/write-isolation.d.ts +11 -0
  80. package/dist/write-isolation.d.ts.map +1 -0
  81. package/dist/write-isolation.js +13 -0
  82. package/dist/write-isolation.js.map +1 -0
  83. package/package.json +17 -17
@@ -1 +1 @@
1
- {"version":3,"file":"planQuestions.d.ts","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA+BtD;;;;6DAI6D;AAC7D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG;IAClD,KAAK,EAAE,OAAO,GAAG,YAAY,CAAC;IAC9B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B,CAwCA"}
1
+ {"version":3,"file":"planQuestions.d.ts","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAsCtD;;;;6DAI6D;AAC7D,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG;IAClD,KAAK,EAAE,OAAO,GAAG,YAAY,CAAC;IAC9B,SAAS,EAAE,YAAY,EAAE,CAAC;CAC3B,CAwCA"}
@@ -1,12 +1,19 @@
1
1
  /**
2
2
  * Engine-owned parser for the planner's tagged `## Open Questions` block
3
3
  * (ported from the retired spec-interview grounding parser; the plan
4
- * lifecycle is its sole owner now). Parsing is TOLERANT so the loop degrades
5
- * gracefully: an untagged bullet with no `::` becomes a free-text question;
6
- * an untagged bullet WITH 2+ options defaults to single-choice; a tagged
7
- * choice with no options falls back to text; `(none)` bullets are skipped.
8
- * This is plain delimiter parsing of the harness's own structured output (a
9
- * data shape we instructed), not a governance signal (INV-049).
4
+ * lifecycle is its sole owner now). Parsing is bounded to the INSTRUCTED
5
+ * block and degrades gracefully. Once the block contains any recognized
6
+ * `[single]`/`[multi]`/`[text]` bullet it is STRUCTURED: only tagged bullets
7
+ * (and a terminal `(none)`) are questions, and the first nonconforming
8
+ * top-level bullet ends the set (QA-016 an adapter that appends ordinary
9
+ * todo bullets after the tagged block can no longer fabricate owner
10
+ * questions). A block with NO tagged bullet keeps the tolerant legacy
11
+ * behavior: an untagged bullet with no `::` is a free-text question, one WITH
12
+ * 2+ options defaults to single-choice. A tagged choice with no options falls
13
+ * back to text; `(none)` is TERMINAL (so `(none)` followed by todos is `ready`,
14
+ * not `needs_answers`). This is plain delimiter parsing of the harness's own
15
+ * structured output (a data shape we instructed), not a governance signal
16
+ * (INV-049).
10
17
  */
11
18
  const QUESTION_KINDS = new Set(["single", "multi", "text"]);
12
19
  function isMarkdownHeading(line) {
@@ -66,54 +73,102 @@ export function extractPlanQuestions(plan) {
66
73
  // silently ready).
67
74
  return { parse: sawHeading ? "found" : "none_found", questions: best };
68
75
  }
76
+ /** The recognized `[single]`/`[multi]`/`[text]` kind tag on a bullet body, or
77
+ * null when the body carries no recognized tag (the instructed format always
78
+ * tags; an untagged bullet is a deviation). */
79
+ function recognizedTag(body) {
80
+ if (!body.startsWith("["))
81
+ return null;
82
+ const close = body.indexOf("]");
83
+ if (close <= 0)
84
+ return null;
85
+ const tag = body.slice(1, close).trim().toLowerCase();
86
+ return QUESTION_KINDS.has(tag) ? tag : null;
87
+ }
88
+ /** The top-level `- `/`* ` list-item body of a line, or null when the line is
89
+ * not a bullet. */
90
+ function bulletBody(raw) {
91
+ const line = raw.trim();
92
+ if (!line.startsWith("- ") && !line.startsWith("* "))
93
+ return null;
94
+ return line.slice(2).trim();
95
+ }
96
+ /**
97
+ * QA-016: parse the bullets under one `## Open Questions` heading into typed
98
+ * questions, bounded to the INSTRUCTED block. The instructed format tags every
99
+ * bullet (`[single]`/`[multi]`/`[text]`), so once the block contains any tagged
100
+ * bullet it is STRUCTURED: only tagged bullets (and a terminal `(none)`) are
101
+ * questions, and the FIRST nonconforming top-level bullet ends the set — an
102
+ * adapter that appends ordinary todo bullets after the tagged block (Cursor's
103
+ * empty-`planUri` recovery) can no longer fabricate owner questions. A block
104
+ * with NO tagged bullet keeps the tolerant legacy behavior (an untagged bullet
105
+ * with 2+ `::` options is single-choice, else free text). `(none)` is terminal
106
+ * in both modes, so `(none)` followed by todos reads as `ready` (zero
107
+ * questions), never `needs_answers`.
108
+ */
69
109
  function parseQuestionBullets(blockLines) {
110
+ const bodies = blockLines.map(bulletBody).filter((body) => body !== null);
111
+ const structured = bodies.some((body) => recognizedTag(body) !== null);
70
112
  const questions = [];
71
- for (const raw of blockLines) {
72
- const line = raw.trim();
73
- if (!line.startsWith("- ") && !line.startsWith("* "))
74
- continue;
75
- let body = line.slice(2).trim();
113
+ for (const body of bodies) {
114
+ // `(none)` terminates the question set (never "skip and keep scanning").
76
115
  if (isNoneBullet(body))
77
- continue;
78
- let kind = "text";
79
- let kindTagged = false;
80
- if (body.startsWith("[")) {
81
- const close = body.indexOf("]");
82
- if (close > 0) {
83
- const tag = body.slice(1, close).trim().toLowerCase();
84
- if (QUESTION_KINDS.has(tag)) {
85
- kind = tag;
86
- kindTagged = true;
87
- body = body.slice(close + 1).trim();
88
- }
89
- }
90
- }
91
- if (isNoneBullet(body))
92
- continue;
93
- const segments = body
94
- .split("::")
95
- .map((p) => p.trim())
96
- .filter((p) => p.length > 0);
97
- const splitAsChoice = kindTagged ? segments.length > 1 : segments.length >= 3;
98
- const promptText = splitAsChoice ? (segments[0] ?? "") : body;
99
- if (!promptText || isPlaceholder(promptText))
100
- continue;
101
- const options = (splitAsChoice ? segments.slice(1) : [])
102
- .filter((label) => !isPlaceholder(label))
103
- .map((label, i) => ({ id: `o${i + 1}`, label }));
104
- if (!kindTagged)
105
- kind = options.length > 0 ? "single" : "text";
106
- if (kind !== "text" && options.length === 0)
107
- kind = "text";
108
- const isText = kind === "text";
109
- questions.push({
110
- id: `q${questions.length + 1}`,
111
- kind,
112
- prompt: promptText,
113
- options: isText ? [] : options,
114
- allow_text: isText,
115
- });
116
+ break;
117
+ const tag = recognizedTag(body);
118
+ // In a structured block, a nonconforming (untagged) bullet ends the set.
119
+ if (structured && tag === null)
120
+ break;
121
+ const parsed = tag !== null ? parseTaggedBullet(body, tag) : parseTolerantBullet(body);
122
+ if (parsed)
123
+ questions.push({ ...parsed, id: `q${questions.length + 1}` });
116
124
  }
117
125
  return questions;
118
126
  }
127
+ function toQuestion(kind, promptText, options) {
128
+ const resolved = kind !== "text" && options.length === 0 ? "text" : kind;
129
+ const isText = resolved === "text";
130
+ return {
131
+ id: "",
132
+ kind: resolved,
133
+ prompt: promptText,
134
+ options: isText ? [] : options,
135
+ allow_text: isText,
136
+ };
137
+ }
138
+ /** Parse a bullet that carries a recognized `[single]`/`[multi]`/`[text]` tag. */
139
+ function parseTaggedBullet(body, kind) {
140
+ const rest = body.slice(body.indexOf("]") + 1).trim();
141
+ if (isNoneBullet(rest))
142
+ return null;
143
+ const segments = rest
144
+ .split("::")
145
+ .map((p) => p.trim())
146
+ .filter((p) => p.length > 0);
147
+ const splitAsChoice = segments.length > 1;
148
+ const promptText = splitAsChoice ? (segments[0] ?? "") : rest;
149
+ if (!promptText || isPlaceholder(promptText))
150
+ return null;
151
+ const options = (splitAsChoice ? segments.slice(1) : [])
152
+ .filter((label) => !isPlaceholder(label))
153
+ .map((label, i) => ({ id: `o${i + 1}`, label }));
154
+ return toQuestion(kind, promptText, options);
155
+ }
156
+ /** Parse an untagged bullet in a wholly-untagged (legacy) block: a bullet with
157
+ * 2+ `::` options is single-choice, otherwise free text. */
158
+ function parseTolerantBullet(body) {
159
+ if (isNoneBullet(body))
160
+ return null;
161
+ const segments = body
162
+ .split("::")
163
+ .map((p) => p.trim())
164
+ .filter((p) => p.length > 0);
165
+ const splitAsChoice = segments.length >= 3;
166
+ const promptText = splitAsChoice ? (segments[0] ?? "") : body;
167
+ if (!promptText || isPlaceholder(promptText))
168
+ return null;
169
+ const options = (splitAsChoice ? segments.slice(1) : [])
170
+ .filter((label) => !isPlaceholder(label))
171
+ .map((label, i) => ({ id: `o${i + 1}`, label }));
172
+ return toQuestion(options.length > 0 ? "single" : "text", promptText, options);
173
+ }
119
174
  //# sourceMappingURL=planQuestions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"planQuestions.js","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AAEH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAE5D,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IACjC,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACxC,CAAC;AAED;;;;6DAI6D;AAC7D,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAI/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAAE,SAAS;QACpC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;YAAE,SAAS;QAC/E,UAAU,GAAG,IAAI,CAAC;QAClB,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACrC,IAAI,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;gBAAE,MAAM;YACzC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QACD,IACE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE;YACpB,MAAM,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;YAC5B,OAAO,CACL,GAAG,CAAC,QAAQ,CAAC,wBAAwB,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,6BAA6B,CAAC,CACtF,CAAC;QACJ,CAAC,CAAC,EACF,CAAC;YACD,SAAS;QACX,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,GAAmB,EAAE,CAAC;IAC9B,IAAI,SAAS,GAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3C,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;QAClF,MAAM,KAAK,GAAqB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtF,SAAS,GAAG,KAAK,CAAC;YAClB,IAAI,GAAG,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IACD,4EAA4E;IAC5E,0EAA0E;IAC1E,mBAAmB;IACnB,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACzE,CAAC;AAED,SAAS,oBAAoB,CAAC,UAAoB;IAChD,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAC/D,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,YAAY,CAAC,IAAI,CAAC;YAAE,SAAS;QACjC,IAAI,IAAI,GAAyB,MAAM,CAAC;QACxC,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;YAChC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;gBACtD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC5B,IAAI,GAAG,GAA2B,CAAC;oBACnC,UAAU,GAAG,IAAI,CAAC;oBAClB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,YAAY,CAAC,IAAI,CAAC;YAAE,SAAS;QACjC,MAAM,QAAQ,GAAG,IAAI;aAClB,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/B,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,CAAC;QAC9E,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9D,IAAI,CAAC,UAAU,IAAI,aAAa,CAAC,UAAU,CAAC;YAAE,SAAS;QACvD,MAAM,OAAO,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aACrD,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;aACxC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU;YAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/D,IAAI,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,IAAI,GAAG,MAAM,CAAC;QAC3D,MAAM,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC;QAC/B,SAAS,CAAC,IAAI,CAAC;YACb,EAAE,EAAE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9B,IAAI;YACJ,MAAM,EAAE,UAAU;YAClB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO;YAC9B,UAAU,EAAE,MAAM;SACnB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"planQuestions.js","sourceRoot":"","sources":["../src/planQuestions.ts"],"names":[],"mappings":"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"}
package/dist/planRun.d.ts CHANGED
@@ -3,13 +3,14 @@ import { ArtifactStore, type RunPaths } from "@claudexor/artifact-store";
3
3
  import { EventLog } from "@claudexor/event-log";
4
4
  import { BudgetLedger } from "@claudexor/budget";
5
5
  import type { AttemptTelemetry } from "./attemptTelemetry.js";
6
+ import type { AttemptOutcomeClass } from "./attemptFinalize.js";
7
+ import { type BudgetDenial } from "./budgetFailure.js";
6
8
  import type { OrchestratorResult, PlannerAttemptArgs, PlannerAttemptOutcome, RoutedAdapter, RunInput } from "./orchestrator.js";
7
9
  /**
8
10
  * Council plan strategy (INV-031 / D31) + the shared plan-run finalize/failure
9
11
  * tails, extracted from orchestrator.ts so the god-file does not absorb the new
10
- * behavior (complexity ratchet). These are FREE functions that receive the few
11
- * orchestrator methods they need via `PlanRunDeps`; every other collaborator is
12
- * a module-level import, identical to what the orchestrator used inline.
12
+ * behavior (complexity ratchet). FREE functions that receive the few orchestrator
13
+ * methods they need via `PlanRunDeps`; every other collaborator is a module import.
13
14
  */
14
15
  export interface PlanRunDeps {
15
16
  /** One planner spawn (native plan mode, read-only) — the SAME machinery the
@@ -56,10 +57,9 @@ export declare function runCouncilPlan(deps: PlanRunDeps, args: {
56
57
  contextSection: string;
57
58
  laneRun: boolean;
58
59
  }): Promise<OrchestratorResult>;
59
- /** Write final plan artifacts (plan.md, questions.json, work_product,
60
- * summary, telemetry) and the terminal event, then return the result. ONE
61
- * owner for both the solo and council success tails so the artifacts are
62
- * shape-identical (downstream readiness/freeze/implement never branch). */
60
+ /** Write final plan artifacts (plan.md, questions.json, work_product, summary,
61
+ * telemetry) and the terminal event, then return the result. ONE owner for both
62
+ * the solo and council success tails so the artifacts are shape-identical. */
63
63
  export declare function finalizePlanRun(deps: PlanRunDeps, args: {
64
64
  input: RunInput;
65
65
  contract: TaskContract;
@@ -77,6 +77,8 @@ export declare function finalizePlanRun(deps: PlanRunDeps, args: {
77
77
  attemptId: string;
78
78
  harnessId: string;
79
79
  status: "success" | "failed" | "blocked";
80
+ /** D-16 r9: interrupted planners project an interrupted terminal. */
81
+ outcomeClass?: AttemptOutcomeClass;
80
82
  error: string | null;
81
83
  }[];
82
84
  attemptTelemetries: {
@@ -103,6 +105,8 @@ export declare function writePlanHarnessFailure(deps: PlanRunDeps, ctx: {
103
105
  attemptId: string;
104
106
  harnessId: string;
105
107
  status: "success" | "failed" | "blocked";
108
+ /** D-16 r9: interrupted planners project an interrupted terminal. */
109
+ outcomeClass?: AttemptOutcomeClass;
106
110
  error: string | null;
107
111
  }[];
108
112
  attemptTelemetries: {
@@ -110,5 +114,9 @@ export declare function writePlanHarnessFailure(deps: PlanRunDeps, ctx: {
110
114
  harnessId: string;
111
115
  telemetry: AttemptTelemetry;
112
116
  }[];
117
+ /** QA-050: the typed budget denial captured when a planner slot was refused
118
+ * pre-spawn, so plan/council terminals emit a budget failure (typed code +
119
+ * remediation) instead of a harness auth/setup template. */
120
+ budgetDenial?: BudgetDenial | null;
113
121
  }, fallbackMessage: string): OrchestratorResult;
114
122
  //# sourceMappingURL=planRun.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"planRun.d.ts","sourceRoot":"","sources":["../src/planRun.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"planRun.d.ts","sourceRoot":"","sources":["../src/planRun.ts"],"names":[],"mappings":"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"}
package/dist/planRun.js CHANGED
@@ -2,8 +2,9 @@ import { join } from "node:path";
2
2
  import { PlanQuestionsArtifact, derivePlanReadiness, makeOutcomeFacts, } from "@claudexor/schema";
3
3
  import { newId, redactSecrets } from "@claudexor/util";
4
4
  import { cancelledResult, writeFailure } from "./runTerminals.js";
5
+ import { budgetFailureRecord, classifyBudgetFailure } from "./budgetFailure.js";
5
6
  import { extractPlanQuestions } from "./planQuestions.js";
6
- import { resolveReadOnlyRouteContext } from "./routeContext.js";
7
+ import { emitPlanTerminal, resolvePlanTerminalFacts } from "./planTerminal.js";
7
8
  import { buildCouncilProjection, councilDegradationNote, councilDraftRelPath, councilMergePrompt, resolveCouncilWidth, } from "./council.js";
8
9
  /**
9
10
  * Council plan strategy (INV-031 / D31). Round 1: every member drafts a plan
@@ -30,6 +31,9 @@ export async function runCouncilPlan(deps, args) {
30
31
  members: memberAdapters.map((a) => a.adapter.id),
31
32
  });
32
33
  let drafts = [];
34
+ // QA-050: the first council member refused pre-spawn on budget; drives the
35
+ // all-members-failed terminal to a typed budget failure.
36
+ let councilBudgetDenial = null;
33
37
  try {
34
38
  // Round 1 — parallel drafts (each member = one planner attempt).
35
39
  const outcomes = await Promise.all(memberAdapters.map((routed, idx) => deps.runPlannerAttempt({
@@ -60,8 +64,11 @@ export async function runCouncilPlan(deps, args) {
60
64
  attemptId: outcome.attemptId,
61
65
  harnessId: outcome.harnessId,
62
66
  status: outcome.status,
67
+ outcomeClass: outcome.outcomeClass,
63
68
  error: outcome.error,
64
69
  });
70
+ if (outcome.budgetDenied)
71
+ councilBudgetDenial ??= outcome.budgetDenial ?? null;
65
72
  if (outcome.status === "success" && outcome.text) {
66
73
  const rel = councilDraftRelPath(routed.adapter.id);
67
74
  const absPath = join(paths.root, rel);
@@ -78,21 +85,24 @@ export async function runCouncilPlan(deps, args) {
78
85
  }
79
86
  }
80
87
  }
81
- finally {
82
- // Round-1 planners done reclaim the shared read-only route context BEFORE
83
- // the merge (which spawns in the primary's own lane/route home again).
88
+ catch (err) {
89
+ // QA-047 root cause 2: the success path keeps roHome alive so the merge
90
+ // REUSES the admitted context (draft authenticated there) instead of a
91
+ // fresh HOME whose cold native-status probe times out. Leak-safe here.
84
92
  roHome.dispose();
93
+ throw err;
85
94
  }
86
95
  if (input.signal?.aborted) {
96
+ roHome.dispose();
87
97
  return cancelledResult(log, runId, taskId, "plan", paths.root, planAttempts.map((p) => ({
88
98
  attemptId: p.attemptId,
89
99
  harnessId: p.harnessId,
90
100
  status: p.status,
91
101
  })), () => deps.writeRunTelemetry(store, paths, contract, runId, taskId, "plan", attemptTelemetries, null), ledger.spend(), input.signal, store);
92
102
  }
93
- // Degradation is honest: ALL members failed → typed failure (no plan to
94
- // merge). One survivor still merges (normalizes format + extracts questions).
103
+ // ALL members failed → typed failure (no plan to merge); one survivor merges.
95
104
  if (drafts.length === 0) {
105
+ roHome.dispose();
96
106
  return writePlanHarnessFailure(deps, {
97
107
  input,
98
108
  contract,
@@ -104,6 +114,7 @@ export async function runCouncilPlan(deps, args) {
104
114
  ledger,
105
115
  planAttempts,
106
116
  attemptTelemetries,
117
+ budgetDenial: councilBudgetDenial,
107
118
  }, "all council members failed");
108
119
  }
109
120
  // The merger is the primary when it survived round 1, else the first
@@ -112,7 +123,6 @@ export async function runCouncilPlan(deps, args) {
112
123
  const draftedIds = new Set(drafts.map((d) => d.harnessId));
113
124
  const primary = memberAdapters.find((a) => draftedIds.has(a.adapter.id)) ??
114
125
  memberAdapters[0];
115
- const roHome2 = resolveReadOnlyRouteContext(deps.execRootOf(input));
116
126
  let mergeOutcome;
117
127
  try {
118
128
  mergeOutcome = await deps.runPlannerAttempt({
@@ -127,7 +137,9 @@ export async function runCouncilPlan(deps, args) {
127
137
  routed: primary,
128
138
  attemptId: `p${String(memberCount + 1).padStart(2, "0")}`,
129
139
  laneRun: args.laneRun,
130
- fallbackHome: roHome2.env,
140
+ // QA-047 root cause 2: merge in the SAME admitted route context (not a
141
+ // fresh HOME whose cold native-status probe times out as an absent login).
142
+ fallbackHome: roHome.env,
131
143
  // The merge references the draft FILES by absolute path (pointer lines);
132
144
  // full draft text never rides the prompt bubble.
133
145
  promptBody: councilMergePrompt(input.prompt, drafts.map((d) => ({ harnessId: d.harnessId, absPath: d.absPath }))),
@@ -136,7 +148,7 @@ export async function runCouncilPlan(deps, args) {
136
148
  });
137
149
  }
138
150
  finally {
139
- roHome2.dispose();
151
+ roHome.dispose();
140
152
  }
141
153
  if (mergeOutcome.telemetry)
142
154
  attemptTelemetries.push({
@@ -148,16 +160,21 @@ export async function runCouncilPlan(deps, args) {
148
160
  attemptId: mergeOutcome.attemptId,
149
161
  harnessId: mergeOutcome.harnessId,
150
162
  status: mergeOutcome.status,
163
+ outcomeClass: mergeOutcome.outcomeClass,
151
164
  error: mergeOutcome.error,
152
165
  });
153
166
  const mergedBy = mergeOutcome.status === "success" ? primary.adapter.id : null;
167
+ // QA-047 root cause 4: a member card carries its DRAFT error only — the
168
+ // primary owns two attempts under one harness id (draft + merge), so a
169
+ // harness-id-only lookup would misattach the merge failure to a drafted member.
170
+ const mergeAttemptId = mergeOutcome.attemptId;
154
171
  const councilProjection = buildCouncilProjection({
155
172
  requested,
156
173
  members: memberAdapters.map((a) => ({
157
174
  harnessId: a.adapter.id,
158
175
  role: a.adapter.id === primary.adapter.id ? "primary" : "member",
159
176
  drafted: draftedIds.has(a.adapter.id),
160
- error: planAttempts.find((p) => p.harnessId === a.adapter.id && p.error)?.error ?? null,
177
+ error: planAttempts.find((p) => p.harnessId === a.adapter.id && p.attemptId !== mergeAttemptId && p.error)?.error ?? null,
161
178
  })),
162
179
  mergedBy,
163
180
  });
@@ -182,6 +199,7 @@ export async function runCouncilPlan(deps, args) {
182
199
  ledger,
183
200
  planAttempts,
184
201
  attemptTelemetries,
202
+ budgetDenial: mergeOutcome.budgetDenied ? (mergeOutcome.budgetDenial ?? null) : null,
185
203
  }, `council merge failed: ${mergeOutcome.error ?? "the primary produced no unified plan"}`);
186
204
  }
187
205
  return finalizePlanRun(deps, {
@@ -200,31 +218,26 @@ export async function runCouncilPlan(deps, args) {
200
218
  council: councilProjection,
201
219
  });
202
220
  }
203
- /** Write final plan artifacts (plan.md, questions.json, work_product,
204
- * summary, telemetry) and the terminal event, then return the result. ONE
205
- * owner for both the solo and council success tails so the artifacts are
206
- * shape-identical (downstream readiness/freeze/implement never branch). */
221
+ /** Write final plan artifacts (plan.md, questions.json, work_product, summary,
222
+ * telemetry) and the terminal event, then return the result. ONE owner for both
223
+ * the solo and council success tails so the artifacts are shape-identical. */
207
224
  export function finalizePlanRun(deps, args) {
208
225
  const { input, contract, taskId, runId, store, paths, log, ledger, plans, planAttempts, council, } = args;
209
226
  const failedPlanners = planAttempts.filter((p) => p.status !== "success");
210
227
  const winner = plans[0];
211
228
  const winnerHarness = winner?.id ?? "(none)";
212
229
  const winnerAttemptId = args.winnerAttemptId ?? planAttempts.find((p) => p.status === "success")?.attemptId ?? null;
213
- // final/plan.md is the PURE plan body (the winning planner's / merger's own
214
- // text): implement freezes and hashes THIS file, so wrapper prose lives in
215
- // summary.md instead (advisor pass, V6a).
230
+ // final/plan.md is the PURE plan body (implement freezes+hashes it; V6a).
216
231
  const planDoc = redactSecrets(winner?.text ?? "(no output)");
217
232
  store.writeText(join(paths.finalDir, "plan.md"), planDoc + "\n");
218
- // Engine-parsed open questions (final/questions.json): the ONE artifact
219
- // plan readiness derives from. For council this runs on the MERGE output
220
- // only — draft questions never leak into the final set.
233
+ // Engine-parsed open questions (final/questions.json): the ONE artifact plan
234
+ // readiness derives from. For council this runs on the MERGE output only.
221
235
  const parsedQuestions = extractPlanQuestions(planDoc);
222
236
  store.writeJson(join(paths.finalDir, "questions.json"), parsedQuestions);
223
237
  if (council)
224
238
  store.writeYaml(join(paths.root, "council", "membership.yaml"), council);
225
- // A plan is a delivered work product (a report), even with risks — parity
226
- // with the other read-only modes. result_kind=plan tells surfaces NO files
227
- // changed.
239
+ // A plan is a delivered work product (a report); result_kind=plan tells
240
+ // surfaces NO files changed.
228
241
  store.writeYaml(join(paths.finalDir, "work_product.yaml"), {
229
242
  id: newId("wp"),
230
243
  kind: "report",
@@ -233,7 +246,7 @@ export function finalizePlanRun(deps, args) {
233
246
  meta: {
234
247
  mode: "plan",
235
248
  result_kind: "plan",
236
- planners: plans.length,
249
+ planners: council?.members.length ?? plans.length,
237
250
  diffstat: { files: 0, additions: 0, deletions: 0 },
238
251
  blockers: 0,
239
252
  adopted: null,
@@ -241,10 +254,12 @@ export function finalizePlanRun(deps, args) {
241
254
  });
242
255
  const readiness = derivePlanReadiness(PlanQuestionsArtifact.parse(parsedQuestions));
243
256
  const councilNote = council ? councilDegradationNote(council) : "";
257
+ // D-16: fold the WINNING attempt's work_state into the plan terminal (INV-116; see planTerminal.ts).
258
+ const { planFacts, planVetoed, lifecycleLine, summarySuffix } = resolvePlanTerminalFacts(args.attemptTelemetries, winnerAttemptId);
244
259
  store.writeText(join(paths.finalDir, "summary.md"), [
245
260
  `# Run ${runId} (plan)`,
246
261
  "",
247
- `- Lifecycle: succeeded (plan only — no files changed)`,
262
+ lifecycleLine,
248
263
  council
249
264
  ? `- Council: merged by ${council.mergedBy ?? "(none)"} from ${council.drafted} of ${council.requested} member(s)`
250
265
  : `- Planner: ${winnerHarness}`,
@@ -266,8 +281,8 @@ export function finalizePlanRun(deps, args) {
266
281
  question_count: readiness.questionCount,
267
282
  readiness: readiness.state,
268
283
  });
269
- const planFacts = makeOutcomeFacts("succeeded", { noChanges: true });
270
- log.emit("run.completed", { lifecycle: planFacts.lifecycle, facts: planFacts, reason: null });
284
+ // D-16 terminal disclosure keyed on the folded facts (see planTerminal.ts).
285
+ emitPlanTerminal(store, paths, log, planFacts, planVetoed);
271
286
  return {
272
287
  spendUsd: ledger.spend(),
273
288
  runId,
@@ -277,7 +292,7 @@ export function finalizePlanRun(deps, args) {
277
292
  facts: planFacts,
278
293
  winner: null,
279
294
  runDir: paths.root,
280
- summary: `${council ? `Council plan (merged by ${winnerHarness})` : `Plan by ${winnerHarness}`}; ${readiness.questionCount} open question(s)${parsedQuestions.parse === "none_found" ? " (untagged plan — unverified)" : ""}.`,
295
+ summary: `${council ? `Council plan (merged by ${winnerHarness})` : `Plan by ${winnerHarness}`}; ${readiness.questionCount} open question(s)${parsedQuestions.parse === "none_found" ? " (untagged plan — unverified)" : ""}${summarySuffix}.`,
281
296
  candidates: planAttempts.map((p) => ({
282
297
  attemptId: p.attemptId,
283
298
  harnessId: p.harnessId,
@@ -291,23 +306,53 @@ export function finalizePlanRun(deps, args) {
291
306
  export function writePlanHarnessFailure(deps, ctx, fallbackMessage) {
292
307
  const { input, contract, taskId, runId, store, paths, log, ledger, planAttempts } = ctx;
293
308
  const blocked = planAttempts.some((p) => p.status === "blocked");
294
- const message = planAttempts.map((p) => `${p.attemptId}/${p.harnessId}: ${p.error ?? "failed"}`).join("\n") ||
295
- fallbackMessage;
309
+ // QA-050: a budget refusal (pre-spawn denial, or a settled budget terminal)
310
+ // is a BUDGET failure across plan + council, not a harness one.
311
+ const budgetMapping = !blocked && (ctx.budgetDenial || ledger.terminal())
312
+ ? classifyBudgetFailure({ denial: ctx.budgetDenial ?? null, terminal: ledger.terminal() })
313
+ : null;
314
+ // QA-047 root cause 3: a proven-success draft can NEVER read "failed". Only
315
+ // non-success attempts feed failure lines; drafts are preserved evidence.
316
+ const failedLines = planAttempts
317
+ .filter((p) => p.status !== "success")
318
+ .map((p) => `${p.attemptId}/${p.harnessId}: ${p.error ?? "failed"}`);
319
+ const preserved = planAttempts
320
+ .filter((p) => p.status === "success")
321
+ .map((p) => `${p.attemptId}/${p.harnessId}`);
322
+ const message = budgetMapping
323
+ ? budgetMapping.safeMessage
324
+ : `${failedLines.length > 0 ? failedLines.join("\n") : fallbackMessage}${preserved.length > 0 ? `\nPreserved drafts: ${preserved.join(", ")}` : ""}`.trim();
296
325
  deps.writeRunTelemetry(store, paths, contract, runId, taskId, "plan", ctx.attemptTelemetries, null);
297
- store.writeText(join(paths.contextDir, "context_error.md"), `# Harness Error\n\n${message}\n`);
298
- writeFailure(store, paths, {
299
- phase: "harness",
300
- category: blocked ? "policy" : "harness_error",
301
- safeMessage: message,
302
- eventRefs: planAttempts.map((p) => `attempts/${p.attemptId}/events.jsonl`),
303
- runDir: paths.root,
304
- nextActions: ["Open diagnostics", "Check harness authentication", "Retry after setup"],
305
- });
306
- store.writeText(join(paths.finalDir, "summary.md"), `# Run ${runId} (plan)\n\n- Lifecycle: ${blocked ? "succeeded (needs review)" : "failed"}\n\n${message}\n`);
326
+ store.writeText(join(paths.contextDir, "context_error.md"), `# ${budgetMapping ? "Budget Denied" : "Harness Error"}\n\n${message}\n`);
327
+ if (budgetMapping) {
328
+ writeFailure(store, paths, budgetFailureRecord(budgetMapping, {
329
+ eventRefs: planAttempts.map((p) => `attempts/${p.attemptId}/events.jsonl`),
330
+ runDir: paths.root,
331
+ }));
332
+ }
333
+ else {
334
+ writeFailure(store, paths, {
335
+ phase: "harness",
336
+ category: blocked ? "policy" : "harness_error",
337
+ safeMessage: message,
338
+ eventRefs: planAttempts.map((p) => `attempts/${p.attemptId}/events.jsonl`),
339
+ runDir: paths.root,
340
+ nextActions: ["Open diagnostics", "Check harness authentication", "Retry after setup"],
341
+ });
342
+ }
343
+ // D-16 r9: when NO planner blocked/budget-failed and some ran out of
344
+ // context, the terminal is interrupted — not a generic harness failure.
345
+ const anyInterrupted = planAttempts.some((p) => p.outcomeClass === "interrupted");
346
+ store.writeText(join(paths.finalDir, "summary.md"), `# Run ${runId} (plan)\n\n- Lifecycle: ${blocked ? "succeeded (needs review)" : anyInterrupted && !budgetMapping ? "interrupted" : "failed"}\n\n${message}\n`);
307
347
  log.emit("output.ready", { kind: "summary", path: "final/summary.md", state: "diagnostic" });
308
348
  const planFailFacts = blocked
309
349
  ? makeOutcomeFacts("succeeded", { review: "blocked", reason: "review_blocked" })
310
- : makeOutcomeFacts("failed", { reason: "harness_failed" });
350
+ : !budgetMapping && anyInterrupted
351
+ ? makeOutcomeFacts("interrupted", { reason: "context_capacity_exhausted" })
352
+ : makeOutcomeFacts("failed", {
353
+ reason: budgetMapping ? budgetMapping.reason : "harness_failed",
354
+ });
355
+ const failPhase = budgetMapping ? budgetMapping.phase : "harness";
311
356
  if (blocked)
312
357
  log.emit("run.blocked", {
313
358
  lifecycle: planFailFacts.lifecycle,
@@ -321,7 +366,8 @@ export function writePlanHarnessFailure(deps, ctx, fallbackMessage) {
321
366
  lifecycle: planFailFacts.lifecycle,
322
367
  facts: planFailFacts,
323
368
  reason: planFailFacts.reason,
324
- phase: "harness",
369
+ phase: failPhase,
370
+ ...(budgetMapping?.harnessId ? { harness_id: budgetMapping.harnessId } : {}),
325
371
  error: message,
326
372
  failure_ref: "final/failure.yaml",
327
373
  });