planpong 0.3.0 → 0.5.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.
- package/dist/src/config/defaults.js +1 -0
- package/dist/src/config/defaults.js.map +1 -1
- package/dist/src/config/loader.d.ts +1 -0
- package/dist/src/config/loader.js +3 -0
- package/dist/src/config/loader.js.map +1 -1
- package/dist/src/core/apply-edits.d.ts +40 -0
- package/dist/src/core/apply-edits.js +220 -0
- package/dist/src/core/apply-edits.js.map +1 -0
- package/dist/src/core/convergence.d.ts +57 -4
- package/dist/src/core/convergence.js +134 -6
- package/dist/src/core/convergence.js.map +1 -1
- package/dist/src/core/loop.js +3 -3
- package/dist/src/core/loop.js.map +1 -1
- package/dist/src/core/operations.d.ts +14 -1
- package/dist/src/core/operations.js +592 -56
- package/dist/src/core/operations.js.map +1 -1
- package/dist/src/core/plan-diff.d.ts +23 -0
- package/dist/src/core/plan-diff.js +135 -0
- package/dist/src/core/plan-diff.js.map +1 -0
- package/dist/src/core/session.d.ts +11 -0
- package/dist/src/core/session.js +51 -1
- package/dist/src/core/session.js.map +1 -1
- package/dist/src/mcp/tools/get-feedback.d.ts +16 -0
- package/dist/src/mcp/tools/get-feedback.js +118 -114
- package/dist/src/mcp/tools/get-feedback.js.map +1 -1
- package/dist/src/mcp/tools/revise.d.ts +16 -0
- package/dist/src/mcp/tools/revise.js +76 -61
- package/dist/src/mcp/tools/revise.js.map +1 -1
- package/dist/src/mcp/tools/status.js +15 -1
- package/dist/src/mcp/tools/status.js.map +1 -1
- package/dist/src/prompts/planner.d.ts +34 -1
- package/dist/src/prompts/planner.js +272 -17
- package/dist/src/prompts/planner.js.map +1 -1
- package/dist/src/prompts/reviewer.d.ts +14 -1
- package/dist/src/prompts/reviewer.js +84 -1
- package/dist/src/prompts/reviewer.js.map +1 -1
- package/dist/src/providers/claude.d.ts +3 -0
- package/dist/src/providers/claude.js +151 -13
- package/dist/src/providers/claude.js.map +1 -1
- package/dist/src/providers/codex.d.ts +3 -0
- package/dist/src/providers/codex.js +150 -14
- package/dist/src/providers/codex.js.map +1 -1
- package/dist/src/providers/types.d.ts +69 -3
- package/dist/src/schemas/config.d.ts +3 -0
- package/dist/src/schemas/config.js +6 -0
- package/dist/src/schemas/config.js.map +1 -1
- package/dist/src/schemas/json-schema.d.ts +21 -0
- package/dist/src/schemas/json-schema.js +172 -0
- package/dist/src/schemas/json-schema.js.map +1 -0
- package/dist/src/schemas/metrics.d.ts +171 -0
- package/dist/src/schemas/metrics.js +49 -0
- package/dist/src/schemas/metrics.js.map +1 -0
- package/dist/src/schemas/revision.d.ts +166 -2
- package/dist/src/schemas/revision.js +35 -2
- package/dist/src/schemas/revision.js.map +1 -1
- package/dist/src/schemas/session.d.ts +6 -0
- package/dist/src/schemas/session.js +10 -0
- package/dist/src/schemas/session.js.map +1 -1
- package/package.json +4 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,OAAO,EAAE;QACP,QAAQ,EAAE,QAAQ;KACnB;IACD,QAAQ,EAAE;QACR,QAAQ,EAAE,OAAO;KAClB;IACD,SAAS,EAAE,YAAY;IACvB,UAAU,EAAE,EAAE;IACd,aAAa,EAAE,IAAI;
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../../src/config/defaults.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAmB;IAC5C,OAAO,EAAE;QACP,QAAQ,EAAE,QAAQ;KACnB;IACD,QAAQ,EAAE;QACR,QAAQ,EAAE,OAAO;KAClB;IACD,SAAS,EAAE,YAAY;IACvB,UAAU,EAAE,EAAE;IACd,aAAa,EAAE,IAAI;IACnB,aAAa,EAAE,MAAM;CACtB,CAAC"}
|
|
@@ -68,6 +68,9 @@ export function loadConfig(options) {
|
|
|
68
68
|
? !overrides.autonomous
|
|
69
69
|
: (fileConfig.human_in_loop ??
|
|
70
70
|
DEFAULT_CONFIG.human_in_loop),
|
|
71
|
+
revision_mode: overrides.revisionMode ??
|
|
72
|
+
fileConfig.revision_mode ??
|
|
73
|
+
DEFAULT_CONFIG.revision_mode,
|
|
71
74
|
};
|
|
72
75
|
return PlanpongConfigSchema.parse(merged);
|
|
73
76
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EACL,oBAAoB,GAErB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,MAAM,gBAAgB,GAAG;IACvB,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,eAAe;CAChB,CAAC;AAEF;;;GAGG;AACH,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,GAAG,GAAG,GAAG,CAAC;IACd,MAAM,IAAI,GAAG,GAAG,CAAC;IAEjB,OAAO,IAAI,EAAE,CAAC;QACZ,KAAK,MAAM,QAAQ,IAAI,gBAAgB,EAAE,CAAC;YACxC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACtC,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1B,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;gBAC7C,OAAO,SAAS,CAAC,GAAG,CAA4B,CAAC;YACnD,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC/B,IAAI,MAAM,KAAK,GAAG,IAAI,GAAG,KAAK,IAAI;YAAE,MAAM;QAC1C,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ReplaceEdit } from "../schemas/revision.js";
|
|
2
|
+
export type EditFailureReason = "no-match" | "multi-match" | "section-not-found" | "status-line";
|
|
3
|
+
export interface EditResult {
|
|
4
|
+
edit: ReplaceEdit;
|
|
5
|
+
match_offset: number;
|
|
6
|
+
}
|
|
7
|
+
export interface EditFailure {
|
|
8
|
+
edit: ReplaceEdit;
|
|
9
|
+
reason: EditFailureReason;
|
|
10
|
+
section_searched: string | null;
|
|
11
|
+
diagnostic?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ApplyEditsResult {
|
|
14
|
+
plan: string;
|
|
15
|
+
applied: EditResult[];
|
|
16
|
+
failures: EditFailure[];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Apply a list of section-scoped text-replacement edits to a markdown plan.
|
|
20
|
+
*
|
|
21
|
+
* Edits are processed sequentially against the running plan — later edits
|
|
22
|
+
* see earlier edits' results. Each edit must locate its section heading and
|
|
23
|
+
* its `before` string must appear exactly once within that section's
|
|
24
|
+
* content. Failures are recorded but do NOT abort the run; surviving edits
|
|
25
|
+
* are applied. The caller decides whether to retry the failed edits.
|
|
26
|
+
*
|
|
27
|
+
* Pure: no filesystem access, no logging side-effects. The caller surfaces
|
|
28
|
+
* diagnostics via stderr or telemetry.
|
|
29
|
+
*/
|
|
30
|
+
export declare function applyEdits(plan: string, edits: ReplaceEdit[]): ApplyEditsResult;
|
|
31
|
+
/**
|
|
32
|
+
* Build a stderr-friendly summary of edit application. Used by callers that
|
|
33
|
+
* want a one-line log per round.
|
|
34
|
+
*/
|
|
35
|
+
export declare function summarizeApply(result: ApplyEditsResult): string;
|
|
36
|
+
/**
|
|
37
|
+
* Emit per-failure stderr diagnostics. Caller invokes this once after first-
|
|
38
|
+
* pass and once after retry pass.
|
|
39
|
+
*/
|
|
40
|
+
export declare function logFailures(prefix: string, failures: EditFailure[]): void;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
const STATUS_LINE_RE = /^\*\*planpong:\*\*[^\n]*$/m;
|
|
2
|
+
// Collapse a CRLF-or-LF run of trailing whitespace down to "no trailing
|
|
3
|
+
// whitespace on each line." This makes `before` matches tolerant to the
|
|
4
|
+
// kind of whitespace drift that's common when planners paraphrase
|
|
5
|
+
// surrounding content. We deliberately do NOT normalize internal
|
|
6
|
+
// whitespace — that would silently mis-match meaningful indentation.
|
|
7
|
+
function normalizeTrailingWhitespace(s) {
|
|
8
|
+
return s.replace(/\r\n/g, "\n").replace(/[ \t]+\n/g, "\n");
|
|
9
|
+
}
|
|
10
|
+
function parseSections(plan) {
|
|
11
|
+
const lines = plan.split("\n");
|
|
12
|
+
const boundaries = [];
|
|
13
|
+
let inFence = false;
|
|
14
|
+
// First pass: locate heading lines while tracking fenced code blocks
|
|
15
|
+
// (triple-backtick or triple-tilde). Lines inside fences never count as
|
|
16
|
+
// headings even if they start with `#`.
|
|
17
|
+
const headingLines = [];
|
|
18
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19
|
+
const line = lines[i];
|
|
20
|
+
const fenceMatch = line.match(/^(```|~~~)/);
|
|
21
|
+
if (fenceMatch) {
|
|
22
|
+
inFence = !inFence;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (inFence)
|
|
26
|
+
continue;
|
|
27
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
28
|
+
if (!headingMatch)
|
|
29
|
+
continue;
|
|
30
|
+
headingLines.push({
|
|
31
|
+
index: i,
|
|
32
|
+
level: headingMatch[1].length,
|
|
33
|
+
heading: headingMatch[2].trim(),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
// Convert heading lines to character offsets and resolve section ends:
|
|
37
|
+
// section i ends where the next heading of level <= i.level begins.
|
|
38
|
+
// Pre-compute line start offsets once.
|
|
39
|
+
const lineStarts = [0];
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
lineStarts.push(lineStarts[i] + lines[i].length + 1); // +1 for the \n
|
|
42
|
+
}
|
|
43
|
+
for (let h = 0; h < headingLines.length; h++) {
|
|
44
|
+
const cur = headingLines[h];
|
|
45
|
+
const start = lineStarts[cur.index];
|
|
46
|
+
const contentStart = lineStarts[cur.index + 1] ?? plan.length;
|
|
47
|
+
let end = plan.length;
|
|
48
|
+
for (let n = h + 1; n < headingLines.length; n++) {
|
|
49
|
+
if (headingLines[n].level <= cur.level) {
|
|
50
|
+
end = lineStarts[headingLines[n].index];
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
boundaries.push({
|
|
55
|
+
heading: cur.heading,
|
|
56
|
+
level: cur.level,
|
|
57
|
+
start,
|
|
58
|
+
end,
|
|
59
|
+
contentStart,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return boundaries;
|
|
63
|
+
}
|
|
64
|
+
function findSection(boundaries, label) {
|
|
65
|
+
const target = label.trim();
|
|
66
|
+
const matches = boundaries.filter((b) => b.heading === target);
|
|
67
|
+
if (matches.length === 0)
|
|
68
|
+
return null;
|
|
69
|
+
// First-match-wins for duplicate-labeled headings. The ROUND-3 reviewer
|
|
70
|
+
// flagged this as silent-mis-application risk; the plan as approved keeps
|
|
71
|
+
// first-match + warning. The duplicate count is surfaced so the caller can
|
|
72
|
+
// emit the warning to stderr.
|
|
73
|
+
return { boundary: matches[0], duplicateCount: matches.length };
|
|
74
|
+
}
|
|
75
|
+
function indexOfAllOccurrences(haystack, needle) {
|
|
76
|
+
const offsets = [];
|
|
77
|
+
if (needle.length === 0)
|
|
78
|
+
return offsets;
|
|
79
|
+
let from = 0;
|
|
80
|
+
while (true) {
|
|
81
|
+
const idx = haystack.indexOf(needle, from);
|
|
82
|
+
if (idx === -1)
|
|
83
|
+
return offsets;
|
|
84
|
+
offsets.push(idx);
|
|
85
|
+
from = idx + 1;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function modifiesStatusLine(plan, range) {
|
|
89
|
+
const match = STATUS_LINE_RE.exec(plan);
|
|
90
|
+
if (!match)
|
|
91
|
+
return false;
|
|
92
|
+
const lineStart = match.index;
|
|
93
|
+
const lineEnd = match.index + match[0].length;
|
|
94
|
+
return range.start < lineEnd && range.end > lineStart;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Apply a list of section-scoped text-replacement edits to a markdown plan.
|
|
98
|
+
*
|
|
99
|
+
* Edits are processed sequentially against the running plan — later edits
|
|
100
|
+
* see earlier edits' results. Each edit must locate its section heading and
|
|
101
|
+
* its `before` string must appear exactly once within that section's
|
|
102
|
+
* content. Failures are recorded but do NOT abort the run; surviving edits
|
|
103
|
+
* are applied. The caller decides whether to retry the failed edits.
|
|
104
|
+
*
|
|
105
|
+
* Pure: no filesystem access, no logging side-effects. The caller surfaces
|
|
106
|
+
* diagnostics via stderr or telemetry.
|
|
107
|
+
*/
|
|
108
|
+
export function applyEdits(plan, edits) {
|
|
109
|
+
let working = plan.replace(/\r\n/g, "\n");
|
|
110
|
+
const applied = [];
|
|
111
|
+
const failures = [];
|
|
112
|
+
for (const edit of edits) {
|
|
113
|
+
const boundaries = parseSections(working);
|
|
114
|
+
const sectionLabel = edit.section.trim();
|
|
115
|
+
const sectionHit = findSection(boundaries, sectionLabel);
|
|
116
|
+
if (!sectionHit) {
|
|
117
|
+
failures.push({
|
|
118
|
+
edit,
|
|
119
|
+
reason: "section-not-found",
|
|
120
|
+
section_searched: sectionLabel,
|
|
121
|
+
});
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const { boundary } = sectionHit;
|
|
125
|
+
const sectionContent = working.slice(boundary.contentStart, boundary.end);
|
|
126
|
+
const normalizedSection = normalizeTrailingWhitespace(sectionContent);
|
|
127
|
+
const normalizedBefore = normalizeTrailingWhitespace(edit.before);
|
|
128
|
+
const offsets = indexOfAllOccurrences(normalizedSection, normalizedBefore);
|
|
129
|
+
if (offsets.length === 0) {
|
|
130
|
+
// Plan-wide diagnostic: locate where the unscoped match would have
|
|
131
|
+
// landed, if anywhere. This is INFORMATIONAL — never applied.
|
|
132
|
+
const planWide = indexOfAllOccurrences(normalizeTrailingWhitespace(working), normalizedBefore);
|
|
133
|
+
const diagnostic = planWide.length
|
|
134
|
+
? `would have matched at offset ${planWide[0]} of plan (cross-section)`
|
|
135
|
+
: "no plan-wide match either";
|
|
136
|
+
failures.push({
|
|
137
|
+
edit,
|
|
138
|
+
reason: "no-match",
|
|
139
|
+
section_searched: sectionLabel,
|
|
140
|
+
diagnostic,
|
|
141
|
+
});
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (offsets.length > 1) {
|
|
145
|
+
failures.push({
|
|
146
|
+
edit,
|
|
147
|
+
reason: "multi-match",
|
|
148
|
+
section_searched: sectionLabel,
|
|
149
|
+
diagnostic: `${offsets.length} occurrences within section`,
|
|
150
|
+
});
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
// Unique match. Map normalized offset back to the un-normalized
|
|
154
|
+
// working text. Because normalization only collapses TRAILING
|
|
155
|
+
// whitespace per line, the byte offset within the section is invariant
|
|
156
|
+
// up to the first normalized character — we can locate the match in
|
|
157
|
+
// the un-normalized section by re-scanning with the same `before` and
|
|
158
|
+
// selecting the matching occurrence by index. Edit count is 1, so
|
|
159
|
+
// index 0 of the un-normalized matches.
|
|
160
|
+
const unNormalizedOffsets = indexOfAllOccurrences(sectionContent, edit.before);
|
|
161
|
+
let absoluteStart;
|
|
162
|
+
let matchedLength;
|
|
163
|
+
if (unNormalizedOffsets.length === 1) {
|
|
164
|
+
absoluteStart = boundary.contentStart + unNormalizedOffsets[0];
|
|
165
|
+
matchedLength = edit.before.length;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// Trailing-whitespace differences caused the un-normalized match to
|
|
169
|
+
// shift. Fall back to the normalized offset, treat the original
|
|
170
|
+
// before string as the replacement region length. This is rare —
|
|
171
|
+
// typically when the planner stripped a trailing space the file
|
|
172
|
+
// happens to have. Accept the small risk; the alternative is
|
|
173
|
+
// rejecting the edit and the planner gets a retry anyway.
|
|
174
|
+
absoluteStart = boundary.contentStart + offsets[0];
|
|
175
|
+
// Find the actual matched substring in the original by re-scanning
|
|
176
|
+
// tolerantly. Use the section content's character range that
|
|
177
|
+
// contains the normalized hit.
|
|
178
|
+
const candidate = sectionContent.slice(offsets[0], offsets[0] + edit.before.length + 32);
|
|
179
|
+
const restored = candidate.match(new RegExp(edit.before
|
|
180
|
+
.replace(/\r\n/g, "\n")
|
|
181
|
+
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
182
|
+
.replace(/[ \t]+\n/g, "[ \\t]*\\n")));
|
|
183
|
+
matchedLength = restored ? restored[0].length : edit.before.length;
|
|
184
|
+
}
|
|
185
|
+
const range = { start: absoluteStart, end: absoluteStart + matchedLength };
|
|
186
|
+
if (modifiesStatusLine(working, range)) {
|
|
187
|
+
failures.push({
|
|
188
|
+
edit,
|
|
189
|
+
reason: "status-line",
|
|
190
|
+
section_searched: sectionLabel,
|
|
191
|
+
});
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
working =
|
|
195
|
+
working.slice(0, range.start) + edit.after + working.slice(range.end);
|
|
196
|
+
applied.push({ edit, match_offset: range.start });
|
|
197
|
+
}
|
|
198
|
+
return { plan: working, applied, failures };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Build a stderr-friendly summary of edit application. Used by callers that
|
|
202
|
+
* want a one-line log per round.
|
|
203
|
+
*/
|
|
204
|
+
export function summarizeApply(result) {
|
|
205
|
+
return `applied=${result.applied.length} failed=${result.failures.length}` +
|
|
206
|
+
(result.failures.length
|
|
207
|
+
? ` reasons=${result.failures.map((f) => f.reason).join(",")}`
|
|
208
|
+
: "");
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Emit per-failure stderr diagnostics. Caller invokes this once after first-
|
|
212
|
+
* pass and once after retry pass.
|
|
213
|
+
*/
|
|
214
|
+
export function logFailures(prefix, failures) {
|
|
215
|
+
for (const f of failures) {
|
|
216
|
+
const detail = f.diagnostic ? ` (${f.diagnostic})` : "";
|
|
217
|
+
process.stderr.write(`[planpong] ${prefix}: edit failed (${f.reason}) section="${f.section_searched ?? "?"}"${detail}\n`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=apply-edits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-edits.js","sourceRoot":"","sources":["../../../src/core/apply-edits.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
1
2
|
import { type ReviewFeedback, type PhaseFeedback } from "../schemas/feedback.js";
|
|
2
3
|
import { type PlannerRevision } from "../schemas/revision.js";
|
|
3
4
|
import type { ReviewPhase } from "../prompts/reviewer.js";
|
|
5
|
+
/**
|
|
6
|
+
* Thrown when structured output produces text that is not valid JSON.
|
|
7
|
+
* The state machine treats this as a downgrade-eligible failure.
|
|
8
|
+
*/
|
|
9
|
+
export declare class StructuredOutputParseError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Thrown when structured output produces valid JSON that fails Zod
|
|
14
|
+
* validation (e.g., a refinement violation). The state machine treats
|
|
15
|
+
* this as terminal — the structured output mechanism worked, the model
|
|
16
|
+
* just produced semantically invalid content. Retrying won't help.
|
|
17
|
+
*/
|
|
18
|
+
export declare class ZodValidationError extends Error {
|
|
19
|
+
readonly zodError: ZodError;
|
|
20
|
+
constructor(message: string, zodError: ZodError);
|
|
21
|
+
}
|
|
4
22
|
/**
|
|
5
23
|
* Extract JSON from between sentinel tags. Falls back to finding JSON in
|
|
6
24
|
* code fences, then tries parsing the entire content as JSON.
|
|
@@ -8,10 +26,45 @@ import type { ReviewPhase } from "../prompts/reviewer.js";
|
|
|
8
26
|
export declare function extractJSON(content: string, tag: string): string | null;
|
|
9
27
|
export declare function parseFeedback(content: string): ReviewFeedback;
|
|
10
28
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
29
|
+
* Parse structured-output feedback. The model output is guaranteed to be
|
|
30
|
+
* valid JSON conforming to the JSON Schema we passed to the CLI, so we
|
|
31
|
+
* skip tag/fence extraction and parse directly. Throws:
|
|
32
|
+
* - `StructuredOutputParseError` if JSON.parse fails (downgrade-eligible)
|
|
33
|
+
* - `ZodValidationError` if Zod validation fails (terminal)
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseStructuredFeedbackForPhase(content: string, phase: ReviewPhase): PhaseFeedback;
|
|
36
|
+
/**
|
|
37
|
+
* Parse structured-output revision (planner response). Same contract as
|
|
38
|
+
* `parseStructuredFeedbackForPhase`: throws `StructuredOutputParseError`
|
|
39
|
+
* for JSON failures and `ZodValidationError` for Zod failures.
|
|
40
|
+
*/
|
|
41
|
+
export type RevisionShape = "full" | "edits";
|
|
42
|
+
/**
|
|
43
|
+
* Phase-aware structured-output revision parser.
|
|
44
|
+
*
|
|
45
|
+
* - `shape: "full"` (direction phase or `revision_mode: "full"` config):
|
|
46
|
+
* accepts only `{ responses, updated_plan }`. Edits payloads are rejected.
|
|
47
|
+
* - `shape: "edits"` (risk + detail with `revision_mode: "edits"`): accepts
|
|
48
|
+
* only `{ responses, edits }`. `updated_plan` payloads are rejected.
|
|
49
|
+
*
|
|
50
|
+
* Strict-mode `.strict()` on the Zod schemas already rejects extra fields,
|
|
51
|
+
* so a payload mixing both shapes fails validation. No silent normalization.
|
|
52
|
+
*
|
|
53
|
+
* Throws `StructuredOutputParseError` for JSON failures (downgrade-eligible)
|
|
54
|
+
* and `ZodValidationError` for shape failures (terminal — the model violated
|
|
55
|
+
* the schema).
|
|
56
|
+
*/
|
|
57
|
+
export declare function parseStructuredRevision(content: string, shape?: RevisionShape): PlannerRevision;
|
|
58
|
+
/**
|
|
59
|
+
* Phase-aware feedback parser (LEGACY/DEGRADATION MODE).
|
|
60
|
+
*
|
|
61
|
+
* TODO: deprecate when structured output is stable across all providers.
|
|
62
|
+
*
|
|
63
|
+
* Tries the phase-specific parser first, falls back to base parser, then
|
|
64
|
+
* applies verdict coercion and blocked rationale validation. Used when a
|
|
65
|
+
* provider does not support structured output, or as a fallback when
|
|
66
|
+
* structured output fails.
|
|
14
67
|
*/
|
|
15
68
|
export declare function parseFeedbackForPhase(content: string, phase: ReviewPhase): PhaseFeedback;
|
|
16
|
-
export declare function parseRevision(content: string): PlannerRevision;
|
|
69
|
+
export declare function parseRevision(content: string, shape?: RevisionShape): PlannerRevision;
|
|
17
70
|
export declare function isConverged(feedback: PhaseFeedback): boolean;
|
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
import { ReviewFeedbackSchema, DirectionFeedbackSchema, RiskFeedbackSchema, } from "../schemas/feedback.js";
|
|
2
|
-
import {
|
|
2
|
+
import { DirectionRevisionSchema, EditsRevisionSchema, } from "../schemas/revision.js";
|
|
3
|
+
/**
|
|
4
|
+
* Thrown when structured output produces text that is not valid JSON.
|
|
5
|
+
* The state machine treats this as a downgrade-eligible failure.
|
|
6
|
+
*/
|
|
7
|
+
export class StructuredOutputParseError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "StructuredOutputParseError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when structured output produces valid JSON that fails Zod
|
|
15
|
+
* validation (e.g., a refinement violation). The state machine treats
|
|
16
|
+
* this as terminal — the structured output mechanism worked, the model
|
|
17
|
+
* just produced semantically invalid content. Retrying won't help.
|
|
18
|
+
*/
|
|
19
|
+
export class ZodValidationError extends Error {
|
|
20
|
+
zodError;
|
|
21
|
+
constructor(message, zodError) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "ZodValidationError";
|
|
24
|
+
this.zodError = zodError;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
3
27
|
/**
|
|
4
28
|
* Extract JSON from between sentinel tags. Falls back to finding JSON in
|
|
5
29
|
* code fences, then tries parsing the entire content as JSON.
|
|
@@ -102,9 +126,112 @@ function extractArrayFromRaw(content, field) {
|
|
|
102
126
|
return null;
|
|
103
127
|
}
|
|
104
128
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
129
|
+
* Recursively strip `null` property values from an object. OpenAI-strict
|
|
130
|
+
* structured output requires every optional property to be present as
|
|
131
|
+
* `null`, but our Zod schemas use `.optional()` which expects missing keys
|
|
132
|
+
* (not nulls). This adapter removes nulls so Zod validation succeeds.
|
|
133
|
+
*
|
|
134
|
+
* Only strips top-level and nested object properties that are `null`;
|
|
135
|
+
* array elements and primitive values are preserved.
|
|
136
|
+
*/
|
|
137
|
+
function stripNullProperties(value) {
|
|
138
|
+
if (Array.isArray(value))
|
|
139
|
+
return value.map(stripNullProperties);
|
|
140
|
+
if (value && typeof value === "object") {
|
|
141
|
+
const result = {};
|
|
142
|
+
for (const [key, v] of Object.entries(value)) {
|
|
143
|
+
if (v === null)
|
|
144
|
+
continue;
|
|
145
|
+
result[key] = stripNullProperties(v);
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Parse structured-output feedback. The model output is guaranteed to be
|
|
153
|
+
* valid JSON conforming to the JSON Schema we passed to the CLI, so we
|
|
154
|
+
* skip tag/fence extraction and parse directly. Throws:
|
|
155
|
+
* - `StructuredOutputParseError` if JSON.parse fails (downgrade-eligible)
|
|
156
|
+
* - `ZodValidationError` if Zod validation fails (terminal)
|
|
157
|
+
*/
|
|
158
|
+
export function parseStructuredFeedbackForPhase(content, phase) {
|
|
159
|
+
let parsed;
|
|
160
|
+
try {
|
|
161
|
+
parsed = JSON.parse(content);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
throw new StructuredOutputParseError(`Structured output is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
165
|
+
}
|
|
166
|
+
// OpenAI-strict output includes optional fields as null; Zod expects them missing.
|
|
167
|
+
parsed = stripNullProperties(parsed);
|
|
168
|
+
const schema = phase === "direction"
|
|
169
|
+
? DirectionFeedbackSchema
|
|
170
|
+
: phase === "risk"
|
|
171
|
+
? RiskFeedbackSchema
|
|
172
|
+
: ReviewFeedbackSchema;
|
|
173
|
+
const result = schema.safeParse(parsed);
|
|
174
|
+
if (!result.success) {
|
|
175
|
+
throw new ZodValidationError(`Structured output failed Zod validation for ${phase} phase: ${result.error.message}`, result.error);
|
|
176
|
+
}
|
|
177
|
+
// Apply blocked rationale validation (same rules as legacy path)
|
|
178
|
+
const feedback = result.data;
|
|
179
|
+
if (phase === "direction" && feedback.verdict === "blocked") {
|
|
180
|
+
const direction = feedback;
|
|
181
|
+
if (!direction.approach_assessment?.trim()) {
|
|
182
|
+
console.warn("[planpong] Blocked verdict without approach_assessment rationale — coercing to needs_revision");
|
|
183
|
+
return { ...direction, verdict: "needs_revision" };
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (phase === "risk" && feedback.verdict === "blocked") {
|
|
187
|
+
const risk = feedback;
|
|
188
|
+
if (!risk.risks || risk.risks.length === 0) {
|
|
189
|
+
console.warn("[planpong] Blocked verdict without risks rationale — coercing to needs_revision");
|
|
190
|
+
return { ...risk, verdict: "needs_revision" };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return feedback;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Phase-aware structured-output revision parser.
|
|
197
|
+
*
|
|
198
|
+
* - `shape: "full"` (direction phase or `revision_mode: "full"` config):
|
|
199
|
+
* accepts only `{ responses, updated_plan }`. Edits payloads are rejected.
|
|
200
|
+
* - `shape: "edits"` (risk + detail with `revision_mode: "edits"`): accepts
|
|
201
|
+
* only `{ responses, edits }`. `updated_plan` payloads are rejected.
|
|
202
|
+
*
|
|
203
|
+
* Strict-mode `.strict()` on the Zod schemas already rejects extra fields,
|
|
204
|
+
* so a payload mixing both shapes fails validation. No silent normalization.
|
|
205
|
+
*
|
|
206
|
+
* Throws `StructuredOutputParseError` for JSON failures (downgrade-eligible)
|
|
207
|
+
* and `ZodValidationError` for shape failures (terminal — the model violated
|
|
208
|
+
* the schema).
|
|
209
|
+
*/
|
|
210
|
+
export function parseStructuredRevision(content, shape = "full") {
|
|
211
|
+
let parsed;
|
|
212
|
+
try {
|
|
213
|
+
parsed = JSON.parse(content);
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
throw new StructuredOutputParseError(`Structured output is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
217
|
+
}
|
|
218
|
+
parsed = stripNullProperties(parsed);
|
|
219
|
+
const schema = shape === "edits" ? EditsRevisionSchema : DirectionRevisionSchema;
|
|
220
|
+
const result = schema.safeParse(parsed);
|
|
221
|
+
if (!result.success) {
|
|
222
|
+
throw new ZodValidationError(`Structured output failed Zod validation for ${shape} revision: ${result.error.message}`, result.error);
|
|
223
|
+
}
|
|
224
|
+
return result.data;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Phase-aware feedback parser (LEGACY/DEGRADATION MODE).
|
|
228
|
+
*
|
|
229
|
+
* TODO: deprecate when structured output is stable across all providers.
|
|
230
|
+
*
|
|
231
|
+
* Tries the phase-specific parser first, falls back to base parser, then
|
|
232
|
+
* applies verdict coercion and blocked rationale validation. Used when a
|
|
233
|
+
* provider does not support structured output, or as a fallback when
|
|
234
|
+
* structured output fails.
|
|
108
235
|
*/
|
|
109
236
|
export function parseFeedbackForPhase(content, phase) {
|
|
110
237
|
if (phase === "detail") {
|
|
@@ -196,7 +323,7 @@ export function parseFeedbackForPhase(content, phase) {
|
|
|
196
323
|
missing_phase_fields: missingFields,
|
|
197
324
|
};
|
|
198
325
|
}
|
|
199
|
-
export function parseRevision(content) {
|
|
326
|
+
export function parseRevision(content, shape = "full") {
|
|
200
327
|
const json = extractJSON(content, "planpong-revision");
|
|
201
328
|
if (!json) {
|
|
202
329
|
throw new Error("Could not extract revision JSON from planner output. Expected <planpong-revision> tags, JSON code fence, or raw JSON object.");
|
|
@@ -208,7 +335,8 @@ export function parseRevision(content) {
|
|
|
208
335
|
catch {
|
|
209
336
|
throw new Error(`Invalid JSON in planner output:\n${json.slice(0, 200)}`);
|
|
210
337
|
}
|
|
211
|
-
|
|
338
|
+
const schema = shape === "edits" ? EditsRevisionSchema : DirectionRevisionSchema;
|
|
339
|
+
return schema.parse(parsed);
|
|
212
340
|
}
|
|
213
341
|
export function isConverged(feedback) {
|
|
214
342
|
return feedback.verdict !== "needs_revision";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convergence.js","sourceRoot":"","sources":["../../../src/core/convergence.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"convergence.js","sourceRoot":"","sources":["../../../src/core/convergence.ts"],"names":[],"mappings":"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"}
|
package/dist/src/core/loop.js
CHANGED
|
@@ -34,14 +34,14 @@ export async function runLoop(options) {
|
|
|
34
34
|
model: config.planner.model,
|
|
35
35
|
effort: config.planner.effort,
|
|
36
36
|
});
|
|
37
|
-
if (planResponse.
|
|
38
|
-
throw new Error(`Planner failed (exit ${planResponse.exitCode}):\n${planResponse.
|
|
37
|
+
if (!planResponse.ok) {
|
|
38
|
+
throw new Error(`Planner failed (exit ${planResponse.error.exitCode}):\n${planResponse.error.message}`);
|
|
39
39
|
}
|
|
40
40
|
// Step 3: Write plan to disk
|
|
41
41
|
const filename = resolvePlanSlug(plansDir, planName);
|
|
42
42
|
const planPath = join(plansDir, filename);
|
|
43
43
|
const relativePlanPath = relative(cwd, planPath);
|
|
44
|
-
let planContent = planResponse.
|
|
44
|
+
let planContent = planResponse.output;
|
|
45
45
|
const initialStatusLine = `**planpong:** R0/${config.max_rounds} | ${formatProviderLabel(config.planner)} → ${formatProviderLabel(config.reviewer)} | Awaiting review`;
|
|
46
46
|
planContent = updatePlanStatusLine(planContent, initialStatusLine);
|
|
47
47
|
writeFileSync(planPath, planContent);
|