aiwcli 0.12.3 → 0.12.7
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/bin/dev.cmd +3 -3
- package/bin/dev.js +16 -16
- package/bin/run.cmd +3 -3
- package/bin/run.js +21 -21
- package/dist/commands/branch.js +7 -2
- package/dist/lib/bmad-installer.js +37 -37
- package/dist/lib/terminal.d.ts +2 -0
- package/dist/lib/terminal.js +57 -7
- package/dist/templates/CLAUDE.md +205 -205
- package/dist/templates/_shared/.claude/commands/handoff-resume.md +12 -64
- package/dist/templates/_shared/.claude/commands/handoff.md +12 -198
- package/dist/templates/_shared/.claude/settings.json +65 -65
- package/dist/templates/_shared/.codex/workflows/handoff.md +226 -226
- package/dist/templates/_shared/.windsurf/workflows/handoff.md +226 -226
- package/dist/templates/_shared/handoff-system/CLAUDE.md +421 -0
- package/dist/templates/_shared/{lib-ts/handoff → handoff-system/lib}/document-generator.ts +215 -216
- package/dist/templates/_shared/{lib-ts/handoff → handoff-system/lib}/handoff-reader.ts +157 -158
- package/dist/templates/_shared/{scripts → handoff-system/scripts}/resume_handoff.ts +373 -373
- package/dist/templates/_shared/{scripts → handoff-system/scripts}/save_handoff.ts +469 -358
- package/dist/templates/_shared/handoff-system/workflows/handoff-resume.md +66 -0
- package/dist/templates/_shared/{workflows → handoff-system/workflows}/handoff.md +254 -254
- package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -2
- package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -159
- package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -147
- package/dist/templates/_shared/hooks-ts/file-suggestion.ts +128 -128
- package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -49
- package/dist/templates/_shared/hooks-ts/session_end.ts +196 -183
- package/dist/templates/_shared/hooks-ts/session_start.ts +163 -151
- package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -48
- package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -74
- package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +93 -93
- package/dist/templates/_shared/lib-ts/CLAUDE.md +367 -367
- package/dist/templates/_shared/lib-ts/base/atomic-write.ts +138 -138
- package/dist/templates/_shared/lib-ts/base/constants.ts +303 -303
- package/dist/templates/_shared/lib-ts/base/git-state.ts +58 -58
- package/dist/templates/_shared/lib-ts/base/hook-utils.ts +582 -582
- package/dist/templates/_shared/lib-ts/base/inference.ts +301 -301
- package/dist/templates/_shared/lib-ts/base/logger.ts +247 -247
- package/dist/templates/_shared/lib-ts/base/state-io.ts +202 -130
- package/dist/templates/_shared/lib-ts/base/stop-words.ts +184 -184
- package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +56 -0
- package/dist/templates/_shared/lib-ts/base/utils.ts +184 -184
- package/dist/templates/_shared/lib-ts/context/context-formatter.ts +566 -560
- package/dist/templates/_shared/lib-ts/context/context-selector.ts +524 -515
- package/dist/templates/_shared/lib-ts/context/context-store.ts +712 -668
- package/dist/templates/_shared/lib-ts/context/plan-manager.ts +312 -312
- package/dist/templates/_shared/lib-ts/context/task-tracker.ts +185 -185
- package/dist/templates/_shared/lib-ts/package.json +20 -20
- package/dist/templates/_shared/lib-ts/templates/formatters.ts +102 -102
- package/dist/templates/_shared/lib-ts/templates/plan-context.ts +58 -58
- package/dist/templates/_shared/lib-ts/tsconfig.json +13 -13
- package/dist/templates/_shared/lib-ts/types.ts +186 -180
- package/dist/templates/_shared/scripts/resolve_context.ts +33 -33
- package/dist/templates/_shared/scripts/status_line.ts +690 -690
- package/dist/templates/cc-native/.claude/commands/{rlm → cc-native/rlm}/ask.md +136 -136
- package/dist/templates/cc-native/.claude/commands/{rlm → cc-native/rlm}/index.md +21 -21
- package/dist/templates/cc-native/.claude/commands/{rlm → cc-native/rlm}/overview.md +56 -56
- package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +10 -10
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/fix.md +8 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/implement.md +8 -8
- package/dist/templates/cc-native/.windsurf/workflows/cc-native/research.md +8 -8
- package/dist/templates/cc-native/CC-NATIVE-README.md +189 -189
- package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +304 -304
- package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +143 -143
- package/dist/templates/cc-native/_cc-native/agents/PLAN-ORCHESTRATOR.md +213 -213
- package/dist/templates/cc-native/_cc-native/agents/plan-questions/PLAN-QUESTIONER.md +70 -70
- package/dist/templates/cc-native/_cc-native/cc-native.config.json +96 -96
- package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +247 -247
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +76 -76
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +54 -54
- package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +51 -51
- package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +53 -53
- package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -61
- package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -163
- package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +156 -156
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/format.ts +597 -597
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/index.ts +26 -26
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/tracker.ts +107 -107
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts/write.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +21 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +319 -319
- package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +144 -144
- package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -57
- package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -83
- package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +119 -119
- package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +79 -79
- package/dist/templates/cc-native/_cc-native/lib-ts/graduation.ts +132 -132
- package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +116 -116
- package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +168 -168
- package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +70 -70
- package/dist/templates/cc-native/_cc-native/lib-ts/output-builder.ts +130 -130
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +80 -80
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +41 -41
- package/dist/templates/cc-native/_cc-native/lib-ts/plan-questions.ts +101 -101
- package/dist/templates/cc-native/_cc-native/lib-ts/review-pipeline.ts +511 -511
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +71 -71
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/base/base-agent.ts +217 -217
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +12 -12
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/claude-agent.ts +66 -65
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/codex-agent.ts +184 -184
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/gemini-agent.ts +39 -39
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/providers/orchestrator-claude-agent.ts +196 -195
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/schemas.ts +201 -201
- package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +21 -21
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/CLAUDE.md +480 -480
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +287 -287
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +148 -148
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +54 -54
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +58 -58
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +208 -208
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +460 -460
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +446 -447
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +280 -280
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +274 -274
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +201 -201
- package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +278 -278
- package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +184 -184
- package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +275 -275
- package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -18
- package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +329 -329
- package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -72
- package/dist/templates/cc-native/_cc-native/workflows/specdev.md +9 -9
- package/oclif.manifest.json +1 -1
- package/package.json +108 -108
- package/dist/templates/cc-native/_cc-native/lib-ts/nul +0 -3
|
@@ -1,65 +1,66 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Claude CLI agent reviewer implementation.
|
|
3
|
-
* Uses claude CLI with --json-schema and --system-prompt flags.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { shellQuoteWin } from "../../../../_shared/lib-ts/base/subprocess-utils.js";
|
|
7
|
-
import { parseCliOutput } from "../../cli-output-parser.js";
|
|
8
|
-
import { coerceToReview } from "../../json-parser.js";
|
|
9
|
-
import type { ReviewerResult } from "../../types.js";
|
|
10
|
-
import { BaseCliAgent } from "../base/base-agent.js";
|
|
11
|
-
import { AGENT_REVIEW_PROMPT_PREFIX } from "../schemas.js";
|
|
12
|
-
import { makeResult } from "../types.js";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Claude CLI-based agent reviewer.
|
|
16
|
-
* Extends BaseCliAgent with Claude-specific prompt and argument handling.
|
|
17
|
-
*/
|
|
18
|
-
export class ClaudeAgent extends BaseCliAgent<ReviewerResult> {
|
|
19
|
-
protected buildCliArgs(): string[] {
|
|
20
|
-
const schemaJson = JSON.stringify(this.schema);
|
|
21
|
-
const cmdArgs = [
|
|
22
|
-
"--model", this.agent.model,
|
|
23
|
-
"--output-format", "json",
|
|
24
|
-
"--json-schema", shellQuoteWin(schemaJson),
|
|
25
|
-
"--max-turns", "3",
|
|
26
|
-
"--setting-sources", process.platform === "win32" ? '""' : "",
|
|
27
|
-
"-p",
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Claude CLI agent reviewer implementation.
|
|
3
|
+
* Uses claude CLI with --json-schema and --system-prompt flags.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { shellQuoteWin } from "../../../../_shared/lib-ts/base/subprocess-utils.js";
|
|
7
|
+
import { parseCliOutput } from "../../cli-output-parser.js";
|
|
8
|
+
import { coerceToReview } from "../../json-parser.js";
|
|
9
|
+
import type { ReviewerResult } from "../../types.js";
|
|
10
|
+
import { BaseCliAgent } from "../base/base-agent.js";
|
|
11
|
+
import { AGENT_REVIEW_PROMPT_PREFIX } from "../schemas.js";
|
|
12
|
+
import { makeResult } from "../types.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Claude CLI-based agent reviewer.
|
|
16
|
+
* Extends BaseCliAgent with Claude-specific prompt and argument handling.
|
|
17
|
+
*/
|
|
18
|
+
export class ClaudeAgent extends BaseCliAgent<ReviewerResult> {
|
|
19
|
+
protected buildCliArgs(): string[] {
|
|
20
|
+
const schemaJson = JSON.stringify(this.schema);
|
|
21
|
+
const cmdArgs = [
|
|
22
|
+
"--model", this.agent.model,
|
|
23
|
+
"--output-format", "json",
|
|
24
|
+
"--json-schema", shellQuoteWin(schemaJson),
|
|
25
|
+
"--max-turns", "3",
|
|
26
|
+
"--setting-sources", process.platform === "win32" ? '""' : "",
|
|
27
|
+
"-p",
|
|
28
|
+
"--no-session-persistence", // Prevent subprocess from creating session records
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
if (this.agent.system_prompt) {
|
|
32
|
+
const fullPrompt = AGENT_REVIEW_PROMPT_PREFIX + "\n\n---\n\n" + this.agent.system_prompt;
|
|
33
|
+
cmdArgs.push("--system-prompt", shellQuoteWin(fullPrompt));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return cmdArgs;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected buildPrompt(plan: string): string {
|
|
40
|
+
return `IMMEDIATELY call StructuredOutput with your review of the plan below.
|
|
41
|
+
Do NOT output any text before calling StructuredOutput.
|
|
42
|
+
|
|
43
|
+
PLAN:
|
|
44
|
+
<<<
|
|
45
|
+
${plan}
|
|
46
|
+
>>>
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
protected coerceResult(obj: Record<string, unknown> | null, raw: string, err: string): ReviewerResult {
|
|
51
|
+
const [ok, verdict, norm] = coerceToReview(obj, this.getDefaultErrorMessage());
|
|
52
|
+
return makeResult(this.agent.name, ok, verdict, norm, raw, err);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected getCliName(): string {
|
|
56
|
+
return "claude";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected makeErrorResult(type: "skip" | "error", message: string): ReviewerResult {
|
|
60
|
+
return makeResult(this.agent.name, false, type, {}, "", message);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
protected parseOutput(raw: string, _result: unknown): Record<string, unknown> | null {
|
|
64
|
+
return parseCliOutput(raw, ["verdict", "summary"]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Codex CLI agent reviewer implementation.
|
|
3
|
-
* Uses codex exec with temp files for schema and output.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import * as fs from "node:fs";
|
|
7
|
-
import * as os from "node:os";
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI agent reviewer implementation.
|
|
3
|
+
* Uses codex exec with temp files for schema and output.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from "node:fs";
|
|
7
|
+
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
|
|
10
|
-
import { logDebug, logWarn } from "../../../../_shared/lib-ts/base/logger.js";
|
|
11
|
-
import { getInternalSubprocessEnv, execFileAsync } from "../../../../_shared/lib-ts/base/subprocess-utils.js";
|
|
12
|
-
import { debugLog, debugRaw } from "../../debug.js";
|
|
13
|
-
import { parseJsonMaybe, coerceToReview } from "../../json-parser.js";
|
|
14
|
-
import type { ReviewerResult } from "../../types.js";
|
|
15
|
-
import { BaseCliAgent, type ExecResult } from "../base/base-agent.js";
|
|
16
|
-
import { AGENT_REVIEW_PROMPT_PREFIX } from "../schemas.js";
|
|
17
|
-
import { makeResult } from "../types.js";
|
|
18
|
-
|
|
19
|
-
/** Temp directory for Codex schema/output files */
|
|
20
|
-
const tmpDir: string | null = null;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Codex CLI-based agent reviewer.
|
|
24
|
-
* Codex has no --system-prompt flag, so we embed schema and persona in stdin.
|
|
25
|
-
* Uses temp files for schema and output.
|
|
26
|
-
*/
|
|
27
|
-
export class CodexAgent extends BaseCliAgent<ReviewerResult> {
|
|
28
|
-
private tempDir: string | null = null;
|
|
29
|
-
|
|
30
|
-
protected buildCliArgs(): string[] {
|
|
31
|
-
// Create temp directory for schema and output files
|
|
32
|
-
this.tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `codex-agent-${this.agent.name}-`));
|
|
33
|
-
|
|
34
|
-
const schemaPath = path.join(this.tempDir, "schema.json");
|
|
35
|
-
const outPath = path.join(this.tempDir, "output.json");
|
|
36
|
-
fs.writeFileSync(schemaPath, JSON.stringify(this.schema, null, 2), "utf-8");
|
|
37
|
-
|
|
38
|
-
const cmdArgs = ["exec", "--sandbox", "read-only"];
|
|
39
|
-
if (this.agent.model) cmdArgs.push("--model", this.agent.model);
|
|
40
|
-
cmdArgs.push("--output-schema", schemaPath, "-o", outPath, "-");
|
|
41
|
-
|
|
42
|
-
return cmdArgs;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
protected buildPrompt(plan: string): string {
|
|
46
|
-
// Codex has no --system-prompt flag, so we prepend the agent persona to stdin.
|
|
47
|
-
return [
|
|
48
|
-
AGENT_REVIEW_PROMPT_PREFIX,
|
|
49
|
-
"---",
|
|
50
|
-
this.agent.system_prompt || "",
|
|
51
|
-
"---",
|
|
52
|
-
`Return ONLY a JSON object matching this schema:\n${JSON.stringify(this.schema)}`,
|
|
53
|
-
"",
|
|
54
|
-
"PLAN:",
|
|
55
|
-
"<<<",
|
|
56
|
-
plan,
|
|
57
|
-
">>>",
|
|
58
|
-
].join("\n\n");
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
protected async cleanup(): Promise<void> {
|
|
62
|
-
if (this.tempDir) {
|
|
63
|
-
try {
|
|
64
|
-
fs.rmSync(this.tempDir, { recursive: true, force: true });
|
|
65
|
-
} catch (error) {
|
|
66
|
-
logDebug(this.agent.name, `Failed to cleanup temp dir ${this.tempDir}: ${error}`);
|
|
67
|
-
}
|
|
68
|
-
this.tempDir = null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
protected coerceResult(obj: Record<string, unknown> | null, raw: string, err: string): ReviewerResult {
|
|
73
|
-
const [ok, verdict, norm] = coerceToReview(obj, this.getDefaultErrorMessage());
|
|
74
|
-
return makeResult(this.agent.name, ok, verdict, norm, raw, err);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
protected extractOutput(result: ExecResult): { raw: string; err: string } {
|
|
78
|
-
const outPath = this.getOutputPath();
|
|
79
|
-
let raw = "";
|
|
80
|
-
const outExists = fs.existsSync(outPath);
|
|
81
|
-
|
|
82
|
-
if (outExists) {
|
|
83
|
-
raw = fs.readFileSync(outPath, "utf-8");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
logDebug(this.agent.name, `Codex output: exit=${result.exitCode}, outFile=${outExists} (${raw.length} chars), stdout=${result.stdout.length} chars`);
|
|
87
|
-
|
|
88
|
-
// Debug logging (override to include out_file_exists)
|
|
89
|
-
if (this.contextPath) {
|
|
90
|
-
debugRaw(this.contextPath, this.sessionName, `agent:${this.agent.name}`, "stdout", raw || result.stdout);
|
|
91
|
-
if (result.stderr) {
|
|
92
|
-
debugRaw(this.contextPath, this.sessionName, `agent:${this.agent.name}`, "stderr", result.stderr);
|
|
93
|
-
}
|
|
94
|
-
debugLog(this.contextPath, this.sessionName, `agent:${this.agent.name}`, "subprocess_info", {
|
|
95
|
-
exit_code: result.exitCode,
|
|
96
|
-
stdout_len: (raw || result.stdout).length,
|
|
97
|
-
stderr_len: result.stderr.length,
|
|
98
|
-
out_file_exists: outExists,
|
|
99
|
-
model: this.agent.model,
|
|
100
|
-
provider: "codex",
|
|
101
|
-
timeout: this.timeout,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
raw: raw || result.stdout,
|
|
107
|
-
err: result.stderr.trim(),
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
protected getCliName(): string {
|
|
112
|
-
return "codex";
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
protected makeErrorResult(type: "skip" | "error", message: string): ReviewerResult {
|
|
116
|
-
return makeResult(this.agent.name, false, type, {}, "", message);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
protected parseOutput(raw: string, result: ExecResult): Record<string, unknown> | null {
|
|
120
|
-
return parseJsonMaybe(raw) ?? parseJsonMaybe(result.stdout);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Override review() to handle temp file creation in try block.
|
|
125
|
-
* Codex writes output to a temp file instead of stdout.
|
|
126
|
-
*/
|
|
127
|
-
async review(plan: string): Promise<ReviewerResult> {
|
|
128
|
-
const cliPath = this.findCli();
|
|
129
|
-
if (!cliPath) {
|
|
130
|
-
return this.makeSkipResult(`${this.getCliName()} CLI not found on PATH`);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
logDebug(this.agent.name, `Found ${this.getCliName()} CLI at: ${cliPath}`);
|
|
134
|
-
|
|
135
|
-
const prompt = this.buildPrompt(plan);
|
|
136
|
-
const args = this.buildCliArgs();
|
|
137
|
-
|
|
138
|
-
logDebug(this.agent.name, `Running ${this.getCliName()} with model: ${this.agent.model}, timeout: ${this.timeout}s`);
|
|
139
|
-
|
|
140
|
-
try {
|
|
141
|
-
const env = getInternalSubprocessEnv();
|
|
142
|
-
const result = await execFileAsync(cliPath, args, {
|
|
143
|
-
input: prompt,
|
|
144
|
-
timeout: this.timeout * 1000,
|
|
145
|
-
env: env as Record<string, string>,
|
|
146
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
147
|
-
shell: process.platform === "win32",
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
if (result.killed || result.signal === "SIGTERM") {
|
|
151
|
-
return this.handleTimeout();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Extract from temp file if exists, fallback to stdout
|
|
155
|
-
const { raw, err } = this.extractOutput(result);
|
|
156
|
-
|
|
157
|
-
// Log exit code and stderr tail for ALL non-zero exits
|
|
158
|
-
if (result.exitCode !== 0) {
|
|
159
|
-
const stderrTail = err.slice(-500);
|
|
160
|
-
logWarn(this.agent.name, `Codex exited with code ${result.exitCode}, stderr_len=${err.length}, stderr_tail: ${stderrTail}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (!raw && !err && !this.outputFileExists() && result.exitCode !== 0) {
|
|
164
|
-
return this.handleExitError(result);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
this.logSubprocessResult(result, raw, err);
|
|
168
|
-
|
|
169
|
-
const obj = this.parseOutput(raw, result);
|
|
170
|
-
this.logParsedResult(obj);
|
|
171
|
-
|
|
172
|
-
return this.coerceResult(obj, raw, err);
|
|
173
|
-
} finally {
|
|
174
|
-
await this.cleanup();
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
private getOutputPath(): string {
|
|
179
|
-
return path.join(this.tempDir!, "output.json");
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
private outputFileExists(): boolean {
|
|
183
|
-
return this.tempDir ? fs.existsSync(this.getOutputPath()) : false;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
9
|
+
|
|
10
|
+
import { logDebug, logWarn } from "../../../../_shared/lib-ts/base/logger.js";
|
|
11
|
+
import { getInternalSubprocessEnv, execFileAsync } from "../../../../_shared/lib-ts/base/subprocess-utils.js";
|
|
12
|
+
import { debugLog, debugRaw } from "../../debug.js";
|
|
13
|
+
import { parseJsonMaybe, coerceToReview } from "../../json-parser.js";
|
|
14
|
+
import type { ReviewerResult } from "../../types.js";
|
|
15
|
+
import { BaseCliAgent, type ExecResult } from "../base/base-agent.js";
|
|
16
|
+
import { AGENT_REVIEW_PROMPT_PREFIX } from "../schemas.js";
|
|
17
|
+
import { makeResult } from "../types.js";
|
|
18
|
+
|
|
19
|
+
/** Temp directory for Codex schema/output files */
|
|
20
|
+
const tmpDir: string | null = null;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Codex CLI-based agent reviewer.
|
|
24
|
+
* Codex has no --system-prompt flag, so we embed schema and persona in stdin.
|
|
25
|
+
* Uses temp files for schema and output.
|
|
26
|
+
*/
|
|
27
|
+
export class CodexAgent extends BaseCliAgent<ReviewerResult> {
|
|
28
|
+
private tempDir: string | null = null;
|
|
29
|
+
|
|
30
|
+
protected buildCliArgs(): string[] {
|
|
31
|
+
// Create temp directory for schema and output files
|
|
32
|
+
this.tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `codex-agent-${this.agent.name}-`));
|
|
33
|
+
|
|
34
|
+
const schemaPath = path.join(this.tempDir, "schema.json");
|
|
35
|
+
const outPath = path.join(this.tempDir, "output.json");
|
|
36
|
+
fs.writeFileSync(schemaPath, JSON.stringify(this.schema, null, 2), "utf-8");
|
|
37
|
+
|
|
38
|
+
const cmdArgs = ["exec", "--sandbox", "read-only"];
|
|
39
|
+
if (this.agent.model) cmdArgs.push("--model", this.agent.model);
|
|
40
|
+
cmdArgs.push("--output-schema", schemaPath, "-o", outPath, "-");
|
|
41
|
+
|
|
42
|
+
return cmdArgs;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected buildPrompt(plan: string): string {
|
|
46
|
+
// Codex has no --system-prompt flag, so we prepend the agent persona to stdin.
|
|
47
|
+
return [
|
|
48
|
+
AGENT_REVIEW_PROMPT_PREFIX,
|
|
49
|
+
"---",
|
|
50
|
+
this.agent.system_prompt || "",
|
|
51
|
+
"---",
|
|
52
|
+
`Return ONLY a JSON object matching this schema:\n${JSON.stringify(this.schema)}`,
|
|
53
|
+
"",
|
|
54
|
+
"PLAN:",
|
|
55
|
+
"<<<",
|
|
56
|
+
plan,
|
|
57
|
+
">>>",
|
|
58
|
+
].join("\n\n");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected async cleanup(): Promise<void> {
|
|
62
|
+
if (this.tempDir) {
|
|
63
|
+
try {
|
|
64
|
+
fs.rmSync(this.tempDir, { recursive: true, force: true });
|
|
65
|
+
} catch (error) {
|
|
66
|
+
logDebug(this.agent.name, `Failed to cleanup temp dir ${this.tempDir}: ${error}`);
|
|
67
|
+
}
|
|
68
|
+
this.tempDir = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected coerceResult(obj: Record<string, unknown> | null, raw: string, err: string): ReviewerResult {
|
|
73
|
+
const [ok, verdict, norm] = coerceToReview(obj, this.getDefaultErrorMessage());
|
|
74
|
+
return makeResult(this.agent.name, ok, verdict, norm, raw, err);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected extractOutput(result: ExecResult): { raw: string; err: string } {
|
|
78
|
+
const outPath = this.getOutputPath();
|
|
79
|
+
let raw = "";
|
|
80
|
+
const outExists = fs.existsSync(outPath);
|
|
81
|
+
|
|
82
|
+
if (outExists) {
|
|
83
|
+
raw = fs.readFileSync(outPath, "utf-8");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
logDebug(this.agent.name, `Codex output: exit=${result.exitCode}, outFile=${outExists} (${raw.length} chars), stdout=${result.stdout.length} chars`);
|
|
87
|
+
|
|
88
|
+
// Debug logging (override to include out_file_exists)
|
|
89
|
+
if (this.contextPath) {
|
|
90
|
+
debugRaw(this.contextPath, this.sessionName, `agent:${this.agent.name}`, "stdout", raw || result.stdout);
|
|
91
|
+
if (result.stderr) {
|
|
92
|
+
debugRaw(this.contextPath, this.sessionName, `agent:${this.agent.name}`, "stderr", result.stderr);
|
|
93
|
+
}
|
|
94
|
+
debugLog(this.contextPath, this.sessionName, `agent:${this.agent.name}`, "subprocess_info", {
|
|
95
|
+
exit_code: result.exitCode,
|
|
96
|
+
stdout_len: (raw || result.stdout).length,
|
|
97
|
+
stderr_len: result.stderr.length,
|
|
98
|
+
out_file_exists: outExists,
|
|
99
|
+
model: this.agent.model,
|
|
100
|
+
provider: "codex",
|
|
101
|
+
timeout: this.timeout,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
raw: raw || result.stdout,
|
|
107
|
+
err: result.stderr.trim(),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
protected getCliName(): string {
|
|
112
|
+
return "codex";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
protected makeErrorResult(type: "skip" | "error", message: string): ReviewerResult {
|
|
116
|
+
return makeResult(this.agent.name, false, type, {}, "", message);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
protected parseOutput(raw: string, result: ExecResult): Record<string, unknown> | null {
|
|
120
|
+
return parseJsonMaybe(raw) ?? parseJsonMaybe(result.stdout);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Override review() to handle temp file creation in try block.
|
|
125
|
+
* Codex writes output to a temp file instead of stdout.
|
|
126
|
+
*/
|
|
127
|
+
async review(plan: string): Promise<ReviewerResult> {
|
|
128
|
+
const cliPath = this.findCli();
|
|
129
|
+
if (!cliPath) {
|
|
130
|
+
return this.makeSkipResult(`${this.getCliName()} CLI not found on PATH`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
logDebug(this.agent.name, `Found ${this.getCliName()} CLI at: ${cliPath}`);
|
|
134
|
+
|
|
135
|
+
const prompt = this.buildPrompt(plan);
|
|
136
|
+
const args = this.buildCliArgs();
|
|
137
|
+
|
|
138
|
+
logDebug(this.agent.name, `Running ${this.getCliName()} with model: ${this.agent.model}, timeout: ${this.timeout}s`);
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const env = getInternalSubprocessEnv();
|
|
142
|
+
const result = await execFileAsync(cliPath, args, {
|
|
143
|
+
input: prompt,
|
|
144
|
+
timeout: this.timeout * 1000,
|
|
145
|
+
env: env as Record<string, string>,
|
|
146
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
147
|
+
shell: process.platform === "win32",
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
if (result.killed || result.signal === "SIGTERM") {
|
|
151
|
+
return this.handleTimeout();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Extract from temp file if exists, fallback to stdout
|
|
155
|
+
const { raw, err } = this.extractOutput(result);
|
|
156
|
+
|
|
157
|
+
// Log exit code and stderr tail for ALL non-zero exits
|
|
158
|
+
if (result.exitCode !== 0) {
|
|
159
|
+
const stderrTail = err.slice(-500);
|
|
160
|
+
logWarn(this.agent.name, `Codex exited with code ${result.exitCode}, stderr_len=${err.length}, stderr_tail: ${stderrTail}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!raw && !err && !this.outputFileExists() && result.exitCode !== 0) {
|
|
164
|
+
return this.handleExitError(result);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.logSubprocessResult(result, raw, err);
|
|
168
|
+
|
|
169
|
+
const obj = this.parseOutput(raw, result);
|
|
170
|
+
this.logParsedResult(obj);
|
|
171
|
+
|
|
172
|
+
return this.coerceResult(obj, raw, err);
|
|
173
|
+
} finally {
|
|
174
|
+
await this.cleanup();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private getOutputPath(): string {
|
|
179
|
+
return path.join(this.tempDir!, "output.json");
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private outputFileExists(): boolean {
|
|
183
|
+
return this.tempDir ? fs.existsSync(this.getOutputPath()) : false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Gemini CLI agent reviewer implementation (stub).
|
|
3
|
-
* Placeholder for future implementation.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ReviewerResult } from "../../types.js";
|
|
7
|
-
import { BaseCliAgent } from "../base/base-agent.js";
|
|
8
|
-
import { makeResult } from "../types.js";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Gemini CLI-based agent reviewer (NOT IMPLEMENTED).
|
|
12
|
-
* All methods throw "not implemented" errors.
|
|
13
|
-
* This is a placeholder for future development.
|
|
14
|
-
*/
|
|
15
|
-
export class GeminiAgent extends BaseCliAgent<ReviewerResult> {
|
|
16
|
-
protected buildCliArgs(): string[] {
|
|
17
|
-
throw new Error("GeminiAgent not implemented");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
protected buildPrompt(_plan: string): string {
|
|
21
|
-
throw new Error("GeminiAgent not implemented");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
protected coerceResult(_obj: Record<string, unknown> | null, _raw: string, _err: string): ReviewerResult {
|
|
25
|
-
throw new Error("GeminiAgent not implemented");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
protected getCliName(): string {
|
|
29
|
-
throw new Error("GeminiAgent not implemented");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
protected makeErrorResult(type: "skip" | "error", message: string): ReviewerResult {
|
|
33
|
-
return makeResult(this.agent.name, false, type, {}, "", message);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
protected parseOutput(_raw: string, _result: unknown): Record<string, unknown> | null {
|
|
37
|
-
throw new Error("GeminiAgent not implemented");
|
|
38
|
-
}
|
|
39
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Gemini CLI agent reviewer implementation (stub).
|
|
3
|
+
* Placeholder for future implementation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ReviewerResult } from "../../types.js";
|
|
7
|
+
import { BaseCliAgent } from "../base/base-agent.js";
|
|
8
|
+
import { makeResult } from "../types.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Gemini CLI-based agent reviewer (NOT IMPLEMENTED).
|
|
12
|
+
* All methods throw "not implemented" errors.
|
|
13
|
+
* This is a placeholder for future development.
|
|
14
|
+
*/
|
|
15
|
+
export class GeminiAgent extends BaseCliAgent<ReviewerResult> {
|
|
16
|
+
protected buildCliArgs(): string[] {
|
|
17
|
+
throw new Error("GeminiAgent not implemented");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected buildPrompt(_plan: string): string {
|
|
21
|
+
throw new Error("GeminiAgent not implemented");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected coerceResult(_obj: Record<string, unknown> | null, _raw: string, _err: string): ReviewerResult {
|
|
25
|
+
throw new Error("GeminiAgent not implemented");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
protected getCliName(): string {
|
|
29
|
+
throw new Error("GeminiAgent not implemented");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
protected makeErrorResult(type: "skip" | "error", message: string): ReviewerResult {
|
|
33
|
+
return makeResult(this.agent.name, false, type, {}, "", message);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected parseOutput(_raw: string, _result: unknown): Record<string, unknown> | null {
|
|
37
|
+
throw new Error("GeminiAgent not implemented");
|
|
38
|
+
}
|
|
39
|
+
}
|