automata-cli 0.1.0-009-codex-flag-implement-next.75 → 0.1.0-010-sonarcloud-prompts-execute.81

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 (2) hide show
  1. package/dist/index.js +320 -25
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command5 } from "commander";
4
+ import { Command as Command6 } from "commander";
5
5
 
6
6
  // src/version.ts
7
7
  import { readFileSync } from "fs";
@@ -23,6 +23,8 @@ import { Box, Text, useInput, useApp } from "ink";
23
23
  // src/config/configStore.ts
24
24
  import { readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
25
25
  import { join } from "path";
26
+ 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.";
27
+ var DEFAULT_SONAR_PROMPT = "You are an expert software engineer. You have been given the URL of a SonarCloud analysis for this pull request. Please visit the SonarCloud analysis URL provided and fix all new issues reported. Focus on code smells, bugs, and vulnerabilities flagged as new in this PR. Make targeted, minimal changes that resolve each issue without altering unrelated code.";
26
28
  var CONFIG_DIR = ".automata";
27
29
  var CONFIG_FILE = "config.json";
28
30
  function configPath() {
@@ -53,22 +55,47 @@ var TECHNIQUE_OPTIONS = [
53
55
  { label: "By Assignee", value: "assignee" },
54
56
  { label: "By Title Contains", value: "title-contains" }
55
57
  ];
58
+ var MAIN_MENU_OPTIONS = ["Remote / Mode", "Implement-Next", "Prompts"];
59
+ var PROMPTS_MENU_OPTIONS = ["Sonar", "Fix-Comments"];
56
60
  function ConfigWizard() {
57
61
  const existing = readConfig();
58
62
  const initialRemoteIndex = REMOTE_OPTIONS.findIndex((o) => o.value === existing.remoteType);
59
63
  const initialTechIndex = TECHNIQUE_OPTIONS.findIndex((o) => o.value === existing.issueDiscoveryTechnique);
60
- const [screen, setScreen] = useState("remote");
64
+ const [screen, setScreen] = useState("main");
65
+ const [mainMenuIndex, setMainMenuIndex] = useState(0);
61
66
  const [selectedRemoteIndex, setSelectedRemoteIndex] = useState(initialRemoteIndex >= 0 ? initialRemoteIndex : 0);
62
67
  const [selectedTechIndex, setSelectedTechIndex] = useState(initialTechIndex >= 0 ? initialTechIndex : 0);
63
68
  const [discoveryValue, setDiscoveryValue] = useState(existing.issueDiscoveryValue ?? "");
64
69
  const [systemPrompt, setSystemPrompt] = useState(existing.claudeSystemPrompt ?? "");
70
+ const [promptsMenuIndex, setPromptsMenuIndex] = useState(0);
71
+ const [sonarPrompt, setSonarPrompt] = useState(existing.prompts?.sonar ?? DEFAULT_SONAR_PROMPT);
72
+ const [fixCommentsPrompt, setFixCommentsPrompt] = useState(
73
+ existing.prompts?.fixComments ?? DEFAULT_FIX_COMMENTS_PROMPT
74
+ );
65
75
  const [pendingRemote, setPendingRemote] = useState(existing.remoteType ?? "gh");
66
76
  const [pendingTechnique, setPendingTechnique] = useState(
67
77
  existing.issueDiscoveryTechnique ?? "label"
68
78
  );
69
79
  const { exit } = useApp();
70
80
  useInput((input, key) => {
71
- if (screen === "remote") {
81
+ if (screen === "main") {
82
+ if (key.upArrow) {
83
+ setMainMenuIndex((i) => i > 0 ? i - 1 : MAIN_MENU_OPTIONS.length - 1);
84
+ } else if (key.downArrow) {
85
+ setMainMenuIndex((i) => i < MAIN_MENU_OPTIONS.length - 1 ? i + 1 : 0);
86
+ } else if (key.return) {
87
+ const chosen = MAIN_MENU_OPTIONS[mainMenuIndex];
88
+ if (chosen === "Remote / Mode") {
89
+ setScreen("remote");
90
+ } else if (chosen === "Implement-Next") {
91
+ setScreen("technique");
92
+ } else {
93
+ setScreen("prompts-menu");
94
+ }
95
+ } else if (key.escape || key.ctrl && input === "c") {
96
+ exit();
97
+ }
98
+ } else if (screen === "remote") {
72
99
  if (key.upArrow) {
73
100
  setSelectedRemoteIndex((i) => i > 0 ? i - 1 : REMOTE_OPTIONS.length - 1);
74
101
  } else if (key.downArrow) {
@@ -82,7 +109,9 @@ function ConfigWizard() {
82
109
  writeConfig({ ...existing, remoteType: chosen.value });
83
110
  exit();
84
111
  }
85
- } else if (key.escape || key.ctrl && input === "c") {
112
+ } else if (key.escape) {
113
+ setScreen("main");
114
+ } else if (key.ctrl && input === "c") {
86
115
  exit();
87
116
  }
88
117
  } else if (screen === "technique") {
@@ -94,7 +123,9 @@ function ConfigWizard() {
94
123
  const chosen = TECHNIQUE_OPTIONS[selectedTechIndex];
95
124
  setPendingTechnique(chosen.value);
96
125
  setScreen("value");
97
- } else if (key.escape || key.ctrl && input === "c") {
126
+ } else if (key.escape) {
127
+ setScreen("main");
128
+ } else if (key.ctrl && input === "c") {
98
129
  exit();
99
130
  }
100
131
  } else if (screen === "value") {
@@ -102,7 +133,9 @@ function ConfigWizard() {
102
133
  setScreen("system-prompt");
103
134
  } else if (key.backspace || key.delete) {
104
135
  setDiscoveryValue((v) => v.slice(0, -1));
105
- } else if (key.escape || key.ctrl && input === "c") {
136
+ } else if (key.escape) {
137
+ setScreen("main");
138
+ } else if (key.ctrl && input === "c") {
106
139
  exit();
107
140
  } else if (input && !key.ctrl && !key.meta) {
108
141
  setDiscoveryValue((v) => v + input);
@@ -119,29 +152,92 @@ function ConfigWizard() {
119
152
  exit();
120
153
  } else if (key.backspace || key.delete) {
121
154
  setSystemPrompt((v) => v.slice(0, -1));
122
- } else if (key.escape || key.ctrl && input === "c") {
155
+ } else if (key.escape) {
156
+ setScreen("main");
157
+ } else if (key.ctrl && input === "c") {
123
158
  exit();
124
159
  } else if (input && !key.ctrl && !key.meta) {
125
160
  setSystemPrompt((v) => v + input);
126
161
  }
162
+ } else if (screen === "prompts-menu") {
163
+ if (key.upArrow) {
164
+ setPromptsMenuIndex((i) => i > 0 ? i - 1 : PROMPTS_MENU_OPTIONS.length - 1);
165
+ } else if (key.downArrow) {
166
+ setPromptsMenuIndex((i) => i < PROMPTS_MENU_OPTIONS.length - 1 ? i + 1 : 0);
167
+ } else if (key.return) {
168
+ const chosen = PROMPTS_MENU_OPTIONS[promptsMenuIndex];
169
+ if (chosen === "Sonar") {
170
+ setScreen("sonar-prompt");
171
+ } else {
172
+ setScreen("fix-comments-prompt");
173
+ }
174
+ } else if (key.escape) {
175
+ setScreen("main");
176
+ } else if (key.ctrl && input === "c") {
177
+ exit();
178
+ }
179
+ } else if (screen === "sonar-prompt") {
180
+ if (key.return) {
181
+ writeConfig({
182
+ ...existing,
183
+ prompts: { ...existing.prompts, sonar: sonarPrompt || void 0 }
184
+ });
185
+ setScreen("prompts-menu");
186
+ } else if (key.backspace || key.delete) {
187
+ setSonarPrompt((v) => v.slice(0, -1));
188
+ } else if (key.escape) {
189
+ setScreen("prompts-menu");
190
+ } else if (key.ctrl && input === "c") {
191
+ exit();
192
+ } else if (input && !key.ctrl && !key.meta) {
193
+ setSonarPrompt((v) => v + input);
194
+ }
195
+ } else if (screen === "fix-comments-prompt") {
196
+ if (key.return) {
197
+ writeConfig({
198
+ ...existing,
199
+ prompts: { ...existing.prompts, fixComments: fixCommentsPrompt || void 0 }
200
+ });
201
+ setScreen("prompts-menu");
202
+ } else if (key.backspace || key.delete) {
203
+ setFixCommentsPrompt((v) => v.slice(0, -1));
204
+ } else if (key.escape) {
205
+ setScreen("prompts-menu");
206
+ } else if (key.ctrl && input === "c") {
207
+ exit();
208
+ } else if (input && !key.ctrl && !key.meta) {
209
+ setFixCommentsPrompt((v) => v + input);
210
+ }
127
211
  }
128
212
  });
129
- if (screen === "remote") {
213
+ if (screen === "main") {
130
214
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
131
215
  /* @__PURE__ */ jsx(Text, { bold: true, children: "Configure Automata" }),
132
216
  /* @__PURE__ */ jsx(Text, { children: " " }),
217
+ MAIN_MENU_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === mainMenuIndex ? "cyan" : void 0, children: [
218
+ index === mainMenuIndex ? "\u276F " : " ",
219
+ option
220
+ ] }) }, option)),
221
+ /* @__PURE__ */ jsx(Text, { children: " " }),
222
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to cancel" })
223
+ ] });
224
+ }
225
+ if (screen === "remote") {
226
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
227
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Remote / Mode" }),
228
+ /* @__PURE__ */ jsx(Text, { children: " " }),
133
229
  /* @__PURE__ */ jsx(Text, { children: "Remote environment type:" }),
134
230
  REMOTE_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === selectedRemoteIndex ? "cyan" : void 0, children: [
135
231
  index === selectedRemoteIndex ? "\u276F " : " ",
136
232
  option.label
137
233
  ] }) }, option.value)),
138
234
  /* @__PURE__ */ jsx(Text, { children: " " }),
139
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Ctrl+C to cancel" })
235
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
140
236
  ] });
141
237
  }
142
238
  if (screen === "technique") {
143
239
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
144
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Configure Issue Discovery Technique" }),
240
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Issue Discovery Technique" }),
145
241
  /* @__PURE__ */ jsx(Text, { children: " " }),
146
242
  /* @__PURE__ */ jsx(Text, { children: "How to find the next issue to work on:" }),
147
243
  TECHNIQUE_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === selectedTechIndex ? "cyan" : void 0, children: [
@@ -149,13 +245,13 @@ function ConfigWizard() {
149
245
  option.label
150
246
  ] }) }, option.value)),
151
247
  /* @__PURE__ */ jsx(Text, { children: " " }),
152
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Ctrl+C to cancel" })
248
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to confirm \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
153
249
  ] });
154
250
  }
155
251
  if (screen === "value") {
156
252
  const techLabel = TECHNIQUE_OPTIONS.find((t) => t.value === pendingTechnique)?.label ?? pendingTechnique;
157
253
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
158
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Configure Issue Discovery Value" }),
254
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Issue Discovery Value" }),
159
255
  /* @__PURE__ */ jsx(Text, { children: " " }),
160
256
  /* @__PURE__ */ jsxs(Text, { children: [
161
257
  techLabel,
@@ -167,22 +263,66 @@ function ConfigWizard() {
167
263
  ] })
168
264
  ] }),
169
265
  /* @__PURE__ */ jsx(Text, { children: " " }),
170
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type value \xB7 Enter to confirm \xB7 Ctrl+C to cancel" })
266
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type value \xB7 Enter to continue \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
267
+ ] });
268
+ }
269
+ if (screen === "system-prompt") {
270
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
271
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Implement-Next \u2014 Claude System Prompt" }),
272
+ /* @__PURE__ */ jsx(Text, { children: " " }),
273
+ /* @__PURE__ */ jsxs(Text, { children: [
274
+ "System prompt (optional):",
275
+ " ",
276
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
277
+ systemPrompt,
278
+ /* @__PURE__ */ jsx(Text, { children: "_" })
279
+ ] })
280
+ ] }),
281
+ /* @__PURE__ */ jsx(Text, { children: " " }),
282
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save and exit \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
283
+ ] });
284
+ }
285
+ if (screen === "prompts-menu") {
286
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
287
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts" }),
288
+ /* @__PURE__ */ jsx(Text, { children: " " }),
289
+ PROMPTS_MENU_OPTIONS.map((option, index) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: index === promptsMenuIndex ? "cyan" : void 0, children: [
290
+ index === promptsMenuIndex ? "\u276F " : " ",
291
+ option
292
+ ] }) }, option)),
293
+ /* @__PURE__ */ jsx(Text, { children: " " }),
294
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\u2191/\u2193 to move \xB7 Enter to edit \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
295
+ ] });
296
+ }
297
+ if (screen === "sonar-prompt") {
298
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
299
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts \u2014 Sonar" }),
300
+ /* @__PURE__ */ jsx(Text, { children: " " }),
301
+ /* @__PURE__ */ jsxs(Text, { children: [
302
+ "Sonar prompt:",
303
+ " ",
304
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
305
+ sonarPrompt,
306
+ /* @__PURE__ */ jsx(Text, { children: "_" })
307
+ ] })
308
+ ] }),
309
+ /* @__PURE__ */ jsx(Text, { children: " " }),
310
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
171
311
  ] });
172
312
  }
173
313
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
174
- /* @__PURE__ */ jsx(Text, { bold: true, children: "Configure Claude System Prompt" }),
314
+ /* @__PURE__ */ jsx(Text, { bold: true, children: "Prompts \u2014 Fix-Comments" }),
175
315
  /* @__PURE__ */ jsx(Text, { children: " " }),
176
316
  /* @__PURE__ */ jsxs(Text, { children: [
177
- "System prompt (optional):",
317
+ "Fix-Comments prompt:",
178
318
  " ",
179
319
  /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
180
- systemPrompt,
320
+ fixCommentsPrompt,
181
321
  /* @__PURE__ */ jsx(Text, { children: "_" })
182
322
  ] })
183
323
  ] }),
184
324
  /* @__PURE__ */ jsx(Text, { children: " " }),
185
- /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save and exit \xB7 Ctrl+C to cancel" })
325
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Type prompt \xB7 Enter to save \xB7 Esc to go back \xB7 Ctrl+C to cancel" })
186
326
  ] });
187
327
  }
188
328
 
@@ -335,7 +475,27 @@ function fetchCheckRunOutputs(ownerRepo, sha) {
335
475
  }
336
476
  return map;
337
477
  }
338
- function getPrInfoGh(branch) {
478
+ function extractSonarProjectKey(url) {
479
+ try {
480
+ const parsed = new URL(url);
481
+ const id = parsed.searchParams.get("id");
482
+ return id ?? null;
483
+ } catch {
484
+ return null;
485
+ }
486
+ }
487
+ async function fetchSonarNewIssues(projectKey, prNumber) {
488
+ const apiUrl = `https://sonarcloud.io/api/issues/search?componentKeys=${encodeURIComponent(projectKey)}&pullRequest=${String(prNumber)}&resolved=false&ps=1`;
489
+ try {
490
+ const response = await fetch(apiUrl);
491
+ if (!response.ok) return null;
492
+ const data = await response.json();
493
+ return data.paging?.total ?? null;
494
+ } catch {
495
+ return null;
496
+ }
497
+ }
498
+ async function getPrInfoGh(branch) {
339
499
  const { stdout, stderr, status } = run2("gh", [
340
500
  "pr",
341
501
  "view",
@@ -365,9 +525,35 @@ function getPrInfoGh(branch) {
365
525
  detailsUrl: enriched?.detailsUrl || c.detailsUrl || ""
366
526
  };
367
527
  });
368
- return { number: raw.number, title: raw.title, state: raw.state, url: raw.url, checks };
528
+ const sonarCheck = checks.find((c) => {
529
+ try {
530
+ const hostname = new URL(c.detailsUrl).hostname;
531
+ return hostname === "sonarcloud.io" || hostname.endsWith(".sonarcloud.io");
532
+ } catch {
533
+ return false;
534
+ }
535
+ });
536
+ let sonarcloudUrl;
537
+ let sonarNewIssues;
538
+ if (sonarCheck) {
539
+ sonarcloudUrl = sonarCheck.detailsUrl;
540
+ const projectKey = extractSonarProjectKey(sonarCheck.detailsUrl);
541
+ if (projectKey) {
542
+ sonarNewIssues = await fetchSonarNewIssues(projectKey, raw.number);
543
+ } else {
544
+ sonarNewIssues = null;
545
+ }
546
+ }
547
+ return {
548
+ number: raw.number,
549
+ title: raw.title,
550
+ state: raw.state,
551
+ url: raw.url,
552
+ checks,
553
+ ...sonarcloudUrl !== void 0 ? { sonarcloudUrl, sonarNewIssues } : {}
554
+ };
369
555
  }
370
- function getPrInfo2(branch) {
556
+ async function getPrInfo2(branch) {
371
557
  const config = readConfig();
372
558
  if (config.remoteType === "azdo") {
373
559
  return getPrInfo();
@@ -603,7 +789,7 @@ See docs/git.md for full output reference.`
603
789
  let pr2;
604
790
  while (true) {
605
791
  try {
606
- pr2 = getPrInfo2(branch);
792
+ pr2 = await getPrInfo2(branch);
607
793
  } catch (err) {
608
794
  process.stderr.write(`Error: ${err.message}
609
795
  `);
@@ -643,7 +829,7 @@ See docs/git.md for full output reference.`
643
829
  }
644
830
  let pr;
645
831
  try {
646
- pr = getPrInfo2(branch);
832
+ pr = await getPrInfo2(branch);
647
833
  } catch (err) {
648
834
  process.stderr.write(`Error: ${err.message}
649
835
  `);
@@ -662,6 +848,13 @@ Title: ${pr.title}
662
848
  State: ${pr.state}
663
849
  URL: ${pr.url}
664
850
  `);
851
+ if (pr.sonarcloudUrl !== void 0) {
852
+ process.stdout.write(`Sonar: ${pr.sonarcloudUrl}
853
+ `);
854
+ const issueStr = pr.sonarNewIssues === null || pr.sonarNewIssues === void 0 ? "unavailable" : String(pr.sonarNewIssues);
855
+ process.stdout.write(`Sonar New Issues: ${issueStr}
856
+ `);
857
+ }
665
858
  process.stdout.write(formatCheckSummary(pr.checks));
666
859
  process.stdout.write(formatChecks(pr.checks));
667
860
  }
@@ -724,7 +917,7 @@ ${safeBody}`);
724
917
  }
725
918
  process.stdout.write(lines.join("\n\n") + "\n");
726
919
  });
727
- var finishFeatureCmd = new Command2("finish-feature").description("Clean up a merged feature branch: checkout develop, pull, and delete local branch").action(() => {
920
+ var finishFeatureCmd = new Command2("finish-feature").description("Clean up a merged feature branch: checkout develop, pull, and delete local branch").action(async () => {
728
921
  let branch;
729
922
  try {
730
923
  branch = getCurrentBranch();
@@ -745,7 +938,7 @@ var finishFeatureCmd = new Command2("finish-feature").description("Clean up a me
745
938
  }
746
939
  let pr;
747
940
  try {
748
- pr = getPrInfo2(branch);
941
+ pr = await getPrInfo2(branch);
749
942
  } catch (err) {
750
943
  process.stderr.write(`Error: ${err.message}
751
944
  `);
@@ -1194,13 +1387,115 @@ var testCodexCmd = new Command4("codex").description("Test Codex CLI invocation
1194
1387
  });
1195
1388
  var testCommand = new Command4("test").description("Test commands for verifying automata integrations").addCommand(testClaudeCmd).addCommand(testCodexCmd);
1196
1389
 
1390
+ // src/commands/executePrompt.ts
1391
+ import { Command as Command5 } from "commander";
1392
+ var executeSonarCmd = new Command5("sonar").description(
1393
+ "Check the current branch for a SonarCloud analysis and invoke the AI with the Sonar prompt and analysis URL"
1394
+ ).option("--codex", "Use Codex CLI instead of Claude Code").option("--verbose", "Show step-by-step progress (Claude only; ignored for Codex)").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)").action(
1395
+ async (options) => {
1396
+ let branch;
1397
+ try {
1398
+ branch = getCurrentBranch();
1399
+ } catch (err) {
1400
+ process.stderr.write(`Error: ${err.message}
1401
+ `);
1402
+ process.exit(1);
1403
+ }
1404
+ let pr;
1405
+ try {
1406
+ pr = await getPrInfo2(branch);
1407
+ } catch (err) {
1408
+ process.stderr.write(`Error: ${err.message}
1409
+ `);
1410
+ process.exit(1);
1411
+ }
1412
+ if (pr === null) {
1413
+ process.stderr.write(`Error: No pull request found for branch: ${branch}
1414
+ `);
1415
+ process.exit(1);
1416
+ }
1417
+ if (!pr.sonarcloudUrl) {
1418
+ process.stderr.write(
1419
+ `Error: No SonarCloud analysis found for PR #${pr.number}. Ensure a SonarCloud check is configured on this repository.
1420
+ `
1421
+ );
1422
+ process.exit(1);
1423
+ }
1424
+ const config = readConfig();
1425
+ const sonarPromptText = config.prompts?.sonar ?? DEFAULT_SONAR_PROMPT;
1426
+ const fullPrompt = `${sonarPromptText}
1427
+
1428
+ SonarCloud analysis URL: ${pr.sonarcloudUrl}`;
1429
+ if (options.codex) {
1430
+ invokeCodexCode(fullPrompt, { yolo: true, verbose: options.verbose });
1431
+ } else {
1432
+ const model = resolveModelOption(options);
1433
+ await invokeClaudeCode(fullPrompt, { yolo: true, verbose: options.verbose, model });
1434
+ }
1435
+ }
1436
+ );
1437
+ function formatComments(comments) {
1438
+ return comments.map((c) => {
1439
+ const loc = c.line !== null ? `${c.path}:${String(c.line)}` : `${c.path}:(file)`;
1440
+ return `[${c.author}] on ${loc}
1441
+ ${c.body}`;
1442
+ }).join("\n\n");
1443
+ }
1444
+ var executeFixCommentsCmd = new Command5("fix-comments").description(
1445
+ "Fetch open review comments on the current PR and invoke the AI with the Fix-Comments prompt"
1446
+ ).option("--codex", "Use Codex CLI instead of Claude Code").option("--verbose", "Show step-by-step progress (Claude only; ignored for Codex)").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)").action(
1447
+ async (options) => {
1448
+ let branch;
1449
+ try {
1450
+ branch = getCurrentBranch();
1451
+ } catch (err) {
1452
+ process.stderr.write(`Error: ${err.message}
1453
+ `);
1454
+ process.exit(1);
1455
+ }
1456
+ const comments = getPrComments(branch);
1457
+ if (comments === "unsupported") {
1458
+ process.stderr.write(
1459
+ `Error: fix-comments is not supported for Azure DevOps. See docs/azdo-gap.md for details.
1460
+ `
1461
+ );
1462
+ process.exit(1);
1463
+ }
1464
+ if (comments === null) {
1465
+ process.stderr.write(`Error: No pull request found for branch: ${branch}
1466
+ `);
1467
+ process.exit(1);
1468
+ }
1469
+ if (comments.length === 0) {
1470
+ process.stderr.write(`Error: No open review comments found on the pull request.
1471
+ `);
1472
+ process.exit(1);
1473
+ }
1474
+ const config = readConfig();
1475
+ const promptText = config.prompts?.fixComments ?? DEFAULT_FIX_COMMENTS_PROMPT;
1476
+ const fullPrompt = `${promptText}
1477
+
1478
+ Open review comments:
1479
+
1480
+ ${formatComments(comments)}`;
1481
+ if (options.codex) {
1482
+ invokeCodexCode(fullPrompt, { yolo: true, verbose: options.verbose });
1483
+ } else {
1484
+ const model = resolveModelOption(options);
1485
+ await invokeClaudeCode(fullPrompt, { yolo: true, verbose: options.verbose, model });
1486
+ }
1487
+ }
1488
+ );
1489
+ var executePromptCommand = new Command5("execute-prompt").description("Execute a configured custom prompt using an AI assistant").addCommand(executeSonarCmd).addCommand(executeFixCommentsCmd);
1490
+
1197
1491
  // src/index.ts
1198
- var program = new Command5();
1492
+ var program = new Command6();
1199
1493
  program.name("automata").description("Automata CLI tool").version(version, "-v, --version");
1200
1494
  program.addCommand(configCommand);
1201
1495
  program.addCommand(gitCommand);
1202
1496
  program.addCommand(implementNextCommand);
1203
1497
  program.addCommand(testCommand);
1498
+ program.addCommand(executePromptCommand);
1204
1499
  program.showHelpAfterError();
1205
1500
  program.parse();
1206
1501
  if (process.argv.length <= 2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automata-cli",
3
- "version": "0.1.0-009-codex-flag-implement-next.75",
3
+ "version": "0.1.0-010-sonarcloud-prompts-execute.81",
4
4
  "description": "Automata CLI tool",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,6 +33,7 @@
33
33
  "@types/node": "^25.5.0",
34
34
  "@types/react": "^19.2.14",
35
35
  "eslint": "^10.1.0",
36
+ "ink-testing-library": "^4.0.0",
36
37
  "prettier": "^3.8.1",
37
38
  "tsup": "^8.5.1",
38
39
  "typescript": "^5.9.3",