aiwcli 0.12.7 → 0.13.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.
Files changed (134) hide show
  1. package/dist/commands/clean.d.ts +7 -0
  2. package/dist/commands/clean.js +17 -8
  3. package/dist/commands/clear.d.ts +85 -0
  4. package/dist/commands/clear.js +455 -347
  5. package/dist/commands/init/index.d.ts +15 -0
  6. package/dist/commands/init/index.js +79 -38
  7. package/dist/lib/gitignore-manager.js +12 -13
  8. package/dist/lib/settings-hierarchy.d.ts +13 -1
  9. package/dist/lib/settings-hierarchy.js +1 -1
  10. package/dist/lib/template-linter.d.ts +4 -0
  11. package/dist/lib/template-linter.js +1 -1
  12. package/dist/lib/tty-detection.d.ts +1 -0
  13. package/dist/lib/tty-detection.js +1 -0
  14. package/dist/templates/CLAUDE.md +27 -0
  15. package/dist/templates/_shared/.claude/settings.json +7 -7
  16. package/dist/templates/_shared/.claude/{commands/handoff.md → skills/handoff/SKILL.md} +4 -3
  17. package/dist/templates/_shared/.claude/{commands/handoff-resume.md → skills/handoff-resume/SKILL.md} +3 -2
  18. package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +43 -0
  19. package/dist/templates/_shared/.codex/workflows/handoff.md +1 -1
  20. package/dist/templates/_shared/.codex/workflows/meta-plan.md +347 -0
  21. package/dist/templates/_shared/.windsurf/workflows/handoff.md +1 -1
  22. package/dist/templates/_shared/.windsurf/workflows/meta-plan.md +347 -0
  23. package/dist/templates/_shared/hooks-ts/lint_after_edit.ts +59 -0
  24. package/dist/templates/_shared/hooks-ts/session_end.ts +11 -10
  25. package/dist/templates/_shared/hooks-ts/session_start.ts +15 -12
  26. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +12 -12
  27. package/dist/templates/_shared/lib-ts/CLAUDE.md +3 -3
  28. package/dist/templates/_shared/lib-ts/base/constants.ts +324 -306
  29. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +26 -7
  30. package/dist/templates/_shared/lib-ts/base/inference.ts +19 -19
  31. package/dist/templates/_shared/lib-ts/base/lint-dispatch.ts +287 -0
  32. package/dist/templates/_shared/lib-ts/base/state-io.ts +4 -3
  33. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +3 -3
  34. package/dist/templates/_shared/lib-ts/context/CLAUDE.md +134 -0
  35. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +16 -15
  36. package/dist/templates/_shared/lib-ts/context/context-selector.ts +16 -16
  37. package/dist/templates/_shared/lib-ts/context/context-store.ts +15 -14
  38. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +2 -2
  39. package/dist/templates/_shared/scripts/resolve-run.ts +61 -0
  40. package/dist/templates/_shared/scripts/resolve_context.ts +1 -1
  41. package/dist/templates/_shared/scripts/status_line.ts +100 -94
  42. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/CLAUDE.md +433 -421
  43. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/document-generator.ts +5 -4
  44. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/lib/handoff-reader.ts +2 -1
  45. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/resume_handoff.ts +6 -6
  46. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/scripts/save_handoff.ts +16 -17
  47. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff-resume.md +2 -2
  48. package/dist/templates/_shared/{handoff-system → skills/handoff-system}/workflows/handoff.md +3 -3
  49. package/dist/templates/_shared/skills/meta-plan/CLAUDE.md +44 -0
  50. package/dist/templates/_shared/skills/meta-plan/workflows/meta-plan.md +347 -0
  51. package/dist/templates/cc-native/.claude/commands/cc-native/specdev.md +1 -1
  52. package/dist/templates/cc-native/.claude/settings.json +86 -57
  53. package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +64 -0
  54. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/format.ts +599 -597
  55. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/index.ts +26 -26
  56. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/tracker.ts +107 -106
  57. package/dist/templates/cc-native/_cc-native/{lib-ts/artifacts → artifacts/lib}/write.ts +119 -118
  58. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +237 -247
  59. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +76 -74
  60. package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +76 -0
  61. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +163 -156
  62. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +15 -16
  63. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +116 -116
  64. package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +3 -3
  65. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +16 -12
  66. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +2 -3
  67. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
  68. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +7 -6
  69. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +9 -7
  70. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +17 -14
  71. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +41 -37
  72. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +43 -33
  73. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
  74. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +9 -8
  75. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +4 -3
  76. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +9 -10
  77. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +20 -19
  78. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +329 -329
  79. package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +149 -0
  80. package/dist/templates/cc-native/_cc-native/plan-review/agents/CLAUDE.md +143 -0
  81. package/dist/templates/cc-native/_cc-native/plan-review/agents/PLAN-ORCHESTRATOR.md +213 -0
  82. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-questions/PLAN-QUESTIONER.md +70 -0
  83. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-EVOLUTION.md +62 -0
  84. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-PATTERNS.md +61 -0
  85. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-STRUCTURE.md +62 -0
  86. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ASSUMPTION-TRACER.md +56 -0
  87. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CLARITY-AUDITOR.md +53 -0
  88. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-FEASIBILITY.md +66 -0
  89. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-GAPS.md +70 -0
  90. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-ORDERING.md +62 -0
  91. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CONSTRAINT-VALIDATOR.md +72 -0
  92. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-ADR-VALIDATOR.md +61 -0
  93. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-SCALE-MATCHER.md +64 -0
  94. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DEVILS-ADVOCATE.md +56 -0
  95. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +86 -0
  96. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HANDOFF-READINESS.md +59 -0
  97. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HIDDEN-COMPLEXITY.md +58 -0
  98. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/INCREMENTAL-DELIVERY.md +66 -0
  99. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-DEPENDENCY.md +62 -0
  100. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-FMEA.md +66 -0
  101. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-PREMORTEM.md +71 -0
  102. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-REVERSIBILITY.md +74 -0
  103. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SCOPE-BOUNDARY.md +77 -0
  104. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SIMPLICITY-GUARDIAN.md +62 -0
  105. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SKEPTIC.md +68 -0
  106. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +61 -0
  107. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +71 -0
  108. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +61 -0
  109. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +61 -0
  110. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-COSTS.md +67 -0
  111. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +65 -0
  112. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-COVERAGE.md +74 -0
  113. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-STRENGTH.md +69 -0
  114. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/agent-selection.ts +162 -163
  115. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/corroboration.ts +119 -119
  116. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/graduation.ts +132 -132
  117. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/orchestrator.ts +70 -70
  118. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/output-builder.ts +121 -130
  119. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/plan-questions.ts +101 -102
  120. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/review-pipeline.ts +507 -511
  121. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/agent.ts +73 -74
  122. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/base/base-agent.ts +217 -217
  123. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/index.ts +12 -12
  124. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/claude-agent.ts +66 -66
  125. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/codex-agent.ts +185 -185
  126. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/gemini-agent.ts +39 -39
  127. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/providers/orchestrator-claude-agent.ts +196 -196
  128. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/schemas.ts +201 -201
  129. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/reviewers/types.ts +23 -23
  130. package/dist/templates/cc-native/_cc-native/{lib-ts → plan-review/lib}/verdict.ts +72 -72
  131. package/dist/templates/cc-native/_cc-native/{workflows → plan-review/workflows}/specdev.md +9 -9
  132. package/oclif.manifest.json +1 -1
  133. package/package.json +6 -5
  134. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +0 -21
@@ -1,66 +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
- "--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
+ /**
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 "../../../../lib-ts/cli-output-parser.js";
8
+ import { coerceToReview } from "../../../../lib-ts/json-parser.js";
9
+ import type { ReviewerResult } from "../../../../lib-ts/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";
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
- }
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
+ 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 "../../../../lib-ts/debug.js";
13
+ import { parseJsonMaybe, coerceToReview } from "../../../../lib-ts/json-parser.js";
14
+ import type { ReviewerResult } from "../../../../lib-ts/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 "../../../../lib-ts/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
+ }