automata-cli 0.1.0-feature-028-normalize-execute-prompt.153 → 0.1.0-feature-fast-tests.158

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/README.md CHANGED
@@ -113,19 +113,6 @@ See [docs/execute.md](docs/execute.md) for full details.
113
113
 
114
114
  ---
115
115
 
116
- ## `automata execute-prompt`
117
-
118
- Run predefined AI workflows that gather context from the current branch before invoking Claude or Codex.
119
-
120
- ```bash
121
- automata execute-prompt sonar --with claude
122
- automata execute-prompt fix-comments --with codex --model o3
123
- ```
124
-
125
- See [docs/execute-prompt.md](docs/execute-prompt.md) for full details.
126
-
127
- ---
128
-
129
116
  ## Development
130
117
 
131
118
  ### Prerequisites
@@ -0,0 +1,320 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_FIX_COMMENTS_PROMPT,
4
+ DEFAULT_SONAR_PROMPT,
5
+ readConfig,
6
+ readRawConfig,
7
+ writeConfig
8
+ } from "./chunk-LAIP3B6F.js";
9
+
10
+ // src/config/ConfigWizard.tsx
11
+ import { useState } from "react";
12
+ import { Box, Text, useInput, useApp } from "ink";
13
+ import { writeFileSync, mkdirSync } from "fs";
14
+ import { join } from "path";
15
+ import { jsx, jsxs } from "react/jsx-runtime";
16
+ function writePromptFile(filename, content) {
17
+ const dir = join(process.cwd(), ".automata");
18
+ mkdirSync(dir, { recursive: true });
19
+ writeFileSync(join(dir, filename), content, "utf8");
20
+ }
21
+ var REMOTE_OPTIONS = [
22
+ { label: "GitHub", value: "gh" },
23
+ { label: "Azure DevOps", value: "azdo" }
24
+ ];
25
+ var TECHNIQUE_OPTIONS = [
26
+ { label: "By Label", value: "label" },
27
+ { label: "By Assignee", value: "assignee" },
28
+ { label: "By Title Contains", value: "title-contains" }
29
+ ];
30
+ var MAIN_MENU_OPTIONS = ["Remote / Mode", "Implement-Next", "Prompts"];
31
+ var PROMPTS_MENU_OPTIONS = ["Sonar", "Fix-Comments"];
32
+ function ConfigWizard() {
33
+ const existing = readConfig();
34
+ const rawExisting = readRawConfig();
35
+ const initialRemoteIndex = REMOTE_OPTIONS.findIndex((o) => o.value === existing.remoteType);
36
+ const initialTechIndex = TECHNIQUE_OPTIONS.findIndex((o) => o.value === existing.issueDiscoveryTechnique);
37
+ const [screen, setScreen] = useState("main");
38
+ const [mainMenuIndex, setMainMenuIndex] = useState(0);
39
+ const [selectedRemoteIndex, setSelectedRemoteIndex] = useState(initialRemoteIndex >= 0 ? initialRemoteIndex : 0);
40
+ const [selectedTechIndex, setSelectedTechIndex] = useState(initialTechIndex >= 0 ? initialTechIndex : 0);
41
+ const [discoveryValue, setDiscoveryValue] = useState(existing.issueDiscoveryValue ?? "");
42
+ const [systemPrompt, setSystemPrompt] = useState(existing.claudeSystemPrompt ?? "");
43
+ const [promptsMenuIndex, setPromptsMenuIndex] = useState(0);
44
+ const [sonarPrompt, setSonarPrompt] = useState(existing.prompts?.sonar ?? DEFAULT_SONAR_PROMPT);
45
+ const [fixCommentsPrompt, setFixCommentsPrompt] = useState(
46
+ existing.prompts?.fixComments ?? DEFAULT_FIX_COMMENTS_PROMPT
47
+ );
48
+ const [pendingRemote, setPendingRemote] = useState(existing.remoteType ?? "gh");
49
+ const [pendingTechnique, setPendingTechnique] = useState(
50
+ existing.issueDiscoveryTechnique ?? "label"
51
+ );
52
+ const { exit } = useApp();
53
+ useInput((input, key) => {
54
+ if (screen === "main") {
55
+ if (key.upArrow) {
56
+ setMainMenuIndex((i) => i > 0 ? i - 1 : MAIN_MENU_OPTIONS.length - 1);
57
+ } else if (key.downArrow) {
58
+ setMainMenuIndex((i) => i < MAIN_MENU_OPTIONS.length - 1 ? i + 1 : 0);
59
+ } else if (key.return) {
60
+ const chosen = MAIN_MENU_OPTIONS[mainMenuIndex];
61
+ if (chosen === "Remote / Mode") {
62
+ setScreen("remote");
63
+ } else if (chosen === "Implement-Next") {
64
+ setScreen("technique");
65
+ } else {
66
+ setScreen("prompts-menu");
67
+ }
68
+ } else if (key.escape || key.ctrl && input === "c") {
69
+ exit();
70
+ }
71
+ } else if (screen === "remote") {
72
+ if (key.upArrow) {
73
+ setSelectedRemoteIndex((i) => i > 0 ? i - 1 : REMOTE_OPTIONS.length - 1);
74
+ } else if (key.downArrow) {
75
+ setSelectedRemoteIndex((i) => i < REMOTE_OPTIONS.length - 1 ? i + 1 : 0);
76
+ } else if (key.return) {
77
+ const chosen = REMOTE_OPTIONS[selectedRemoteIndex];
78
+ setPendingRemote(chosen.value);
79
+ if (chosen.value === "gh") {
80
+ setScreen("technique");
81
+ } else {
82
+ writeConfig({ ...rawExisting, remoteType: chosen.value });
83
+ exit();
84
+ }
85
+ } else if (key.escape) {
86
+ setScreen("main");
87
+ } else if (key.ctrl && input === "c") {
88
+ exit();
89
+ }
90
+ } else if (screen === "technique") {
91
+ if (key.upArrow) {
92
+ setSelectedTechIndex((i) => i > 0 ? i - 1 : TECHNIQUE_OPTIONS.length - 1);
93
+ } else if (key.downArrow) {
94
+ setSelectedTechIndex((i) => i < TECHNIQUE_OPTIONS.length - 1 ? i + 1 : 0);
95
+ } else if (key.return) {
96
+ const chosen = TECHNIQUE_OPTIONS[selectedTechIndex];
97
+ setPendingTechnique(chosen.value);
98
+ setScreen("value");
99
+ } else if (key.escape) {
100
+ setScreen("main");
101
+ } else if (key.ctrl && input === "c") {
102
+ exit();
103
+ }
104
+ } else if (screen === "value") {
105
+ if (key.return) {
106
+ setScreen("system-prompt");
107
+ } else if (key.backspace || key.delete) {
108
+ setDiscoveryValue((v) => v.slice(0, -1));
109
+ } else if (key.escape) {
110
+ setScreen("main");
111
+ } else if (key.ctrl && input === "c") {
112
+ exit();
113
+ } else if (input && !key.ctrl && !key.meta) {
114
+ setDiscoveryValue((v) => v + input);
115
+ }
116
+ } else if (screen === "system-prompt") {
117
+ if (key.return) {
118
+ let claudeSystemPromptValue;
119
+ if (systemPrompt) {
120
+ writePromptFile("claude-system-prompt.md", systemPrompt);
121
+ claudeSystemPromptValue = "claude-system-prompt.md";
122
+ }
123
+ writeConfig({
124
+ ...rawExisting,
125
+ remoteType: pendingRemote,
126
+ issueDiscoveryTechnique: pendingTechnique,
127
+ issueDiscoveryValue: discoveryValue || void 0,
128
+ claudeSystemPrompt: claudeSystemPromptValue
129
+ });
130
+ exit();
131
+ } else if (key.backspace || key.delete) {
132
+ setSystemPrompt((v) => v.slice(0, -1));
133
+ } else if (key.escape) {
134
+ setScreen("main");
135
+ } else if (key.ctrl && input === "c") {
136
+ exit();
137
+ } else if (input && !key.ctrl && !key.meta) {
138
+ setSystemPrompt((v) => v + input);
139
+ }
140
+ } else if (screen === "prompts-menu") {
141
+ if (key.upArrow) {
142
+ setPromptsMenuIndex((i) => i > 0 ? i - 1 : PROMPTS_MENU_OPTIONS.length - 1);
143
+ } else if (key.downArrow) {
144
+ setPromptsMenuIndex((i) => i < PROMPTS_MENU_OPTIONS.length - 1 ? i + 1 : 0);
145
+ } else if (key.return) {
146
+ const chosen = PROMPTS_MENU_OPTIONS[promptsMenuIndex];
147
+ if (chosen === "Sonar") {
148
+ setScreen("sonar-prompt");
149
+ } else {
150
+ setScreen("fix-comments-prompt");
151
+ }
152
+ } else if (key.escape) {
153
+ setScreen("main");
154
+ } else if (key.ctrl && input === "c") {
155
+ exit();
156
+ }
157
+ } else if (screen === "sonar-prompt") {
158
+ if (key.return) {
159
+ let sonarValue;
160
+ if (sonarPrompt) {
161
+ writePromptFile("sonar-prompt.md", sonarPrompt);
162
+ sonarValue = "sonar-prompt.md";
163
+ }
164
+ const current = readRawConfig();
165
+ writeConfig({
166
+ ...current,
167
+ prompts: { ...current.prompts, sonar: sonarValue }
168
+ });
169
+ setScreen("prompts-menu");
170
+ } else if (key.backspace || key.delete) {
171
+ setSonarPrompt((v) => v.slice(0, -1));
172
+ } else if (key.escape) {
173
+ setScreen("prompts-menu");
174
+ } else if (key.ctrl && input === "c") {
175
+ exit();
176
+ } else if (input && !key.ctrl && !key.meta) {
177
+ setSonarPrompt((v) => v + input);
178
+ }
179
+ } else if (screen === "fix-comments-prompt") {
180
+ if (key.return) {
181
+ let fixCommentsValue;
182
+ if (fixCommentsPrompt) {
183
+ writePromptFile("fix-comments-prompt.md", fixCommentsPrompt);
184
+ fixCommentsValue = "fix-comments-prompt.md";
185
+ }
186
+ const current = readRawConfig();
187
+ writeConfig({
188
+ ...current,
189
+ prompts: { ...current.prompts, fixComments: fixCommentsValue }
190
+ });
191
+ setScreen("prompts-menu");
192
+ } else if (key.backspace || key.delete) {
193
+ setFixCommentsPrompt((v) => v.slice(0, -1));
194
+ } else if (key.escape) {
195
+ setScreen("prompts-menu");
196
+ } else if (key.ctrl && input === "c") {
197
+ exit();
198
+ } else if (input && !key.ctrl && !key.meta) {
199
+ setFixCommentsPrompt((v) => v + input);
200
+ }
201
+ }
202
+ });
203
+ if (screen === "main") {
204
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
205
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Configure Automata" }),
206
+ /* @__PURE__ */ jsx(Text, { children: " " }),
207
+ MAIN_MENU_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === mainMenuIndex ? "cyan" : void 0, children: [
208
+ index === mainMenuIndex ? "\u276F " : " ",
209
+ option
210
+ ] }) }, option)),
211
+ /* @__PURE__ */ jsx(Text, { children: " " }),
212
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to cancel" })
213
+ ] });
214
+ }
215
+ if (screen === "remote") {
216
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
217
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Remote / Mode" }),
218
+ /* @__PURE__ */ jsx(Text, { children: " " }),
219
+ /* @__PURE__ */ jsx(Text, { children: "Remote environment type:" }),
220
+ REMOTE_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === selectedRemoteIndex ? "cyan" : void 0, children: [
221
+ index === selectedRemoteIndex ? "\u276F " : " ",
222
+ option.label
223
+ ] }) }, option.value)),
224
+ /* @__PURE__ */ jsx(Text, { children: " " }),
225
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
226
+ ] });
227
+ }
228
+ if (screen === "technique") {
229
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
230
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Issue Discovery Technique" }),
231
+ /* @__PURE__ */ jsx(Text, { children: " " }),
232
+ /* @__PURE__ */ jsx(Text, { children: "How to find the next issue to work on:" }),
233
+ TECHNIQUE_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === selectedTechIndex ? "cyan" : void 0, children: [
234
+ index === selectedTechIndex ? "\u276F " : " ",
235
+ option.label
236
+ ] }) }, option.value)),
237
+ /* @__PURE__ */ jsx(Text, { children: " " }),
238
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
239
+ ] });
240
+ }
241
+ if (screen === "value") {
242
+ const techLabel = TECHNIQUE_OPTIONS.find((t) => t.value === pendingTechnique)?.label ?? pendingTechnique;
243
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
244
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Issue Discovery Value" }),
245
+ /* @__PURE__ */ jsx(Text, { children: " " }),
246
+ /* @__PURE__ */ jsxs(Text, { children: [
247
+ techLabel,
248
+ " value:",
249
+ " ",
250
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
251
+ discoveryValue,
252
+ /* @__PURE__ */ jsx(Text, { children: "_" })
253
+ ] })
254
+ ] }),
255
+ /* @__PURE__ */ jsx(Text, { children: " " }),
256
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type value \xB7 Enter to continue \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
257
+ ] });
258
+ }
259
+ if (screen === "system-prompt") {
260
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
261
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Claude System Prompt" }),
262
+ /* @__PURE__ */ jsx(Text, { children: " " }),
263
+ /* @__PURE__ */ jsxs(Text, { children: [
264
+ "System prompt (optional):",
265
+ " ",
266
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
267
+ systemPrompt,
268
+ /* @__PURE__ */ jsx(Text, { children: "_" })
269
+ ] })
270
+ ] }),
271
+ /* @__PURE__ */ jsx(Text, { children: " " }),
272
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save and exit \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
273
+ ] });
274
+ }
275
+ if (screen === "prompts-menu") {
276
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
277
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts" }),
278
+ /* @__PURE__ */ jsx(Text, { children: " " }),
279
+ PROMPTS_MENU_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === promptsMenuIndex ? "cyan" : void 0, children: [
280
+ index === promptsMenuIndex ? "\u276F " : " ",
281
+ option
282
+ ] }) }, option)),
283
+ /* @__PURE__ */ jsx(Text, { children: " " }),
284
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to edit \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
285
+ ] });
286
+ }
287
+ if (screen === "sonar-prompt") {
288
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
289
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts \u2014 Sonar" }),
290
+ /* @__PURE__ */ jsx(Text, { children: " " }),
291
+ /* @__PURE__ */ jsxs(Text, { children: [
292
+ "Sonar prompt:",
293
+ " ",
294
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
295
+ sonarPrompt,
296
+ /* @__PURE__ */ jsx(Text, { children: "_" })
297
+ ] })
298
+ ] }),
299
+ /* @__PURE__ */ jsx(Text, { children: " " }),
300
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
301
+ ] });
302
+ }
303
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
304
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts \u2014 Fix-Comments" }),
305
+ /* @__PURE__ */ jsx(Text, { children: " " }),
306
+ /* @__PURE__ */ jsxs(Text, { children: [
307
+ "Fix-Comments prompt:",
308
+ " ",
309
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
310
+ fixCommentsPrompt,
311
+ /* @__PURE__ */ jsx(Text, { children: "_" })
312
+ ] })
313
+ ] }),
314
+ /* @__PURE__ */ jsx(Text, { children: " " }),
315
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
316
+ ] });
317
+ }
318
+ export {
319
+ ConfigWizard
320
+ };
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/config/configStore.ts
4
+ import { readFileSync, writeFileSync, mkdirSync } from "fs";
5
+ import { join, resolve, sep } from "path";
6
+ var DEFAULT_CLAUDE_SYSTEM_PROMPT = "You are an expert software engineer. Implement the following issue according to the project's existing conventions and style. Make minimal, targeted changes that satisfy the requirements. Run tests and linting before finishing.";
7
+ var DEFAULT_FIX_COMMENTS_PROMPT = "You are an expert software engineer reviewing a pull request. Below are the open review comments left by reviewers on this PR. Please address each comment by making the appropriate code changes. Focus on the reviewer's concerns and make minimal, targeted changes that resolve each comment without altering unrelated code.";
8
+ var DEFAULT_SONAR_PROMPT = "You are an expert software engineer. You have been given the URL of a SonarCloud analysis for this pull request. If the `sonar-quality-gate` skill is available in this repository, use it. The project is public, so use the SonarCloud REST API directly (no authentication required) rather than scraping the URL. Inspect both the quality gate and the list of issues for this pull request. If the quality gate fails because of duplication or another metric-based condition, use the relevant Sonar APIs to identify the affected files and details instead of relying only on the issues endpoint. Fix all new issues and quality-gate failures reported. Focus on code smells, bugs, vulnerabilities, and blocking quality-gate conditions flagged in this PR. Make targeted, minimal changes that resolve each issue without altering unrelated code.";
9
+ var CONFIG_DIR = ".automata";
10
+ var CONFIG_FILE = "config.json";
11
+ function configPath() {
12
+ return join(process.cwd(), CONFIG_DIR, CONFIG_FILE);
13
+ }
14
+ function automataDir() {
15
+ return join(process.cwd(), CONFIG_DIR);
16
+ }
17
+ function resolvePromptRef(value, dir) {
18
+ if (!value.endsWith(".md")) return value;
19
+ if (value.includes("/") || value.includes("\\")) {
20
+ throw new Error(`Prompt file "${value}" must be a plain filename with no subdirectories`);
21
+ }
22
+ const fullPath = resolve(dir, value);
23
+ const safeBase = resolve(dir) + sep;
24
+ if (!fullPath.startsWith(safeBase)) {
25
+ throw new Error(`Prompt file "${value}" resolves outside .automata/`);
26
+ }
27
+ try {
28
+ return readFileSync(fullPath, "utf8");
29
+ } catch (err) {
30
+ if (err?.code === "ENOENT") {
31
+ throw new Error(
32
+ `Prompt file "${value}" not found in "${dir}". Expected path: ${fullPath}`,
33
+ { cause: err }
34
+ );
35
+ }
36
+ throw err;
37
+ }
38
+ }
39
+ function readRawConfig() {
40
+ try {
41
+ const raw = readFileSync(configPath(), "utf8");
42
+ return JSON.parse(raw);
43
+ } catch {
44
+ return {};
45
+ }
46
+ }
47
+ function readConfig() {
48
+ let config;
49
+ try {
50
+ const raw = readFileSync(configPath(), "utf8");
51
+ config = JSON.parse(raw);
52
+ } catch {
53
+ return {};
54
+ }
55
+ const dir = automataDir();
56
+ if (config.claudeSystemPrompt) {
57
+ config.claudeSystemPrompt = resolvePromptRef(config.claudeSystemPrompt, dir);
58
+ }
59
+ if (config.prompts?.sonar) {
60
+ config.prompts.sonar = resolvePromptRef(config.prompts.sonar, dir);
61
+ }
62
+ if (config.prompts?.fixComments) {
63
+ config.prompts.fixComments = resolvePromptRef(config.prompts.fixComments, dir);
64
+ }
65
+ return config;
66
+ }
67
+ function writeConfig(config) {
68
+ const dir = join(process.cwd(), CONFIG_DIR);
69
+ mkdirSync(dir, { recursive: true });
70
+ writeFileSync(configPath(), JSON.stringify(config, null, 2) + "\n", "utf8");
71
+ }
72
+
73
+ export {
74
+ DEFAULT_CLAUDE_SYSTEM_PROMPT,
75
+ DEFAULT_FIX_COMMENTS_PROMPT,
76
+ DEFAULT_SONAR_PROMPT,
77
+ readRawConfig,
78
+ readConfig,
79
+ writeConfig
80
+ };
package/dist/index.js CHANGED
@@ -1,4 +1,12 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_CLAUDE_SYSTEM_PROMPT,
4
+ DEFAULT_FIX_COMMENTS_PROMPT,
5
+ DEFAULT_SONAR_PROMPT,
6
+ readConfig,
7
+ readRawConfig,
8
+ writeConfig
9
+ } from "./chunk-LAIP3B6F.js";
2
10
 
3
11
  // src/index.ts
4
12
  import { Command as Command6 } from "commander";
@@ -13,391 +21,6 @@ var version = packageJson.version;
13
21
 
14
22
  // src/commands/config.ts
15
23
  import { Command } from "commander";
16
- import { render } from "ink";
17
- import React2 from "react";
18
-
19
- // src/config/ConfigWizard.tsx
20
- import { useState } from "react";
21
- import { Box, Text, useInput, useApp } from "ink";
22
- import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
23
- import { join as join2 } from "path";
24
-
25
- // src/config/configStore.ts
26
- import { readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
27
- import { join, resolve as resolve2, sep } from "path";
28
- var DEFAULT_CLAUDE_SYSTEM_PROMPT = "You are an expert software engineer. Implement the following issue according to the project's existing conventions and style. Make minimal, targeted changes that satisfy the requirements. Run tests and linting before finishing.";
29
- var DEFAULT_FIX_COMMENTS_PROMPT = "You are an expert software engineer reviewing a pull request. Below are the open review comments left by reviewers on this PR. Please address each comment by making the appropriate code changes. Focus on the reviewer's concerns and make minimal, targeted changes that resolve each comment without altering unrelated code.";
30
- var DEFAULT_SONAR_PROMPT = "You are an expert software engineer. You have been given the URL of a SonarCloud analysis for this pull request. If the `sonar-quality-gate` skill is available in this repository, use it. The project is public, so use the SonarCloud REST API directly (no authentication required) rather than scraping the URL. Inspect both the quality gate and the list of issues for this pull request. If the quality gate fails because of duplication or another metric-based condition, use the relevant Sonar APIs to identify the affected files and details instead of relying only on the issues endpoint. Fix all new issues and quality-gate failures reported. Focus on code smells, bugs, vulnerabilities, and blocking quality-gate conditions flagged in this PR. Make targeted, minimal changes that resolve each issue without altering unrelated code.";
31
- var CONFIG_DIR = ".automata";
32
- var CONFIG_FILE = "config.json";
33
- function configPath() {
34
- return join(process.cwd(), CONFIG_DIR, CONFIG_FILE);
35
- }
36
- function automataDir() {
37
- return join(process.cwd(), CONFIG_DIR);
38
- }
39
- function resolvePromptRef(value, dir) {
40
- if (!value.endsWith(".md")) return value;
41
- if (value.includes("/") || value.includes("\\")) {
42
- throw new Error(`Prompt file "${value}" must be a plain filename with no subdirectories`);
43
- }
44
- const fullPath = resolve2(dir, value);
45
- const safeBase = resolve2(dir) + sep;
46
- if (!fullPath.startsWith(safeBase)) {
47
- throw new Error(`Prompt file "${value}" resolves outside .automata/`);
48
- }
49
- try {
50
- return readFileSync2(fullPath, "utf8");
51
- } catch (err) {
52
- if (err?.code === "ENOENT") {
53
- throw new Error(
54
- `Prompt file "${value}" not found in "${dir}". Expected path: ${fullPath}`,
55
- { cause: err }
56
- );
57
- }
58
- throw err;
59
- }
60
- }
61
- function readRawConfig() {
62
- try {
63
- const raw = readFileSync2(configPath(), "utf8");
64
- return JSON.parse(raw);
65
- } catch {
66
- return {};
67
- }
68
- }
69
- function readConfig() {
70
- let config;
71
- try {
72
- const raw = readFileSync2(configPath(), "utf8");
73
- config = JSON.parse(raw);
74
- } catch {
75
- return {};
76
- }
77
- const dir = automataDir();
78
- if (config.claudeSystemPrompt) {
79
- config.claudeSystemPrompt = resolvePromptRef(config.claudeSystemPrompt, dir);
80
- }
81
- if (config.prompts?.sonar) {
82
- config.prompts.sonar = resolvePromptRef(config.prompts.sonar, dir);
83
- }
84
- if (config.prompts?.fixComments) {
85
- config.prompts.fixComments = resolvePromptRef(config.prompts.fixComments, dir);
86
- }
87
- return config;
88
- }
89
- function writeConfig(config) {
90
- const dir = join(process.cwd(), CONFIG_DIR);
91
- mkdirSync(dir, { recursive: true });
92
- writeFileSync(configPath(), JSON.stringify(config, null, 2) + "\n", "utf8");
93
- }
94
-
95
- // src/config/ConfigWizard.tsx
96
- import { jsx, jsxs } from "react/jsx-runtime";
97
- function writePromptFile(filename, content) {
98
- const dir = join2(process.cwd(), ".automata");
99
- mkdirSync2(dir, { recursive: true });
100
- writeFileSync2(join2(dir, filename), content, "utf8");
101
- }
102
- var REMOTE_OPTIONS = [
103
- { label: "GitHub", value: "gh" },
104
- { label: "Azure DevOps", value: "azdo" }
105
- ];
106
- var TECHNIQUE_OPTIONS = [
107
- { label: "By Label", value: "label" },
108
- { label: "By Assignee", value: "assignee" },
109
- { label: "By Title Contains", value: "title-contains" }
110
- ];
111
- var MAIN_MENU_OPTIONS = ["Remote / Mode", "Implement-Next", "Prompts"];
112
- var PROMPTS_MENU_OPTIONS = ["Sonar", "Fix-Comments"];
113
- function ConfigWizard() {
114
- const existing = readConfig();
115
- const rawExisting = readRawConfig();
116
- const initialRemoteIndex = REMOTE_OPTIONS.findIndex((o) => o.value === existing.remoteType);
117
- const initialTechIndex = TECHNIQUE_OPTIONS.findIndex((o) => o.value === existing.issueDiscoveryTechnique);
118
- const [screen, setScreen] = useState("main");
119
- const [mainMenuIndex, setMainMenuIndex] = useState(0);
120
- const [selectedRemoteIndex, setSelectedRemoteIndex] = useState(initialRemoteIndex >= 0 ? initialRemoteIndex : 0);
121
- const [selectedTechIndex, setSelectedTechIndex] = useState(initialTechIndex >= 0 ? initialTechIndex : 0);
122
- const [discoveryValue, setDiscoveryValue] = useState(existing.issueDiscoveryValue ?? "");
123
- const [systemPrompt, setSystemPrompt] = useState(existing.claudeSystemPrompt ?? "");
124
- const [promptsMenuIndex, setPromptsMenuIndex] = useState(0);
125
- const [sonarPrompt, setSonarPrompt] = useState(existing.prompts?.sonar ?? DEFAULT_SONAR_PROMPT);
126
- const [fixCommentsPrompt, setFixCommentsPrompt] = useState(
127
- existing.prompts?.fixComments ?? DEFAULT_FIX_COMMENTS_PROMPT
128
- );
129
- const [pendingRemote, setPendingRemote] = useState(existing.remoteType ?? "gh");
130
- const [pendingTechnique, setPendingTechnique] = useState(
131
- existing.issueDiscoveryTechnique ?? "label"
132
- );
133
- const { exit } = useApp();
134
- useInput((input, key) => {
135
- if (screen === "main") {
136
- if (key.upArrow) {
137
- setMainMenuIndex((i) => i > 0 ? i - 1 : MAIN_MENU_OPTIONS.length - 1);
138
- } else if (key.downArrow) {
139
- setMainMenuIndex((i) => i < MAIN_MENU_OPTIONS.length - 1 ? i + 1 : 0);
140
- } else if (key.return) {
141
- const chosen = MAIN_MENU_OPTIONS[mainMenuIndex];
142
- if (chosen === "Remote / Mode") {
143
- setScreen("remote");
144
- } else if (chosen === "Implement-Next") {
145
- setScreen("technique");
146
- } else {
147
- setScreen("prompts-menu");
148
- }
149
- } else if (key.escape || key.ctrl && input === "c") {
150
- exit();
151
- }
152
- } else if (screen === "remote") {
153
- if (key.upArrow) {
154
- setSelectedRemoteIndex((i) => i > 0 ? i - 1 : REMOTE_OPTIONS.length - 1);
155
- } else if (key.downArrow) {
156
- setSelectedRemoteIndex((i) => i < REMOTE_OPTIONS.length - 1 ? i + 1 : 0);
157
- } else if (key.return) {
158
- const chosen = REMOTE_OPTIONS[selectedRemoteIndex];
159
- setPendingRemote(chosen.value);
160
- if (chosen.value === "gh") {
161
- setScreen("technique");
162
- } else {
163
- writeConfig({ ...rawExisting, remoteType: chosen.value });
164
- exit();
165
- }
166
- } else if (key.escape) {
167
- setScreen("main");
168
- } else if (key.ctrl && input === "c") {
169
- exit();
170
- }
171
- } else if (screen === "technique") {
172
- if (key.upArrow) {
173
- setSelectedTechIndex((i) => i > 0 ? i - 1 : TECHNIQUE_OPTIONS.length - 1);
174
- } else if (key.downArrow) {
175
- setSelectedTechIndex((i) => i < TECHNIQUE_OPTIONS.length - 1 ? i + 1 : 0);
176
- } else if (key.return) {
177
- const chosen = TECHNIQUE_OPTIONS[selectedTechIndex];
178
- setPendingTechnique(chosen.value);
179
- setScreen("value");
180
- } else if (key.escape) {
181
- setScreen("main");
182
- } else if (key.ctrl && input === "c") {
183
- exit();
184
- }
185
- } else if (screen === "value") {
186
- if (key.return) {
187
- setScreen("system-prompt");
188
- } else if (key.backspace || key.delete) {
189
- setDiscoveryValue((v) => v.slice(0, -1));
190
- } else if (key.escape) {
191
- setScreen("main");
192
- } else if (key.ctrl && input === "c") {
193
- exit();
194
- } else if (input && !key.ctrl && !key.meta) {
195
- setDiscoveryValue((v) => v + input);
196
- }
197
- } else if (screen === "system-prompt") {
198
- if (key.return) {
199
- let claudeSystemPromptValue;
200
- if (systemPrompt) {
201
- writePromptFile("claude-system-prompt.md", systemPrompt);
202
- claudeSystemPromptValue = "claude-system-prompt.md";
203
- }
204
- writeConfig({
205
- ...rawExisting,
206
- remoteType: pendingRemote,
207
- issueDiscoveryTechnique: pendingTechnique,
208
- issueDiscoveryValue: discoveryValue || void 0,
209
- claudeSystemPrompt: claudeSystemPromptValue
210
- });
211
- exit();
212
- } else if (key.backspace || key.delete) {
213
- setSystemPrompt((v) => v.slice(0, -1));
214
- } else if (key.escape) {
215
- setScreen("main");
216
- } else if (key.ctrl && input === "c") {
217
- exit();
218
- } else if (input && !key.ctrl && !key.meta) {
219
- setSystemPrompt((v) => v + input);
220
- }
221
- } else if (screen === "prompts-menu") {
222
- if (key.upArrow) {
223
- setPromptsMenuIndex((i) => i > 0 ? i - 1 : PROMPTS_MENU_OPTIONS.length - 1);
224
- } else if (key.downArrow) {
225
- setPromptsMenuIndex((i) => i < PROMPTS_MENU_OPTIONS.length - 1 ? i + 1 : 0);
226
- } else if (key.return) {
227
- const chosen = PROMPTS_MENU_OPTIONS[promptsMenuIndex];
228
- if (chosen === "Sonar") {
229
- setScreen("sonar-prompt");
230
- } else {
231
- setScreen("fix-comments-prompt");
232
- }
233
- } else if (key.escape) {
234
- setScreen("main");
235
- } else if (key.ctrl && input === "c") {
236
- exit();
237
- }
238
- } else if (screen === "sonar-prompt") {
239
- if (key.return) {
240
- let sonarValue;
241
- if (sonarPrompt) {
242
- writePromptFile("sonar-prompt.md", sonarPrompt);
243
- sonarValue = "sonar-prompt.md";
244
- }
245
- const current = readRawConfig();
246
- writeConfig({
247
- ...current,
248
- prompts: { ...current.prompts, sonar: sonarValue }
249
- });
250
- setScreen("prompts-menu");
251
- } else if (key.backspace || key.delete) {
252
- setSonarPrompt((v) => v.slice(0, -1));
253
- } else if (key.escape) {
254
- setScreen("prompts-menu");
255
- } else if (key.ctrl && input === "c") {
256
- exit();
257
- } else if (input && !key.ctrl && !key.meta) {
258
- setSonarPrompt((v) => v + input);
259
- }
260
- } else if (screen === "fix-comments-prompt") {
261
- if (key.return) {
262
- let fixCommentsValue;
263
- if (fixCommentsPrompt) {
264
- writePromptFile("fix-comments-prompt.md", fixCommentsPrompt);
265
- fixCommentsValue = "fix-comments-prompt.md";
266
- }
267
- const current = readRawConfig();
268
- writeConfig({
269
- ...current,
270
- prompts: { ...current.prompts, fixComments: fixCommentsValue }
271
- });
272
- setScreen("prompts-menu");
273
- } else if (key.backspace || key.delete) {
274
- setFixCommentsPrompt((v) => v.slice(0, -1));
275
- } else if (key.escape) {
276
- setScreen("prompts-menu");
277
- } else if (key.ctrl && input === "c") {
278
- exit();
279
- } else if (input && !key.ctrl && !key.meta) {
280
- setFixCommentsPrompt((v) => v + input);
281
- }
282
- }
283
- });
284
- if (screen === "main") {
285
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
286
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Configure Automata" }),
287
- /* @__PURE__ */ jsx(Text, { children: " " }),
288
- MAIN_MENU_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === mainMenuIndex ? "cyan" : void 0, children: [
289
- index === mainMenuIndex ? "\u276F " : " ",
290
- option
291
- ] }) }, option)),
292
- /* @__PURE__ */ jsx(Text, { children: " " }),
293
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to cancel" })
294
- ] });
295
- }
296
- if (screen === "remote") {
297
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
298
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Remote / Mode" }),
299
- /* @__PURE__ */ jsx(Text, { children: " " }),
300
- /* @__PURE__ */ jsx(Text, { children: "Remote environment type:" }),
301
- REMOTE_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === selectedRemoteIndex ? "cyan" : void 0, children: [
302
- index === selectedRemoteIndex ? "\u276F " : " ",
303
- option.label
304
- ] }) }, option.value)),
305
- /* @__PURE__ */ jsx(Text, { children: " " }),
306
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
307
- ] });
308
- }
309
- if (screen === "technique") {
310
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
311
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Issue Discovery Technique" }),
312
- /* @__PURE__ */ jsx(Text, { children: " " }),
313
- /* @__PURE__ */ jsx(Text, { children: "How to find the next issue to work on:" }),
314
- TECHNIQUE_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === selectedTechIndex ? "cyan" : void 0, children: [
315
- index === selectedTechIndex ? "\u276F " : " ",
316
- option.label
317
- ] }) }, option.value)),
318
- /* @__PURE__ */ jsx(Text, { children: " " }),
319
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
320
- ] });
321
- }
322
- if (screen === "value") {
323
- const techLabel = TECHNIQUE_OPTIONS.find((t) => t.value === pendingTechnique)?.label ?? pendingTechnique;
324
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
325
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Issue Discovery Value" }),
326
- /* @__PURE__ */ jsx(Text, { children: " " }),
327
- /* @__PURE__ */ jsxs(Text, { children: [
328
- techLabel,
329
- " value:",
330
- " ",
331
- /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
332
- discoveryValue,
333
- /* @__PURE__ */ jsx(Text, { children: "_" })
334
- ] })
335
- ] }),
336
- /* @__PURE__ */ jsx(Text, { children: " " }),
337
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type value \xB7 Enter to continue \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
338
- ] });
339
- }
340
- if (screen === "system-prompt") {
341
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
342
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Claude System Prompt" }),
343
- /* @__PURE__ */ jsx(Text, { children: " " }),
344
- /* @__PURE__ */ jsxs(Text, { children: [
345
- "System prompt (optional):",
346
- " ",
347
- /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
348
- systemPrompt,
349
- /* @__PURE__ */ jsx(Text, { children: "_" })
350
- ] })
351
- ] }),
352
- /* @__PURE__ */ jsx(Text, { children: " " }),
353
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save and exit \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
354
- ] });
355
- }
356
- if (screen === "prompts-menu") {
357
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
358
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts" }),
359
- /* @__PURE__ */ jsx(Text, { children: " " }),
360
- PROMPTS_MENU_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === promptsMenuIndex ? "cyan" : void 0, children: [
361
- index === promptsMenuIndex ? "\u276F " : " ",
362
- option
363
- ] }) }, option)),
364
- /* @__PURE__ */ jsx(Text, { children: " " }),
365
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to edit \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
366
- ] });
367
- }
368
- if (screen === "sonar-prompt") {
369
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
370
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts \u2014 Sonar" }),
371
- /* @__PURE__ */ jsx(Text, { children: " " }),
372
- /* @__PURE__ */ jsxs(Text, { children: [
373
- "Sonar prompt:",
374
- " ",
375
- /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
376
- sonarPrompt,
377
- /* @__PURE__ */ jsx(Text, { children: "_" })
378
- ] })
379
- ] }),
380
- /* @__PURE__ */ jsx(Text, { children: " " }),
381
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
382
- ] });
383
- }
384
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
385
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts \u2014 Fix-Comments" }),
386
- /* @__PURE__ */ jsx(Text, { children: " " }),
387
- /* @__PURE__ */ jsxs(Text, { children: [
388
- "Fix-Comments prompt:",
389
- " ",
390
- /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
391
- fixCommentsPrompt,
392
- /* @__PURE__ */ jsx(Text, { children: "_" })
393
- ] })
394
- ] }),
395
- /* @__PURE__ */ jsx(Text, { children: " " }),
396
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
397
- ] });
398
- }
399
-
400
- // src/commands/config.ts
401
24
  var VALID_TYPES = ["gh", "azdo"];
402
25
  var VALID_TECHNIQUES = ["label", "assignee", "title-contains"];
403
26
  var configSetType = new Command("type").description("Set the remote environment type").argument("<value>", "Remote type: gh (GitHub) or azdo (Azure DevOps)").action((value) => {
@@ -436,7 +59,12 @@ var configSetClaudeSystemPrompt = new Command("claude-system-prompt").descriptio
436
59
  });
437
60
  var configSet = new Command("set").description("Set a configuration value").addCommand(configSetType).addCommand(configSetIssueDiscoveryTechnique).addCommand(configSetIssueDiscoveryValue).addCommand(configSetClaudeSystemPrompt);
438
61
  var configCommand = new Command("config").description("Configure automata settings").addCommand(configSet).action(async () => {
439
- const { waitUntilExit } = render(React2.createElement(ConfigWizard));
62
+ const [{ render }, React, { ConfigWizard }] = await Promise.all([
63
+ import("ink"),
64
+ import("react"),
65
+ import("./ConfigWizard-WUGEM3PT.js")
66
+ ]);
67
+ const { waitUntilExit } = render(React.createElement(ConfigWizard));
440
68
  await waitUntilExit();
441
69
  });
442
70
 
@@ -1140,7 +768,7 @@ function formatChecks(checks) {
1140
768
  return lines.join("\n") + "\n";
1141
769
  }
1142
770
  function sleep(ms) {
1143
- return new Promise((resolve3) => setTimeout(resolve3, ms));
771
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
1144
772
  }
1145
773
  function isSonarCheck(check) {
1146
774
  try {
@@ -1687,7 +1315,7 @@ function addCopilotReviewer(prNumber) {
1687
1315
  import { spawn, spawnSync as spawnSync4 } from "child_process";
1688
1316
  import { createInterface } from "readline";
1689
1317
  import { existsSync } from "fs";
1690
- import { delimiter, join as join3 } from "path";
1318
+ import { delimiter, join } from "path";
1691
1319
 
1692
1320
  // src/cli/spawnUtils.ts
1693
1321
  function truncate(str, max) {
@@ -1722,11 +1350,25 @@ function handleExitCode(status, toolName) {
1722
1350
  function resolveCommand(name) {
1723
1351
  const pathDirs = (process.env["PATH"] ?? "").split(delimiter);
1724
1352
  for (const dir of pathDirs) {
1725
- const candidate = join3(dir, name);
1353
+ const candidate = join(dir, name);
1726
1354
  if (existsSync(candidate)) return candidate;
1727
1355
  }
1728
1356
  return name;
1729
1357
  }
1358
+ var MODEL_IDS = {
1359
+ opus: "claude-opus-4-6",
1360
+ sonnet: "claude-sonnet-4-6",
1361
+ haiku: "claude-haiku-4-5-20251001"
1362
+ };
1363
+ function resolveModelOption(opts) {
1364
+ const selected = ["opus", "sonnet", "haiku"].filter((m) => opts[m]);
1365
+ if (selected.length > 1) {
1366
+ process.stderr.write(`Error: --${selected[0]} and --${selected[1]} are mutually exclusive.
1367
+ `);
1368
+ process.exit(1);
1369
+ }
1370
+ return selected.length === 1 ? MODEL_IDS[selected[0]] : void 0;
1371
+ }
1730
1372
  function invokeClaudeCode(prompt, options = {}) {
1731
1373
  if (options.verbose) {
1732
1374
  return invokeClaudeCodeVerbose(prompt, options.yolo ?? false, options.model);
@@ -1744,7 +1386,7 @@ function invokeClaudeCodeSync(prompt, yolo, model) {
1744
1386
  handleExitCode(result.status, "Claude Code");
1745
1387
  }
1746
1388
  function invokeClaudeCodeVerbose(prompt, yolo, model) {
1747
- return new Promise((resolve3) => {
1389
+ return new Promise((resolve2) => {
1748
1390
  const claudeBin = resolveCommand("claude");
1749
1391
  const args = [];
1750
1392
  if (yolo) args.push("--dangerously-skip-permissions");
@@ -1766,7 +1408,7 @@ function invokeClaudeCodeVerbose(prompt, yolo, model) {
1766
1408
  });
1767
1409
  child.on("close", (code) => {
1768
1410
  handleExitCode(code, "Claude Code");
1769
- resolve3();
1411
+ resolve2();
1770
1412
  });
1771
1413
  });
1772
1414
  }
@@ -1872,8 +1514,8 @@ async function promptSelection(issues, limit, output) {
1872
1514
  writeIssueList(output, issues, limit);
1873
1515
  const rl = createInterface2({ input: process.stdin, output });
1874
1516
  const answer = await new Promise(
1875
- (resolve3) => rl.question(`
1876
- Select issue (1-${issues.length}): `, resolve3)
1517
+ (resolve2) => rl.question(`
1518
+ Select issue (1-${issues.length}): `, resolve2)
1877
1519
  );
1878
1520
  rl.close();
1879
1521
  const n = Number.parseInt(answer.trim(), 10);
@@ -2029,13 +1671,13 @@ ${issue.body}`;
2029
1671
  });
2030
1672
 
2031
1673
  // src/commands/execute.ts
2032
- import { readFileSync as readFileSync3 } from "fs";
1674
+ import { readFileSync as readFileSync2 } from "fs";
2033
1675
  import { Command as Command4 } from "commander";
2034
1676
  function readStdin() {
2035
- return new Promise((resolve3, reject) => {
1677
+ return new Promise((resolve2, reject) => {
2036
1678
  const chunks = [];
2037
1679
  process.stdin.on("data", (chunk) => chunks.push(chunk));
2038
- process.stdin.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
1680
+ process.stdin.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
2039
1681
  process.stdin.on("error", reject);
2040
1682
  });
2041
1683
  }
@@ -2052,7 +1694,7 @@ async function resolvePrompt(options) {
2052
1694
  if (hasFile) {
2053
1695
  const path = options.filePrompt;
2054
1696
  try {
2055
- return readFileSync3(path, "utf8");
1697
+ return readFileSync2(path, "utf8");
2056
1698
  } catch {
2057
1699
  process.stderr.write(`Error: Cannot read file: ${path}
2058
1700
  `);
@@ -2097,24 +1739,7 @@ function formatPrInfoContext(pr) {
2097
1739
  return JSON.stringify(pr, null, 2);
2098
1740
  }
2099
1741
  function addAiOptions(cmd) {
2100
- return cmd.requiredOption("--with <executor>", "Executor to use: claude or codex").option("--model <string>", "Model identifier to pass to the executor").option("--silent", "Suppress step-by-step Claude output; show only the final summary").option("--push", "Append instruction to commit and push changes after the AI finishes");
2101
- }
2102
- function resolveExecutor(withOption) {
2103
- const executor = withOption.toLowerCase();
2104
- if (executor !== "claude" && executor !== "codex") {
2105
- process.stderr.write(`Error: --with must be 'claude' or 'codex', got '${withOption}'.
2106
- `);
2107
- process.exit(1);
2108
- }
2109
- return executor;
2110
- }
2111
- function invokeSelectedExecutor(prompt, options) {
2112
- const executor = resolveExecutor(options.with);
2113
- if (executor === "codex") {
2114
- invokeCodexCode(prompt, { yolo: true, model: options.model });
2115
- return;
2116
- }
2117
- return invokeClaudeCode(prompt, { yolo: true, verbose: !options.silent, model: options.model });
1742
+ return cmd.option("--codex", "Use Codex CLI instead of Claude Code").option("--verbose", "Show step-by-step progress (Claude only; ignored for Codex)").option("--push", "Append instruction to commit and push changes after the AI finishes").option("--opus", "Use claude-opus-4-6 (Claude only)").option("--sonnet", "Use claude-sonnet-4-6 (Claude only)").option("--haiku", "Use claude-haiku-4-5-20251001 (Claude only)");
2118
1743
  }
2119
1744
  var executeSonarCmd = addAiOptions(
2120
1745
  new Command5("sonar").description(
@@ -2160,7 +1785,12 @@ Current PR context from automata git get-pr-info --json:
2160
1785
  ${formatPrInfoContext(pr)}`,
2161
1786
  options.push
2162
1787
  );
2163
- await invokeSelectedExecutor(fullPrompt, options);
1788
+ if (options.codex) {
1789
+ invokeCodexCode(fullPrompt, { yolo: true });
1790
+ } else {
1791
+ const model = resolveModelOption(options);
1792
+ await invokeClaudeCode(fullPrompt, { yolo: true, verbose: options.verbose, model });
1793
+ }
2164
1794
  });
2165
1795
  function formatComments(comments) {
2166
1796
  return comments.map((c) => {
@@ -2210,7 +1840,12 @@ Open review comments:
2210
1840
  ${formatComments(comments)}`,
2211
1841
  options.push
2212
1842
  );
2213
- await invokeSelectedExecutor(fullPrompt, options);
1843
+ if (options.codex) {
1844
+ invokeCodexCode(fullPrompt, { yolo: true });
1845
+ } else {
1846
+ const model = resolveModelOption(options);
1847
+ await invokeClaudeCode(fullPrompt, { yolo: true, verbose: options.verbose, model });
1848
+ }
2214
1849
  });
2215
1850
  var executePromptCommand = new Command5("execute-prompt").description("Execute a configured custom prompt using an AI assistant").addCommand(executeSonarCmd).addCommand(executeFixCommentsCmd);
2216
1851
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automata-cli",
3
- "version": "0.1.0-feature-028-normalize-execute-prompt.153",
3
+ "version": "0.1.0-feature-fast-tests.158",
4
4
  "description": "Automata CLI tool",
5
5
  "type": "module",
6
6
  "bin": {