planpong 0.3.0 → 0.4.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.
- package/dist/src/core/convergence.d.ts +40 -3
- package/dist/src/core/convergence.js +119 -3
- 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.js +92 -45
- package/dist/src/core/operations.js.map +1 -1
- package/dist/src/prompts/planner.d.ts +1 -1
- package/dist/src/prompts/planner.js +39 -19
- package/dist/src/prompts/planner.js.map +1 -1
- package/dist/src/prompts/reviewer.d.ts +1 -1
- package/dist/src/prompts/reviewer.js +19 -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 +134 -12
- package/dist/src/providers/claude.js.map +1 -1
- package/dist/src/providers/codex.d.ts +3 -0
- package/dist/src/providers/codex.js +101 -12
- package/dist/src/providers/codex.js.map +1 -1
- package/dist/src/providers/types.d.ts +49 -3
- package/dist/src/schemas/json-schema.d.ts +9 -0
- package/dist/src/schemas/json-schema.js +153 -0
- package/dist/src/schemas/json-schema.js.map +1 -0
- package/package.json +4 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IssueResponse } from "../schemas/revision.js";
|
|
2
2
|
export type ReviewPhase = "direction" | "risk" | "detail";
|
|
3
3
|
export declare function getReviewPhase(round: number): ReviewPhase;
|
|
4
|
-
export declare function buildReviewPrompt(planContent: string, priorDecisions: string | null, phase?: ReviewPhase): string;
|
|
4
|
+
export declare function buildReviewPrompt(planContent: string, priorDecisions: string | null, phase?: ReviewPhase, structuredOutput?: boolean): string;
|
|
5
5
|
export declare function formatPriorDecisions(rounds: Array<{
|
|
6
6
|
round: number;
|
|
7
7
|
responses: IssueResponse[];
|
|
@@ -180,7 +180,7 @@ If the plan is approved with no issues, use:
|
|
|
180
180
|
{ "verdict": "approved", "summary": "...", "issues": [] }
|
|
181
181
|
\`\`\``;
|
|
182
182
|
}
|
|
183
|
-
export function buildReviewPrompt(planContent, priorDecisions, phase = "detail") {
|
|
183
|
+
export function buildReviewPrompt(planContent, priorDecisions, phase = "detail", structuredOutput = false) {
|
|
184
184
|
const instructions = phase === "direction"
|
|
185
185
|
? buildDirectionReviewInstructions()
|
|
186
186
|
: phase === "risk"
|
|
@@ -191,6 +191,24 @@ export function buildReviewPrompt(planContent, priorDecisions, phase = "detail")
|
|
|
191
191
|
: phase === "risk"
|
|
192
192
|
? buildRiskJsonSchema()
|
|
193
193
|
: buildDetailJsonSchema();
|
|
194
|
+
if (structuredOutput) {
|
|
195
|
+
// Structured-output mode. Some providers (OpenAI/Codex) constrain output
|
|
196
|
+
// at the token level; others (Claude) only validate post-hoc. Emphatic
|
|
197
|
+
// JSON-only instructions help the advisory case comply; the constrained
|
|
198
|
+
// case ignores them harmlessly.
|
|
199
|
+
return `${instructions}
|
|
200
|
+
## Plan to Review
|
|
201
|
+
|
|
202
|
+
${planContent}
|
|
203
|
+
|
|
204
|
+
## Your Task
|
|
205
|
+
|
|
206
|
+
Output ONLY a single JSON object conforming to the schema below. The first character of your response must be \`{\` and the last must be \`}\`. No prose. No markdown. No code fences. No preamble or explanation. No trailing text.
|
|
207
|
+
|
|
208
|
+
Schema:
|
|
209
|
+
|
|
210
|
+
${jsonSchema}`;
|
|
211
|
+
}
|
|
194
212
|
return `${instructions}
|
|
195
213
|
## Plan to Review
|
|
196
214
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reviewer.js","sourceRoot":"","sources":["../../../src/prompts/reviewer.ts"],"names":[],"mappings":"AAIA,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,WAAW,CAAC;IACnC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAC/B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,gCAAgC;IACvC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;oGAyB2F,CAAC;AACrG,CAAC;AAED,SAAS,2BAA2B,CAAC,cAA6B;IAChE,MAAM,UAAU,GAAG,cAAc;QAC/B,CAAC,CAAC,iCAAiC,cAAc,+IAA+I;QAChM,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2BP,UAAU,EAAE,CAAC;AACf,CAAC;AAED,SAAS,6BAA6B,CAAC,cAA6B;IAClE,MAAM,UAAU,GAAG,cAAc;QAC/B,CAAC,CAAC,iCAAiC,cAAc,yLAAyL;QAC1O,CAAC,CAAC,EAAE,CAAC;IAEP,OAAO;;;;;;;;;;;;;;EAcP,UAAU,EAAE,CAAC;AACf,CAAC;AAED,SAAS,wBAAwB;IAC/B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BF,CAAC;AACR,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkCF,CAAC;AACR,CAAC;AAED,SAAS,qBAAqB;IAC5B,OAAO;;;;;;;;;;;;;;;;;;;;OAoBF,CAAC;AACR,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,WAAmB,EACnB,cAA6B,EAC7B,QAAqB,QAAQ;
|
|
1
|
+
{"version":3,"file":"reviewer.js","sourceRoot":"","sources":["../../../src/prompts/reviewer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { Provider, InvokeOptions, ProviderResponse } from "./types.js";
|
|
2
2
|
export declare class ClaudeProvider implements Provider {
|
|
3
3
|
name: string;
|
|
4
|
+
private capabilityCache;
|
|
4
5
|
invoke(prompt: string, options: InvokeOptions): Promise<ProviderResponse>;
|
|
5
6
|
isAvailable(): Promise<boolean>;
|
|
7
|
+
checkStructuredOutputSupport(): Promise<boolean>;
|
|
8
|
+
markNonCapable(): void;
|
|
6
9
|
getModels(): string[];
|
|
7
10
|
getEffortLevels(): string[];
|
|
8
11
|
}
|
|
@@ -13,11 +13,82 @@ function cleanEnv() {
|
|
|
13
13
|
}
|
|
14
14
|
return env;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse claude's `--output-format json` envelope and extract the
|
|
18
|
+
* `structured_output` field as a JSON string ready for downstream parsing.
|
|
19
|
+
* Returns null if the envelope is malformed or the field is missing.
|
|
20
|
+
*
|
|
21
|
+
* Envelope shape (subset):
|
|
22
|
+
* {
|
|
23
|
+
* "type": "result",
|
|
24
|
+
* "is_error": false,
|
|
25
|
+
* "result": "",
|
|
26
|
+
* "structured_output": { ...model's constrained JSON... },
|
|
27
|
+
* ...
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
function extractStructuredOutput(stdout) {
|
|
31
|
+
try {
|
|
32
|
+
const envelope = JSON.parse(stdout);
|
|
33
|
+
if (envelope &&
|
|
34
|
+
typeof envelope === "object" &&
|
|
35
|
+
"structured_output" in envelope &&
|
|
36
|
+
envelope.structured_output !== null &&
|
|
37
|
+
typeof envelope.structured_output === "object") {
|
|
38
|
+
return JSON.stringify(envelope.structured_output);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Not JSON — may indicate a pre-envelope error or auth failure
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Classify a CLI invocation failure as `capability` (downgrade-eligible) or
|
|
48
|
+
* `fatal` (terminal). Capability errors indicate the CLI doesn't support the
|
|
49
|
+
* requested structured output flag; fatal errors are everything else.
|
|
50
|
+
*/
|
|
51
|
+
function classifyError(stderr, exitCode) {
|
|
52
|
+
const lower = stderr.toLowerCase();
|
|
53
|
+
const capabilityIndicators = [
|
|
54
|
+
"unknown flag",
|
|
55
|
+
"unknown option",
|
|
56
|
+
"unrecognized",
|
|
57
|
+
"invalid schema",
|
|
58
|
+
"invalid json schema",
|
|
59
|
+
"json-schema",
|
|
60
|
+
"unsupported",
|
|
61
|
+
];
|
|
62
|
+
const isCapability = capabilityIndicators.some((indicator) => lower.includes(indicator));
|
|
63
|
+
return {
|
|
64
|
+
kind: isCapability ? "capability" : "fatal",
|
|
65
|
+
message: stderr.slice(0, 500) || `claude exited with code ${exitCode}`,
|
|
66
|
+
exitCode,
|
|
67
|
+
stderr,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
16
70
|
export class ClaudeProvider {
|
|
17
71
|
name = "claude";
|
|
72
|
+
capabilityCache = null;
|
|
18
73
|
async invoke(prompt, options) {
|
|
19
|
-
// claude -p reads prompt from stdin when no positional arg is given
|
|
20
|
-
|
|
74
|
+
// claude -p reads prompt from stdin when no positional arg is given.
|
|
75
|
+
// --bare skips hooks/MCP/auto-memory/CLAUDE.md/plugin-sync for faster
|
|
76
|
+
// subprocess startup, but it bypasses OAuth/keychain — only safe to use
|
|
77
|
+
// when ANTHROPIC_API_KEY is set.
|
|
78
|
+
const args = ["-p"];
|
|
79
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
80
|
+
args.push("--bare");
|
|
81
|
+
}
|
|
82
|
+
if (options.jsonSchema) {
|
|
83
|
+
// With a schema, use --output-format json so the response envelope
|
|
84
|
+
// includes a `structured_output` field containing the model's
|
|
85
|
+
// constrained JSON as a native object. --output-format text drops
|
|
86
|
+
// the structured_output field entirely.
|
|
87
|
+
args.push("--output-format", "json", "--json-schema", JSON.stringify(options.jsonSchema));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
args.push("--output-format", "text");
|
|
91
|
+
}
|
|
21
92
|
if (options.model) {
|
|
22
93
|
args.push("--model", options.model);
|
|
23
94
|
}
|
|
@@ -32,22 +103,45 @@ export class ClaudeProvider {
|
|
|
32
103
|
extendEnv: false,
|
|
33
104
|
input: prompt,
|
|
34
105
|
});
|
|
35
|
-
|
|
36
|
-
|
|
106
|
+
const duration = Date.now() - start;
|
|
107
|
+
const exitCode = result.exitCode ?? 1;
|
|
108
|
+
// claude -p can exit non-zero with valid stdout. Treat presence of
|
|
109
|
+
// stdout as success even on non-zero exit.
|
|
110
|
+
if (result.stdout && result.stdout.trim().length > 0) {
|
|
111
|
+
if (options.jsonSchema) {
|
|
112
|
+
// Parse claude's envelope and extract structured_output.
|
|
113
|
+
const extracted = extractStructuredOutput(result.stdout);
|
|
114
|
+
if (extracted === null) {
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
error: {
|
|
118
|
+
kind: "capability",
|
|
119
|
+
message: `claude returned envelope without structured_output field: ${result.stdout.slice(0, 300)}`,
|
|
120
|
+
exitCode,
|
|
121
|
+
stderr: result.stderr,
|
|
122
|
+
},
|
|
123
|
+
duration,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return { ok: true, output: extracted, duration };
|
|
127
|
+
}
|
|
128
|
+
return { ok: true, output: result.stdout, duration };
|
|
37
129
|
}
|
|
130
|
+
// No usable output — classify the failure
|
|
131
|
+
process.stderr.write(`[claude-provider] exit=${exitCode} stderr=${result.stderr?.slice(0, 500)}\n`);
|
|
38
132
|
return {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
duration
|
|
133
|
+
ok: false,
|
|
134
|
+
error: classifyError(result.stderr ?? "", exitCode),
|
|
135
|
+
duration,
|
|
42
136
|
};
|
|
43
137
|
}
|
|
44
138
|
catch (error) {
|
|
139
|
+
const duration = Date.now() - start;
|
|
140
|
+
const message = error instanceof Error ? error.message : "Unknown error invoking claude";
|
|
45
141
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
exitCode: 1,
|
|
50
|
-
duration: Date.now() - start,
|
|
142
|
+
ok: false,
|
|
143
|
+
error: { kind: "fatal", message, exitCode: 1 },
|
|
144
|
+
duration,
|
|
51
145
|
};
|
|
52
146
|
}
|
|
53
147
|
}
|
|
@@ -66,6 +160,34 @@ export class ClaudeProvider {
|
|
|
66
160
|
return false;
|
|
67
161
|
}
|
|
68
162
|
}
|
|
163
|
+
async checkStructuredOutputSupport() {
|
|
164
|
+
if (this.capabilityCache !== null) {
|
|
165
|
+
return this.capabilityCache;
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
const result = await execa("claude", ["--help"], {
|
|
169
|
+
preferLocal: true,
|
|
170
|
+
timeout: 5_000,
|
|
171
|
+
reject: false,
|
|
172
|
+
env: cleanEnv(),
|
|
173
|
+
extendEnv: false,
|
|
174
|
+
});
|
|
175
|
+
const helpText = `${result.stdout ?? ""}\n${result.stderr ?? ""}`;
|
|
176
|
+
const supported = helpText.includes("--json-schema");
|
|
177
|
+
this.capabilityCache = supported;
|
|
178
|
+
if (!supported) {
|
|
179
|
+
process.stderr.write(`[planpong] Structured output not supported by claude — using legacy parsing\n`);
|
|
180
|
+
}
|
|
181
|
+
return supported;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
this.capabilityCache = false;
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
markNonCapable() {
|
|
189
|
+
this.capabilityCache = false;
|
|
190
|
+
}
|
|
69
191
|
getModels() {
|
|
70
192
|
return MODELS;
|
|
71
193
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/providers/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/providers/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { Provider, InvokeOptions, ProviderResponse } from "./types.js";
|
|
2
2
|
export declare class CodexProvider implements Provider {
|
|
3
3
|
name: string;
|
|
4
|
+
private capabilityCache;
|
|
4
5
|
invoke(prompt: string, options: InvokeOptions): Promise<ProviderResponse>;
|
|
5
6
|
isAvailable(): Promise<boolean>;
|
|
7
|
+
checkStructuredOutputSupport(): Promise<boolean>;
|
|
8
|
+
markNonCapable(): void;
|
|
6
9
|
getModels(): string[];
|
|
7
10
|
getEffortLevels(): string[];
|
|
8
11
|
}
|
|
@@ -1,12 +1,40 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { readFileSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { execa } from "execa";
|
|
6
6
|
const MODELS = ["gpt-5.3-codex", "o3-pro", "o3", "o4-mini"];
|
|
7
7
|
const EFFORT_LEVELS = ["low", "medium", "high", "xhigh"];
|
|
8
|
+
/**
|
|
9
|
+
* Classify a CLI invocation failure as `capability` (downgrade-eligible) or
|
|
10
|
+
* `fatal` (terminal). Capability errors indicate the CLI doesn't support the
|
|
11
|
+
* requested structured output flag; fatal errors are everything else.
|
|
12
|
+
*
|
|
13
|
+
* Patterns must be narrow — codex's normal session header includes flag
|
|
14
|
+
* names like "output-schema:" in its info output, so substring matches on
|
|
15
|
+
* the flag name alone produce false positives.
|
|
16
|
+
*/
|
|
17
|
+
function classifyError(stderr, exitCode) {
|
|
18
|
+
const lower = stderr.toLowerCase();
|
|
19
|
+
const capabilityPatterns = [
|
|
20
|
+
/\bunknown (?:flag|option|argument)\b/,
|
|
21
|
+
/\bunrecognized (?:flag|option|argument)\b/,
|
|
22
|
+
/\binvalid_json_schema\b/,
|
|
23
|
+
/\binvalid schema\b/,
|
|
24
|
+
/\bschema is not supported\b/,
|
|
25
|
+
/\bstructured output (?:not|isn't) supported\b/,
|
|
26
|
+
];
|
|
27
|
+
const isCapability = capabilityPatterns.some((pattern) => pattern.test(lower));
|
|
28
|
+
return {
|
|
29
|
+
kind: isCapability ? "capability" : "fatal",
|
|
30
|
+
message: stderr.slice(0, 500) || `codex exited with code ${exitCode}`,
|
|
31
|
+
exitCode,
|
|
32
|
+
stderr,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
8
35
|
export class CodexProvider {
|
|
9
36
|
name = "codex";
|
|
37
|
+
capabilityCache = null;
|
|
10
38
|
async invoke(prompt, options) {
|
|
11
39
|
const args = ["exec"];
|
|
12
40
|
if (options.model) {
|
|
@@ -18,6 +46,19 @@ export class CodexProvider {
|
|
|
18
46
|
// Write clean output to a temp file to avoid parsing header/footer
|
|
19
47
|
const outFile = join(tmpdir(), `planpong-codex-${randomBytes(6).toString("hex")}.txt`);
|
|
20
48
|
args.push("-o", outFile);
|
|
49
|
+
// Optional structured output schema
|
|
50
|
+
let schemaFile = null;
|
|
51
|
+
if (options.jsonSchema) {
|
|
52
|
+
schemaFile = join(tmpdir(), `planpong-codex-schema-${randomBytes(6).toString("hex")}.json`);
|
|
53
|
+
try {
|
|
54
|
+
writeFileSync(schemaFile, JSON.stringify(options.jsonSchema));
|
|
55
|
+
args.push("--output-schema", schemaFile);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
// If we can't write the schema file, fall through without structured output
|
|
59
|
+
schemaFile = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
21
62
|
// Use stdin for prompt (CLI arg has length limits)
|
|
22
63
|
args.push("-");
|
|
23
64
|
const start = Date.now();
|
|
@@ -29,34 +70,56 @@ export class CodexProvider {
|
|
|
29
70
|
reject: false,
|
|
30
71
|
input: prompt,
|
|
31
72
|
});
|
|
32
|
-
|
|
73
|
+
const duration = Date.now() - start;
|
|
74
|
+
const exitCode = result.exitCode ?? 1;
|
|
75
|
+
let content = "";
|
|
33
76
|
try {
|
|
34
77
|
content = readFileSync(outFile, "utf-8");
|
|
35
78
|
}
|
|
36
79
|
catch {
|
|
37
80
|
// Fall back to stdout if output file wasn't created
|
|
38
|
-
content = result.stdout;
|
|
81
|
+
content = result.stdout ?? "";
|
|
39
82
|
}
|
|
40
|
-
// Clean up temp
|
|
83
|
+
// Clean up temp files
|
|
41
84
|
try {
|
|
42
85
|
unlinkSync(outFile);
|
|
43
86
|
}
|
|
44
87
|
catch {
|
|
45
88
|
// ignore
|
|
46
89
|
}
|
|
90
|
+
if (schemaFile) {
|
|
91
|
+
try {
|
|
92
|
+
unlinkSync(schemaFile);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// ignore
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (content && content.trim().length > 0) {
|
|
99
|
+
return { ok: true, output: content, duration };
|
|
100
|
+
}
|
|
47
101
|
return {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
duration
|
|
102
|
+
ok: false,
|
|
103
|
+
error: classifyError(result.stderr ?? "", exitCode),
|
|
104
|
+
duration,
|
|
51
105
|
};
|
|
52
106
|
}
|
|
53
107
|
catch (error) {
|
|
108
|
+
const duration = Date.now() - start;
|
|
109
|
+
// Cleanup on error path
|
|
110
|
+
if (schemaFile) {
|
|
111
|
+
try {
|
|
112
|
+
unlinkSync(schemaFile);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// ignore
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const message = error instanceof Error ? error.message : "Unknown error invoking codex";
|
|
54
119
|
return {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
exitCode: 1,
|
|
59
|
-
duration: Date.now() - start,
|
|
120
|
+
ok: false,
|
|
121
|
+
error: { kind: "fatal", message, exitCode: 1 },
|
|
122
|
+
duration,
|
|
60
123
|
};
|
|
61
124
|
}
|
|
62
125
|
}
|
|
@@ -73,6 +136,32 @@ export class CodexProvider {
|
|
|
73
136
|
return false;
|
|
74
137
|
}
|
|
75
138
|
}
|
|
139
|
+
async checkStructuredOutputSupport() {
|
|
140
|
+
if (this.capabilityCache !== null) {
|
|
141
|
+
return this.capabilityCache;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const result = await execa("codex", ["exec", "--help"], {
|
|
145
|
+
preferLocal: true,
|
|
146
|
+
timeout: 5_000,
|
|
147
|
+
reject: false,
|
|
148
|
+
});
|
|
149
|
+
const helpText = `${result.stdout ?? ""}\n${result.stderr ?? ""}`;
|
|
150
|
+
const supported = helpText.includes("--output-schema");
|
|
151
|
+
this.capabilityCache = supported;
|
|
152
|
+
if (!supported) {
|
|
153
|
+
process.stderr.write(`[planpong] Structured output not supported by codex — using legacy parsing\n`);
|
|
154
|
+
}
|
|
155
|
+
return supported;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
this.capabilityCache = false;
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
markNonCapable() {
|
|
163
|
+
this.capabilityCache = false;
|
|
164
|
+
}
|
|
76
165
|
getModels() {
|
|
77
166
|
return MODELS;
|
|
78
167
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/providers/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/providers/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAQ9B,MAAM,MAAM,GAAG,CAAC,eAAe,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;AAC5D,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAEzD;;;;;;;;GAQG;AACH,SAAS,aAAa,CAAC,MAAc,EAAE,QAAgB;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,kBAAkB,GAAG;QACzB,sCAAsC;QACtC,2CAA2C;QAC3C,yBAAyB;QACzB,oBAAoB;QACpB,6BAA6B;QAC7B,+CAA+C;KAChD,CAAC;IACF,MAAM,YAAY,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CACvD,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CACpB,CAAC;IACF,OAAO;QACL,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO;QAC3C,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,0BAA0B,QAAQ,EAAE;QACrE,QAAQ;QACR,MAAM;KACP,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,aAAa;IACxB,IAAI,GAAG,OAAO,CAAC;IAEP,eAAe,GAAmB,IAAI,CAAC;IAE/C,KAAK,CAAC,MAAM,CACV,MAAc,EACd,OAAsB;QAEtB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;QAEtB,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,2BAA2B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAChE,CAAC;QAED,mEAAmE;QACnE,MAAM,OAAO,GAAG,IAAI,CAClB,MAAM,EAAE,EACR,kBAAkB,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CACvD,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAEzB,oCAAoC;QACpC,IAAI,UAAU,GAAkB,IAAI,CAAC;QACrC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACvB,UAAU,GAAG,IAAI,CACf,MAAM,EAAE,EACR,yBAAyB,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAC/D,CAAC;YACF,IAAI,CAAC;gBACH,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;gBAC9D,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAC;YAC3C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,4EAA4E;gBAC5E,UAAU,GAAG,IAAI,CAAC;YACpB,CAAC;QACH,CAAC;QAED,mDAAmD;QACnD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEf,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;gBACxC,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO;gBACnC,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC;YAEtC,IAAI,OAAO,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC;gBACH,OAAO,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;gBACP,oDAAoD;gBACpD,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;YAChC,CAAC;YAED,sBAAsB;YACtB,IAAI,CAAC;gBACH,UAAU,CAAC,OAAO,CAAC,CAAC;YACtB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,UAAU,CAAC,UAAU,CAAC,CAAC;gBACzB,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;YACH,CAAC;YAED,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;YACjD,CAAC;YAED,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,QAAQ,CAAC;gBACnD,QAAQ;aACT,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YACpC,wBAAwB;YACxB,IAAI,UAAU,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,UAAU,CAAC,UAAU,CAAC,CAAC;gBACzB,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;YACH,CAAC;YACD,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;YAC1E,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE;gBAC9C,QAAQ;aACT,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE;gBACjD,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,KAAK;aACd,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,4BAA4B;QAChC,IAAI,IAAI,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;YAClC,OAAO,IAAI,CAAC,eAAe,CAAC;QAC9B,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;gBACtD,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,KAAK;gBACd,MAAM,EAAE,KAAK;aACd,CAAC,CAAC;YACH,MAAM,QAAQ,GAAG,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,KAAK,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;YAClE,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;YACvD,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;YACjC,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,8EAA8E,CAC/E,CAAC;YACJ,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,cAAc;QACZ,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;IAC/B,CAAC;IAED,SAAS;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,eAAe;QACb,OAAO,aAAa,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -3,16 +3,62 @@ export interface InvokeOptions {
|
|
|
3
3
|
model?: string;
|
|
4
4
|
effort?: string;
|
|
5
5
|
timeout?: number;
|
|
6
|
+
/**
|
|
7
|
+
* JSON Schema to constrain model output. When set, providers pass this to
|
|
8
|
+
* their respective structured-output flags (`--json-schema` for claude,
|
|
9
|
+
* `--output-schema` for codex).
|
|
10
|
+
*/
|
|
11
|
+
jsonSchema?: Record<string, unknown>;
|
|
6
12
|
}
|
|
7
|
-
|
|
8
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Provider invocation error categories. Used by the operations-layer state
|
|
15
|
+
* machine to decide whether to downgrade or fail terminally.
|
|
16
|
+
*
|
|
17
|
+
* - `capability`: schema rejected, flag unrecognized at runtime, structured
|
|
18
|
+
* output format error. Indicates the CLI doesn't support the requested
|
|
19
|
+
* structured output mode. Downgrade-eligible.
|
|
20
|
+
* - `fatal`: auth failure, timeout, network/transport error, non-zero exit
|
|
21
|
+
* with no output. Unrelated to structured output capability. Terminal.
|
|
22
|
+
*/
|
|
23
|
+
export type ProviderErrorKind = "capability" | "fatal";
|
|
24
|
+
export interface ProviderError {
|
|
25
|
+
kind: ProviderErrorKind;
|
|
26
|
+
message: string;
|
|
9
27
|
exitCode: number;
|
|
10
|
-
|
|
28
|
+
stderr?: string;
|
|
11
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Discriminated result of a single provider invocation. Providers are
|
|
32
|
+
* single-shot — they perform one invocation and return either the output
|
|
33
|
+
* or a typed error. They do NOT retry or downgrade internally; that is
|
|
34
|
+
* the operations-layer state machine's job.
|
|
35
|
+
*/
|
|
36
|
+
export type ProviderResponse = {
|
|
37
|
+
ok: true;
|
|
38
|
+
output: string;
|
|
39
|
+
duration: number;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
error: ProviderError;
|
|
43
|
+
duration: number;
|
|
44
|
+
};
|
|
12
45
|
export interface Provider {
|
|
13
46
|
name: string;
|
|
14
47
|
invoke(prompt: string, options: InvokeOptions): Promise<ProviderResponse>;
|
|
15
48
|
isAvailable(): Promise<boolean>;
|
|
16
49
|
getModels(): string[];
|
|
17
50
|
getEffortLevels(): string[];
|
|
51
|
+
/**
|
|
52
|
+
* Probe the underlying CLI to determine whether structured output is
|
|
53
|
+
* supported. Result is cached for the session lifetime. If the probe
|
|
54
|
+
* fails or times out, returns false (use legacy path).
|
|
55
|
+
*/
|
|
56
|
+
checkStructuredOutputSupport(): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Mark this provider as non-capable for the remainder of the session.
|
|
59
|
+
* Called by the state machine after a runtime structured-output failure
|
|
60
|
+
* (capability error or JSON.parse failure) to prevent re-attempting
|
|
61
|
+
* structured output on subsequent rounds.
|
|
62
|
+
*/
|
|
63
|
+
markNonCapable(): void;
|
|
18
64
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReviewPhase } from "../prompts/reviewer.js";
|
|
2
|
+
export declare const DirectionFeedbackJsonSchema: Record<string, unknown>;
|
|
3
|
+
export declare const RiskFeedbackJsonSchema: Record<string, unknown>;
|
|
4
|
+
export declare const ReviewFeedbackJsonSchema: Record<string, unknown>;
|
|
5
|
+
export declare const PlannerRevisionJsonSchema: Record<string, unknown>;
|
|
6
|
+
/**
|
|
7
|
+
* Get the JSON Schema appropriate for a given review phase.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getFeedbackJsonSchemaForPhase(phase: ReviewPhase): Record<string, unknown>;
|