automata-cli 0.5.0-develop.181 → 0.5.0-develop.220

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
@@ -127,6 +127,12 @@ See [docs/execute-prompt.md](docs/execute-prompt.md) for full details.
127
127
 
128
128
  ---
129
129
 
130
+ ## `automata do-work`
131
+
132
+ One tick of the autonomous loop: answer the open issues whose newest message from an authorized account the agent has not answered. Reference: [docs/do-work.md](docs/do-work.md). Process, trust model and setup: [the wiki](docs/wiki/Home.md).
133
+
134
+ ---
135
+
130
136
  ## Development
131
137
 
132
138
  ### Prerequisites
@@ -137,11 +143,19 @@ See [docs/execute-prompt.md](docs/execute-prompt.md) for full details.
137
143
  ### Setup
138
144
 
139
145
  ```bash
140
- git clone https://github.com/alkampfergit/automata-cli.git
146
+ git clone --recurse-submodules https://github.com/alkampfergit/automata-cli.git
141
147
  cd automata-cli
142
148
  npm install
143
149
  ```
144
150
 
151
+ Already cloned without `--recurse-submodules`? Fetch the vendored agent plugins with:
152
+
153
+ ```bash
154
+ git submodule update --init --recursive
155
+ ```
156
+
157
+ `vendor/agent-plugins-base` is registered in `.claude/settings.json` as a project-scope Claude Code marketplace, and the `github-alk` plugin is enabled from it — so its skills load for anyone working in this repository. See [docs/plugins.md](docs/plugins.md).
158
+
145
159
  ### Scripts
146
160
 
147
161
  | Command | Description |
@@ -152,6 +166,8 @@ npm install
152
166
  | `npm run typecheck` | Type-check with tsc (no emit) |
153
167
  | `npm run format` | Check formatting with Prettier |
154
168
 
169
+ Agent plugins are vendored as a submodule and registered with Claude Code — see [docs/plugins.md](docs/plugins.md).
170
+
155
171
  ## License
156
172
 
157
173
  [MIT](LICENSE)
@@ -0,0 +1,544 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ DEFAULT_CHECK_ISSUE_PROMPT,
4
+ DEFAULT_DO_WORK,
5
+ DEFAULT_DO_WORK_ISSUE_DISCUSS_PROMPT,
6
+ DEFAULT_DO_WORK_PR_WORK_PROMPT,
7
+ DEFAULT_FIX_COMMENTS_PROMPT,
8
+ DEFAULT_SONAR_PROMPT,
9
+ readConfig,
10
+ readRawConfig,
11
+ writeConfig
12
+ } from "./chunk-LTCVLM4I.js";
13
+
14
+ // src/config/ConfigWizard.tsx
15
+ import { useState } from "react";
16
+ import { Box, Text, useInput, useApp } from "ink";
17
+ import { writeFileSync, mkdirSync } from "fs";
18
+ import { join } from "path";
19
+ import { jsx, jsxs } from "react/jsx-runtime";
20
+ function writePromptFile(filename, content) {
21
+ const dir = join(process.cwd(), ".automata");
22
+ mkdirSync(dir, { recursive: true });
23
+ writeFileSync(join(dir, filename), content, "utf8");
24
+ }
25
+ var REMOTE_OPTIONS = [
26
+ { label: "GitHub", value: "gh" },
27
+ { label: "Azure DevOps", value: "azdo" }
28
+ ];
29
+ var TECHNIQUE_OPTIONS = [
30
+ { label: "By Label", value: "label" },
31
+ { label: "By Assignee", value: "assignee" },
32
+ { label: "By Title Contains", value: "title-contains" }
33
+ ];
34
+ var EXECUTOR_OPTIONS = [
35
+ { label: "Claude Code", value: "claude" },
36
+ { label: "Codex", value: "codex" }
37
+ ];
38
+ var MAIN_MENU_OPTIONS = ["Remote / Mode", "Implement-Next", "Prompts", "Issue Watch", "Do Work"];
39
+ var PROMPTS_MENU_OPTIONS = [
40
+ "Sonar",
41
+ "Fix-Comments",
42
+ "Check-Issue",
43
+ "Do Work \u2014 Discuss",
44
+ "Do Work \u2014 PR"
45
+ ];
46
+ function parseAllowedUsers(value) {
47
+ return value.split(",").map((user) => user.trim()).filter((user) => user.length > 0);
48
+ }
49
+ function handleTextEntry(input, key, screen, cancel) {
50
+ if (key.return) {
51
+ screen.onSubmit();
52
+ } else if (key.backspace || key.delete) {
53
+ screen.setValue((value) => value.slice(0, -1));
54
+ } else if (key.escape) {
55
+ screen.onBack();
56
+ } else if (key.ctrl && input === "c") {
57
+ cancel();
58
+ } else if (input && !key.ctrl && !key.meta) {
59
+ screen.setValue((value) => value + input);
60
+ }
61
+ }
62
+ function handleMenu(input, key, menu, cancel) {
63
+ if (key.upArrow) {
64
+ menu.setIndex((i) => i > 0 ? i - 1 : menu.length - 1);
65
+ } else if (key.downArrow) {
66
+ menu.setIndex((i) => i < menu.length - 1 ? i + 1 : 0);
67
+ } else if (key.return) {
68
+ menu.onSelect();
69
+ } else if (key.escape) {
70
+ if (menu.onBack) menu.onBack();
71
+ else cancel();
72
+ } else if (key.ctrl && input === "c") {
73
+ cancel();
74
+ }
75
+ }
76
+ function TextEntryScreen({ title, label, value, hint, error }) {
77
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
78
+ /* @__PURE__ */ jsx(Text, { bold: true, children: title }),
79
+ /* @__PURE__ */ jsx(Text, { children: " " }),
80
+ /* @__PURE__ */ jsxs(Text, { children: [
81
+ label,
82
+ " ",
83
+ /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
84
+ value,
85
+ /* @__PURE__ */ jsx(Text, { children: "_" })
86
+ ] })
87
+ ] }),
88
+ error ? /* @__PURE__ */ jsx(Text, { color: "red", children: error }) : /* @__PURE__ */ jsx(Text, { children: " " }),
89
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
90
+ ] });
91
+ }
92
+ function MenuEntryScreen({ title, options, index, hint }) {
93
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
94
+ /* @__PURE__ */ jsx(Text, { bold: true, children: title }),
95
+ /* @__PURE__ */ jsx(Text, { children: " " }),
96
+ options.map((option, optionIndex) => /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: optionIndex === index ? "cyan" : void 0, children: [
97
+ optionIndex === index ? "\u276F " : " ",
98
+ option
99
+ ] }) }, option)),
100
+ /* @__PURE__ */ jsx(Text, { children: " " }),
101
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: hint })
102
+ ] });
103
+ }
104
+ var BACK = "Esc to go back \xB7 Ctrl+C to cancel";
105
+ function parseWholeInt(value) {
106
+ const trimmed = value.trim();
107
+ if (!/^\d+$/.test(trimmed)) return null;
108
+ const parsed = Number(trimmed);
109
+ return Number.isSafeInteger(parsed) ? parsed : null;
110
+ }
111
+ function savePrompt(filename, content, merge) {
112
+ let value;
113
+ if (content) {
114
+ writePromptFile(filename, content);
115
+ value = filename;
116
+ }
117
+ writeConfig(merge(value, readRawConfig()));
118
+ }
119
+ var PROMPT_SCREEN_BY_OPTION = {
120
+ Sonar: "sonar-prompt",
121
+ "Fix-Comments": "fix-comments-prompt",
122
+ "Check-Issue": "check-issue-prompt",
123
+ "Do Work \u2014 Discuss": "do-work-discuss-prompt",
124
+ "Do Work \u2014 PR": "do-work-pr-prompt"
125
+ };
126
+ function ConfigWizard() {
127
+ const existing = readConfig();
128
+ const rawExisting = readRawConfig();
129
+ const initialRemoteIndex = REMOTE_OPTIONS.findIndex((o) => o.value === existing.remoteType);
130
+ const initialTechIndex = TECHNIQUE_OPTIONS.findIndex((o) => o.value === existing.issueDiscoveryTechnique);
131
+ const [screen, setScreen] = useState("main");
132
+ const [mainMenuIndex, setMainMenuIndex] = useState(0);
133
+ const [selectedRemoteIndex, setSelectedRemoteIndex] = useState(initialRemoteIndex >= 0 ? initialRemoteIndex : 0);
134
+ const [selectedTechIndex, setSelectedTechIndex] = useState(initialTechIndex >= 0 ? initialTechIndex : 0);
135
+ const [discoveryValue, setDiscoveryValue] = useState(existing.issueDiscoveryValue ?? "");
136
+ const [systemPrompt, setSystemPrompt] = useState(existing.claudeSystemPrompt ?? "");
137
+ const [promptsMenuIndex, setPromptsMenuIndex] = useState(0);
138
+ const [sonarPrompt, setSonarPrompt] = useState(existing.prompts?.sonar ?? DEFAULT_SONAR_PROMPT);
139
+ const [fixCommentsPrompt, setFixCommentsPrompt] = useState(
140
+ existing.prompts?.fixComments ?? DEFAULT_FIX_COMMENTS_PROMPT
141
+ );
142
+ const [checkIssuePrompt, setCheckIssuePrompt] = useState(existing.prompts?.checkIssue ?? DEFAULT_CHECK_ISSUE_PROMPT);
143
+ const [allowedUsers, setAllowedUsers] = useState((existing.allowedUsers ?? []).join(", "));
144
+ const [agentUser, setAgentUser] = useState(existing.agentUser ?? "");
145
+ const [doWorkBaseBranch, setDoWorkBaseBranch] = useState(
146
+ existing.doWork?.baseBranch ?? DEFAULT_DO_WORK.baseBranch
147
+ );
148
+ const initialExecutorIndex = EXECUTOR_OPTIONS.findIndex((o) => o.value === existing.doWork?.executor);
149
+ const [doWorkExecutorIndex, setDoWorkExecutorIndex] = useState(Math.max(initialExecutorIndex, 0));
150
+ const [doWorkProtectedBranches, setDoWorkProtectedBranches] = useState(
151
+ (existing.doWork?.protectedBranches ?? DEFAULT_DO_WORK.protectedBranches).join(", ")
152
+ );
153
+ const [doWorkClaudeModel, setDoWorkClaudeModel] = useState(existing.doWork?.models?.claude ?? "");
154
+ const [doWorkCodexModel, setDoWorkCodexModel] = useState(existing.doWork?.models?.codex ?? "");
155
+ const [doWorkLockStale, setDoWorkLockStale] = useState(
156
+ String(existing.doWork?.lockStaleMinutes ?? DEFAULT_DO_WORK.lockStaleMinutes)
157
+ );
158
+ const [validationError, setValidationError] = useState("");
159
+ const [doWorkMaxRuns, setDoWorkMaxRuns] = useState(
160
+ String(existing.doWork?.maxRunsPerTick ?? DEFAULT_DO_WORK.maxRunsPerTick)
161
+ );
162
+ const [doWorkDiscussPrompt, setDoWorkDiscussPrompt] = useState(
163
+ existing.doWork?.prompts?.issueDiscuss ?? DEFAULT_DO_WORK_ISSUE_DISCUSS_PROMPT
164
+ );
165
+ const [doWorkPrPrompt, setDoWorkPrPrompt] = useState(
166
+ existing.doWork?.prompts?.prWork ?? DEFAULT_DO_WORK_PR_WORK_PROMPT
167
+ );
168
+ const [pendingRemote, setPendingRemote] = useState(existing.remoteType ?? "gh");
169
+ const [pendingTechnique, setPendingTechnique] = useState(
170
+ existing.issueDiscoveryTechnique ?? "label"
171
+ );
172
+ const { exit } = useApp();
173
+ const textScreens = {
174
+ value: {
175
+ setValue: setDiscoveryValue,
176
+ onSubmit: () => setScreen("system-prompt"),
177
+ onBack: () => setScreen("main")
178
+ },
179
+ "system-prompt": {
180
+ setValue: setSystemPrompt,
181
+ onSubmit: () => {
182
+ let claudeSystemPromptValue;
183
+ if (systemPrompt) {
184
+ writePromptFile("claude-system-prompt.md", systemPrompt);
185
+ claudeSystemPromptValue = "claude-system-prompt.md";
186
+ }
187
+ writeConfig({
188
+ ...rawExisting,
189
+ remoteType: pendingRemote,
190
+ issueDiscoveryTechnique: pendingTechnique,
191
+ issueDiscoveryValue: discoveryValue || void 0,
192
+ claudeSystemPrompt: claudeSystemPromptValue
193
+ });
194
+ exit();
195
+ },
196
+ onBack: () => setScreen("main")
197
+ },
198
+ "sonar-prompt": {
199
+ setValue: setSonarPrompt,
200
+ onSubmit: () => {
201
+ savePrompt("sonar-prompt.md", sonarPrompt, (value, current) => ({
202
+ ...current,
203
+ prompts: { ...current.prompts, sonar: value }
204
+ }));
205
+ setScreen("prompts-menu");
206
+ },
207
+ onBack: () => setScreen("prompts-menu")
208
+ },
209
+ "fix-comments-prompt": {
210
+ setValue: setFixCommentsPrompt,
211
+ onSubmit: () => {
212
+ savePrompt("fix-comments-prompt.md", fixCommentsPrompt, (value, current) => ({
213
+ ...current,
214
+ prompts: { ...current.prompts, fixComments: value }
215
+ }));
216
+ setScreen("prompts-menu");
217
+ },
218
+ onBack: () => setScreen("prompts-menu")
219
+ },
220
+ "check-issue-prompt": {
221
+ setValue: setCheckIssuePrompt,
222
+ onSubmit: () => {
223
+ savePrompt("check-issue-prompt.md", checkIssuePrompt, (value, current) => ({
224
+ ...current,
225
+ prompts: { ...current.prompts, checkIssue: value }
226
+ }));
227
+ setScreen("prompts-menu");
228
+ },
229
+ onBack: () => setScreen("prompts-menu")
230
+ },
231
+ "allowed-users": {
232
+ setValue: setAllowedUsers,
233
+ onSubmit: () => setScreen("agent-user"),
234
+ onBack: () => setScreen("main")
235
+ },
236
+ "agent-user": {
237
+ setValue: setAgentUser,
238
+ onSubmit: () => {
239
+ const parsedUsers = parseAllowedUsers(allowedUsers);
240
+ const current = readRawConfig();
241
+ writeConfig({
242
+ ...current,
243
+ allowedUsers: parsedUsers.length > 0 ? parsedUsers : void 0,
244
+ agentUser: agentUser.trim() || void 0
245
+ });
246
+ exit();
247
+ },
248
+ onBack: () => setScreen("allowed-users")
249
+ },
250
+ "do-work-base-branch": {
251
+ setValue: setDoWorkBaseBranch,
252
+ onSubmit: () => setScreen("do-work-protected-branches"),
253
+ onBack: () => setScreen("main")
254
+ },
255
+ "do-work-protected-branches": {
256
+ setValue: (update) => {
257
+ setValidationError("");
258
+ setDoWorkProtectedBranches(update);
259
+ },
260
+ onSubmit: () => {
261
+ if (parseAllowedUsers(doWorkProtectedBranches).length === 0) {
262
+ setValidationError("Enter at least one branch name.");
263
+ return;
264
+ }
265
+ setValidationError("");
266
+ setScreen("do-work-executor");
267
+ },
268
+ onBack: () => setScreen("do-work-base-branch")
269
+ },
270
+ "do-work-claude-model": {
271
+ setValue: setDoWorkClaudeModel,
272
+ onSubmit: () => setScreen("do-work-codex-model"),
273
+ onBack: () => setScreen("do-work-executor")
274
+ },
275
+ "do-work-codex-model": {
276
+ setValue: setDoWorkCodexModel,
277
+ onSubmit: () => setScreen("do-work-max-runs"),
278
+ onBack: () => setScreen("do-work-claude-model")
279
+ },
280
+ "do-work-max-runs": {
281
+ setValue: (update) => {
282
+ setValidationError("");
283
+ setDoWorkMaxRuns(update);
284
+ },
285
+ onSubmit: () => {
286
+ const parsed = parseWholeInt(doWorkMaxRuns);
287
+ if (parsed === null || parsed < 0) {
288
+ setValidationError("Enter a non-negative whole number (0 = unlimited).");
289
+ return;
290
+ }
291
+ setValidationError("");
292
+ setScreen("do-work-lock-stale");
293
+ },
294
+ onBack: () => setScreen("do-work-codex-model")
295
+ },
296
+ "do-work-lock-stale": {
297
+ setValue: (update) => {
298
+ setValidationError("");
299
+ setDoWorkLockStale(update);
300
+ },
301
+ onSubmit: () => {
302
+ const parsed = parseWholeInt(doWorkLockStale);
303
+ if (parsed === null || parsed <= 0) {
304
+ setValidationError("Enter a whole number of minutes greater than zero.");
305
+ return;
306
+ }
307
+ const maxRuns = parseWholeInt(doWorkMaxRuns);
308
+ const current = readRawConfig();
309
+ writeConfig({
310
+ ...current,
311
+ doWork: {
312
+ ...current.doWork,
313
+ baseBranch: doWorkBaseBranch.trim() || void 0,
314
+ protectedBranches: parseAllowedUsers(doWorkProtectedBranches),
315
+ executor: EXECUTOR_OPTIONS[doWorkExecutorIndex].value,
316
+ models: {
317
+ claude: doWorkClaudeModel.trim() || void 0,
318
+ codex: doWorkCodexModel.trim() || void 0
319
+ },
320
+ maxRunsPerTick: maxRuns ?? void 0,
321
+ lockStaleMinutes: parsed
322
+ }
323
+ });
324
+ exit();
325
+ },
326
+ onBack: () => setScreen("do-work-max-runs")
327
+ },
328
+ "do-work-discuss-prompt": {
329
+ setValue: setDoWorkDiscussPrompt,
330
+ onSubmit: () => {
331
+ savePrompt("do-work-issue-discuss.md", doWorkDiscussPrompt, (value, current) => ({
332
+ ...current,
333
+ doWork: { ...current.doWork, prompts: { ...current.doWork?.prompts, issueDiscuss: value } }
334
+ }));
335
+ setScreen("prompts-menu");
336
+ },
337
+ onBack: () => setScreen("prompts-menu")
338
+ },
339
+ "do-work-pr-prompt": {
340
+ setValue: setDoWorkPrPrompt,
341
+ onSubmit: () => {
342
+ savePrompt("do-work-pr-work.md", doWorkPrPrompt, (value, current) => ({
343
+ ...current,
344
+ doWork: { ...current.doWork, prompts: { ...current.doWork?.prompts, prWork: value } }
345
+ }));
346
+ setScreen("prompts-menu");
347
+ },
348
+ onBack: () => setScreen("prompts-menu")
349
+ }
350
+ };
351
+ const menus = {
352
+ main: {
353
+ index: mainMenuIndex,
354
+ length: MAIN_MENU_OPTIONS.length,
355
+ setIndex: setMainMenuIndex,
356
+ onSelect: () => {
357
+ const chosen = MAIN_MENU_OPTIONS[mainMenuIndex];
358
+ if (chosen === "Remote / Mode") setScreen("remote");
359
+ else if (chosen === "Implement-Next") setScreen("technique");
360
+ else if (chosen === "Issue Watch") setScreen("allowed-users");
361
+ else if (chosen === "Do Work") setScreen("do-work-base-branch");
362
+ else setScreen("prompts-menu");
363
+ }
364
+ },
365
+ remote: {
366
+ index: selectedRemoteIndex,
367
+ length: REMOTE_OPTIONS.length,
368
+ setIndex: setSelectedRemoteIndex,
369
+ onSelect: () => {
370
+ setPendingRemote(REMOTE_OPTIONS[selectedRemoteIndex].value);
371
+ setScreen("technique");
372
+ },
373
+ onBack: () => setScreen("main")
374
+ },
375
+ technique: {
376
+ index: selectedTechIndex,
377
+ length: TECHNIQUE_OPTIONS.length,
378
+ setIndex: setSelectedTechIndex,
379
+ onSelect: () => {
380
+ setPendingTechnique(TECHNIQUE_OPTIONS[selectedTechIndex].value);
381
+ setScreen("value");
382
+ },
383
+ onBack: () => setScreen("main")
384
+ },
385
+ "prompts-menu": {
386
+ index: promptsMenuIndex,
387
+ length: PROMPTS_MENU_OPTIONS.length,
388
+ setIndex: setPromptsMenuIndex,
389
+ onSelect: () => setScreen(PROMPT_SCREEN_BY_OPTION[PROMPTS_MENU_OPTIONS[promptsMenuIndex]]),
390
+ onBack: () => setScreen("main")
391
+ },
392
+ "do-work-executor": {
393
+ index: doWorkExecutorIndex,
394
+ length: EXECUTOR_OPTIONS.length,
395
+ setIndex: setDoWorkExecutorIndex,
396
+ onSelect: () => setScreen("do-work-claude-model"),
397
+ onBack: () => setScreen("do-work-protected-branches")
398
+ }
399
+ };
400
+ useInput((input, key) => {
401
+ const textScreen = textScreens[screen];
402
+ if (textScreen) {
403
+ handleTextEntry(input, key, textScreen, exit);
404
+ return;
405
+ }
406
+ const menu = menus[screen];
407
+ if (menu) {
408
+ handleMenu(input, key, menu, exit);
409
+ }
410
+ });
411
+ const techLabel = TECHNIQUE_OPTIONS.find((o) => o.value === pendingTechnique)?.label ?? pendingTechnique;
412
+ const textViews = {
413
+ value: {
414
+ title: "Implement-Next \u2014 Issue Discovery Value",
415
+ label: `${techLabel} value:`,
416
+ value: discoveryValue,
417
+ hint: `Type value \xB7 Enter to continue \xB7 ${BACK}`
418
+ },
419
+ "system-prompt": {
420
+ title: "Implement-Next \u2014 Claude System Prompt",
421
+ label: "System prompt (optional):",
422
+ value: systemPrompt,
423
+ hint: `Type prompt \xB7 Enter to save and exit \xB7 ${BACK}`
424
+ },
425
+ "sonar-prompt": {
426
+ title: "Prompts \u2014 Sonar",
427
+ label: "Sonar prompt:",
428
+ value: sonarPrompt,
429
+ hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
430
+ },
431
+ "fix-comments-prompt": {
432
+ title: "Prompts \u2014 Fix-Comments",
433
+ label: "Fix-Comments prompt:",
434
+ value: fixCommentsPrompt,
435
+ hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
436
+ },
437
+ "check-issue-prompt": {
438
+ title: "Prompts \u2014 Check-Issue",
439
+ label: "Check-Issue prompt:",
440
+ value: checkIssuePrompt,
441
+ hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
442
+ },
443
+ "allowed-users": {
444
+ title: "Issue Watch \u2014 Allowed Users",
445
+ label: "Logins allowed to instruct the agent (comma separated):",
446
+ value: allowedUsers,
447
+ hint: `Type logins \xB7 Enter to continue \xB7 ${BACK}`
448
+ },
449
+ "agent-user": {
450
+ title: "Issue Watch \u2014 Agent User",
451
+ label: "Login the agent posts as:",
452
+ value: agentUser,
453
+ hint: `Type login \xB7 Enter to save and exit \xB7 ${BACK}`
454
+ },
455
+ "do-work-base-branch": {
456
+ title: "Do Work \u2014 Base Branch",
457
+ label: "Branch discussion turns return to:",
458
+ value: doWorkBaseBranch,
459
+ hint: `Type branch \xB7 Enter to continue \xB7 ${BACK}`
460
+ },
461
+ "do-work-protected-branches": {
462
+ title: "Do Work \u2014 Protected Branches",
463
+ label: "Branches a build turn must never push to (comma separated):",
464
+ value: doWorkProtectedBranches,
465
+ hint: `Type branches \xB7 Enter to continue \xB7 ${BACK}`
466
+ },
467
+ "do-work-claude-model": {
468
+ title: "Do Work \u2014 Claude Model",
469
+ label: "Default model when the executor is Claude (blank = the executor's own default):",
470
+ value: doWorkClaudeModel,
471
+ hint: `Type model \xB7 Enter to continue \xB7 ${BACK}`
472
+ },
473
+ "do-work-codex-model": {
474
+ title: "Do Work \u2014 Codex Model",
475
+ label: "Default model when the executor is Codex (blank = the executor's own default):",
476
+ value: doWorkCodexModel,
477
+ hint: `Type model \xB7 Enter to continue \xB7 ${BACK}`
478
+ },
479
+ "do-work-max-runs": {
480
+ title: "Do Work \u2014 Max Runs Per Tick",
481
+ label: "Model runs allowed per tick (0 = unlimited):",
482
+ value: doWorkMaxRuns,
483
+ hint: `Type a number \xB7 Enter to continue \xB7 ${BACK}`
484
+ },
485
+ "do-work-lock-stale": {
486
+ title: "Do Work \u2014 Lock Staleness",
487
+ label: "Minutes before a run lock from another host is treated as stale:",
488
+ value: doWorkLockStale,
489
+ hint: `Type a number \xB7 Enter to save \xB7 ${BACK}`
490
+ },
491
+ "do-work-discuss-prompt": {
492
+ title: "Prompts \u2014 Do Work \u2014 Discuss",
493
+ label: "Discussion turn instructions:",
494
+ value: doWorkDiscussPrompt,
495
+ hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
496
+ },
497
+ "do-work-pr-prompt": {
498
+ title: "Prompts \u2014 Do Work \u2014 PR",
499
+ label: "Pull request turn instructions:",
500
+ value: doWorkPrPrompt,
501
+ hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
502
+ }
503
+ };
504
+ const menuViews = {
505
+ main: {
506
+ title: "Configure Automata",
507
+ options: MAIN_MENU_OPTIONS,
508
+ index: mainMenuIndex,
509
+ hint: "\u2191/\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to cancel"
510
+ },
511
+ remote: {
512
+ title: "Remote / Mode",
513
+ options: REMOTE_OPTIONS.map((o) => o.label),
514
+ index: selectedRemoteIndex,
515
+ hint: `\u2191/\u2193 to move \xB7 Enter to confirm \xB7 ${BACK}`
516
+ },
517
+ technique: {
518
+ title: "Implement-Next \u2014 Issue Discovery Technique",
519
+ options: TECHNIQUE_OPTIONS.map((o) => o.label),
520
+ index: selectedTechIndex,
521
+ hint: `\u2191/\u2193 to move \xB7 Enter to confirm \xB7 ${BACK}`
522
+ },
523
+ "prompts-menu": {
524
+ title: "Prompts",
525
+ options: PROMPTS_MENU_OPTIONS,
526
+ index: promptsMenuIndex,
527
+ hint: `\u2191/\u2193 to move \xB7 Enter to edit \xB7 ${BACK}`
528
+ },
529
+ "do-work-executor": {
530
+ title: "Do Work \u2014 Executor",
531
+ options: EXECUTOR_OPTIONS.map((o) => o.label),
532
+ index: doWorkExecutorIndex,
533
+ hint: `\u2191/\u2193 to move \xB7 Enter to continue \xB7 ${BACK}`
534
+ }
535
+ };
536
+ const textView = textViews[screen];
537
+ if (textView) return /* @__PURE__ */ jsx(TextEntryScreen, { ...textView, error: validationError });
538
+ const menuView = menuViews[screen];
539
+ if (menuView) return /* @__PURE__ */ jsx(MenuEntryScreen, { ...menuView });
540
+ return null;
541
+ }
542
+ export {
543
+ ConfigWizard
544
+ };
@@ -7,6 +7,15 @@ var DEFAULT_CLAUDE_SYSTEM_PROMPT = "You are an expert software engineer. Impleme
7
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
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
9
  var DEFAULT_CHECK_ISSUE_PROMPT = "You are an expert software engineer working on a GitHub issue. Below is the conversation on that issue, restricted to the people allowed to instruct you and your own previous replies. Messages marked as new arrived after your last run: treat them as the current instruction and read the earlier messages only as context. Do what the new messages ask, following the project's existing conventions and style, and make minimal, targeted changes. Run tests and linting before finishing, then reply on the issue with a short summary of what you did.";
10
+ var DEFAULT_DO_WORK = {
11
+ baseBranch: "develop",
12
+ protectedBranches: ["main", "master"],
13
+ executor: "claude",
14
+ maxRunsPerTick: 0,
15
+ lockStaleMinutes: 120
16
+ };
17
+ var DEFAULT_DO_WORK_ISSUE_DISCUSS_PROMPT = "You are the agent named in the context below, working on a GitHub issue together with the people allowed to instruct you. Answer the messages marked NEW; the earlier messages are context only.\n\nDo not modify, create or delete any file, and do not create a branch or a pull request, UNLESS a message marked NEW explicitly asks you to implement the work. If it does: create a branch off the base branch named below, implement the change following the project's existing conventions, run the tests and the linter, and open a pull request whose body contains `Closes #<issue number>`.\n\nOtherwise do not touch the code at all: reply on the issue with the specification, the plan, or the open questions you need answered. Keep the reply short and concrete.\n\nEither way, always post a reply on the issue before you finish \u2014 including when you implemented and opened a pull request. Silence is indistinguishable from a crash, and the run will be reported as having produced no answer.";
18
+ var DEFAULT_DO_WORK_PR_WORK_PROMPT = "You are the agent named in the context below, working on the pull request for a GitHub issue together with the people allowed to instruct you. Work on the branch named below, which is already checked out and up to date.\n\nAddress every message marked NEW and every unresolved review thread listed. Follow the project's existing conventions, run the tests and the linter, then commit and push to that branch. Do not merge the pull request and do not push to the base branch.\n\nReply on the pull request with a short summary of what you changed, or reply in the review thread when your answer belongs to a specific comment. Always post a reply \u2014 silence looks like a crash.";
10
19
  var CONFIG_DIR = ".automata";
11
20
  var CONFIG_FILE = "config.json";
12
21
  function configPath() {
@@ -66,6 +75,12 @@ function readConfig() {
66
75
  if (config.prompts?.checkIssue) {
67
76
  config.prompts.checkIssue = resolvePromptRef(config.prompts.checkIssue, dir);
68
77
  }
78
+ if (config.doWork?.prompts?.issueDiscuss) {
79
+ config.doWork.prompts.issueDiscuss = resolvePromptRef(config.doWork.prompts.issueDiscuss, dir);
80
+ }
81
+ if (config.doWork?.prompts?.prWork) {
82
+ config.doWork.prompts.prWork = resolvePromptRef(config.doWork.prompts.prWork, dir);
83
+ }
69
84
  return config;
70
85
  }
71
86
  function writeConfig(config) {
@@ -79,6 +94,9 @@ export {
79
94
  DEFAULT_FIX_COMMENTS_PROMPT,
80
95
  DEFAULT_SONAR_PROMPT,
81
96
  DEFAULT_CHECK_ISSUE_PROMPT,
97
+ DEFAULT_DO_WORK,
98
+ DEFAULT_DO_WORK_ISSUE_DISCUSS_PROMPT,
99
+ DEFAULT_DO_WORK_PR_WORK_PROMPT,
82
100
  readRawConfig,
83
101
  readConfig,
84
102
  writeConfig