automata-cli 0.4.0-develop.152 → 0.4.0-develop.164

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,6 +113,19 @@ 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
+
116
129
  ## Development
117
130
 
118
131
  ### 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,25 +1350,11 @@ 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
  }
1730
- var MODEL_IDS = {
1731
- opus: "claude-opus-4-6",
1732
- sonnet: "claude-sonnet-4-6",
1733
- haiku: "claude-haiku-4-5-20251001"
1734
- };
1735
- function resolveModelOption(opts) {
1736
- const selected = ["opus", "sonnet", "haiku"].filter((m) => opts[m]);
1737
- if (selected.length > 1) {
1738
- process.stderr.write(`Error: --${selected[0]} and --${selected[1]} are mutually exclusive.
1739
- `);
1740
- process.exit(1);
1741
- }
1742
- return selected.length === 1 ? MODEL_IDS[selected[0]] : void 0;
1743
- }
1744
1358
  function invokeClaudeCode(prompt, options = {}) {
1745
1359
  if (options.verbose) {
1746
1360
  return invokeClaudeCodeVerbose(prompt, options.yolo ?? false, options.model);
@@ -1758,7 +1372,7 @@ function invokeClaudeCodeSync(prompt, yolo, model) {
1758
1372
  handleExitCode(result.status, "Claude Code");
1759
1373
  }
1760
1374
  function invokeClaudeCodeVerbose(prompt, yolo, model) {
1761
- return new Promise((resolve3) => {
1375
+ return new Promise((resolve2) => {
1762
1376
  const claudeBin = resolveCommand("claude");
1763
1377
  const args = [];
1764
1378
  if (yolo) args.push("--dangerously-skip-permissions");
@@ -1780,7 +1394,7 @@ function invokeClaudeCodeVerbose(prompt, yolo, model) {
1780
1394
  });
1781
1395
  child.on("close", (code) => {
1782
1396
  handleExitCode(code, "Claude Code");
1783
- resolve3();
1397
+ resolve2();
1784
1398
  });
1785
1399
  });
1786
1400
  }
@@ -1886,8 +1500,8 @@ async function promptSelection(issues, limit, output) {
1886
1500
  writeIssueList(output, issues, limit);
1887
1501
  const rl = createInterface2({ input: process.stdin, output });
1888
1502
  const answer = await new Promise(
1889
- (resolve3) => rl.question(`
1890
- Select issue (1-${issues.length}): `, resolve3)
1503
+ (resolve2) => rl.question(`
1504
+ Select issue (1-${issues.length}): `, resolve2)
1891
1505
  );
1892
1506
  rl.close();
1893
1507
  const n = Number.parseInt(answer.trim(), 10);
@@ -2043,13 +1657,13 @@ ${issue.body}`;
2043
1657
  });
2044
1658
 
2045
1659
  // src/commands/execute.ts
2046
- import { readFileSync as readFileSync3 } from "fs";
1660
+ import { readFileSync as readFileSync2 } from "fs";
2047
1661
  import { Command as Command4 } from "commander";
2048
1662
  function readStdin() {
2049
- return new Promise((resolve3, reject) => {
1663
+ return new Promise((resolve2, reject) => {
2050
1664
  const chunks = [];
2051
1665
  process.stdin.on("data", (chunk) => chunks.push(chunk));
2052
- process.stdin.on("end", () => resolve3(Buffer.concat(chunks).toString("utf8")));
1666
+ process.stdin.on("end", () => resolve2(Buffer.concat(chunks).toString("utf8")));
2053
1667
  process.stdin.on("error", reject);
2054
1668
  });
2055
1669
  }
@@ -2066,7 +1680,7 @@ async function resolvePrompt(options) {
2066
1680
  if (hasFile) {
2067
1681
  const path = options.filePrompt;
2068
1682
  try {
2069
- return readFileSync3(path, "utf8");
1683
+ return readFileSync2(path, "utf8");
2070
1684
  } catch {
2071
1685
  process.stderr.write(`Error: Cannot read file: ${path}
2072
1686
  `);
@@ -2111,13 +1725,30 @@ function formatPrInfoContext(pr) {
2111
1725
  return JSON.stringify(pr, null, 2);
2112
1726
  }
2113
1727
  function addAiOptions(cmd) {
2114
- 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)");
1728
+ 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");
1729
+ }
1730
+ function resolveExecutor(withOption) {
1731
+ const executor = withOption.toLowerCase();
1732
+ if (executor !== "claude" && executor !== "codex") {
1733
+ process.stderr.write(`Error: --with must be 'claude' or 'codex', got '${withOption}'.
1734
+ `);
1735
+ process.exit(1);
1736
+ }
1737
+ return executor;
1738
+ }
1739
+ function invokeSelectedExecutor(prompt, executor, options) {
1740
+ if (executor === "codex") {
1741
+ invokeCodexCode(prompt, { yolo: true, model: options.model });
1742
+ return;
1743
+ }
1744
+ return invokeClaudeCode(prompt, { yolo: true, verbose: !options.silent, model: options.model });
2115
1745
  }
2116
1746
  var executeSonarCmd = addAiOptions(
2117
1747
  new Command5("sonar").description(
2118
1748
  "Check the current branch for a SonarCloud analysis and invoke the AI with the Sonar prompt and analysis URL"
2119
1749
  )
2120
1750
  ).action(async (options) => {
1751
+ const executor = resolveExecutor(options.with);
2121
1752
  let branch;
2122
1753
  try {
2123
1754
  branch = getCurrentBranch();
@@ -2157,12 +1788,7 @@ Current PR context from automata git get-pr-info --json:
2157
1788
  ${formatPrInfoContext(pr)}`,
2158
1789
  options.push
2159
1790
  );
2160
- if (options.codex) {
2161
- invokeCodexCode(fullPrompt, { yolo: true });
2162
- } else {
2163
- const model = resolveModelOption(options);
2164
- await invokeClaudeCode(fullPrompt, { yolo: true, verbose: options.verbose, model });
2165
- }
1791
+ await invokeSelectedExecutor(fullPrompt, executor, options);
2166
1792
  });
2167
1793
  function formatComments(comments) {
2168
1794
  return comments.map((c) => {
@@ -2176,6 +1802,7 @@ var executeFixCommentsCmd = addAiOptions(
2176
1802
  "Fetch open review comments on the current PR and invoke the AI with the Fix-Comments prompt"
2177
1803
  )
2178
1804
  ).action(async (options) => {
1805
+ const executor = resolveExecutor(options.with);
2179
1806
  const result = resolveCurrentBranchComments();
2180
1807
  if (!result.ok) {
2181
1808
  if (result.kind === "error") {
@@ -2212,12 +1839,7 @@ Open review comments:
2212
1839
  ${formatComments(comments)}`,
2213
1840
  options.push
2214
1841
  );
2215
- if (options.codex) {
2216
- invokeCodexCode(fullPrompt, { yolo: true });
2217
- } else {
2218
- const model = resolveModelOption(options);
2219
- await invokeClaudeCode(fullPrompt, { yolo: true, verbose: options.verbose, model });
2220
- }
1842
+ await invokeSelectedExecutor(fullPrompt, executor, options);
2221
1843
  });
2222
1844
  var executePromptCommand = new Command5("execute-prompt").description("Execute a configured custom prompt using an AI assistant").addCommand(executeSonarCmd).addCommand(executeFixCommentsCmd);
2223
1845
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automata-cli",
3
- "version": "0.4.0-develop.152",
3
+ "version": "0.4.0-develop.164",
4
4
  "description": "Automata CLI tool",
5
5
  "type": "module",
6
6
  "bin": {