automata-cli 0.1.0-feature-030-do-work.194 → 0.1.0-feature-030-do-work.198
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/dist/ConfigWizard-NTK7NLAE.js +478 -0
- package/dist/index.js +78 -65
- package/package.json +1 -1
- package/dist/ConfigWizard-GN5JC4XP.js +0 -722
|
@@ -0,0 +1,478 @@
|
|
|
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-UA32XYYL.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 }) {
|
|
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
|
+
/* @__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 savePrompt(filename, content, merge) {
|
|
106
|
+
let value;
|
|
107
|
+
if (content) {
|
|
108
|
+
writePromptFile(filename, content);
|
|
109
|
+
value = filename;
|
|
110
|
+
}
|
|
111
|
+
writeConfig(merge(value, readRawConfig()));
|
|
112
|
+
}
|
|
113
|
+
var PROMPT_SCREEN_BY_OPTION = {
|
|
114
|
+
Sonar: "sonar-prompt",
|
|
115
|
+
"Fix-Comments": "fix-comments-prompt",
|
|
116
|
+
"Check-Issue": "check-issue-prompt",
|
|
117
|
+
"Do Work \u2014 Discuss": "do-work-discuss-prompt",
|
|
118
|
+
"Do Work \u2014 PR": "do-work-pr-prompt"
|
|
119
|
+
};
|
|
120
|
+
function ConfigWizard() {
|
|
121
|
+
const existing = readConfig();
|
|
122
|
+
const rawExisting = readRawConfig();
|
|
123
|
+
const initialRemoteIndex = REMOTE_OPTIONS.findIndex((o) => o.value === existing.remoteType);
|
|
124
|
+
const initialTechIndex = TECHNIQUE_OPTIONS.findIndex((o) => o.value === existing.issueDiscoveryTechnique);
|
|
125
|
+
const [screen, setScreen] = useState("main");
|
|
126
|
+
const [mainMenuIndex, setMainMenuIndex] = useState(0);
|
|
127
|
+
const [selectedRemoteIndex, setSelectedRemoteIndex] = useState(initialRemoteIndex >= 0 ? initialRemoteIndex : 0);
|
|
128
|
+
const [selectedTechIndex, setSelectedTechIndex] = useState(initialTechIndex >= 0 ? initialTechIndex : 0);
|
|
129
|
+
const [discoveryValue, setDiscoveryValue] = useState(existing.issueDiscoveryValue ?? "");
|
|
130
|
+
const [systemPrompt, setSystemPrompt] = useState(existing.claudeSystemPrompt ?? "");
|
|
131
|
+
const [promptsMenuIndex, setPromptsMenuIndex] = useState(0);
|
|
132
|
+
const [sonarPrompt, setSonarPrompt] = useState(existing.prompts?.sonar ?? DEFAULT_SONAR_PROMPT);
|
|
133
|
+
const [fixCommentsPrompt, setFixCommentsPrompt] = useState(
|
|
134
|
+
existing.prompts?.fixComments ?? DEFAULT_FIX_COMMENTS_PROMPT
|
|
135
|
+
);
|
|
136
|
+
const [checkIssuePrompt, setCheckIssuePrompt] = useState(existing.prompts?.checkIssue ?? DEFAULT_CHECK_ISSUE_PROMPT);
|
|
137
|
+
const [allowedUsers, setAllowedUsers] = useState((existing.allowedUsers ?? []).join(", "));
|
|
138
|
+
const [agentUser, setAgentUser] = useState(existing.agentUser ?? "");
|
|
139
|
+
const [doWorkBaseBranch, setDoWorkBaseBranch] = useState(
|
|
140
|
+
existing.doWork?.baseBranch ?? DEFAULT_DO_WORK.baseBranch
|
|
141
|
+
);
|
|
142
|
+
const initialExecutorIndex = EXECUTOR_OPTIONS.findIndex((o) => o.value === existing.doWork?.executor);
|
|
143
|
+
const [doWorkExecutorIndex, setDoWorkExecutorIndex] = useState(Math.max(initialExecutorIndex, 0));
|
|
144
|
+
const [doWorkClaudeModel, setDoWorkClaudeModel] = useState(existing.doWork?.models?.claude ?? "");
|
|
145
|
+
const [doWorkCodexModel, setDoWorkCodexModel] = useState(existing.doWork?.models?.codex ?? "");
|
|
146
|
+
const [doWorkMaxRuns, setDoWorkMaxRuns] = useState(
|
|
147
|
+
String(existing.doWork?.maxRunsPerTick ?? DEFAULT_DO_WORK.maxRunsPerTick)
|
|
148
|
+
);
|
|
149
|
+
const [doWorkDiscussPrompt, setDoWorkDiscussPrompt] = useState(
|
|
150
|
+
existing.doWork?.prompts?.issueDiscuss ?? DEFAULT_DO_WORK_ISSUE_DISCUSS_PROMPT
|
|
151
|
+
);
|
|
152
|
+
const [doWorkPrPrompt, setDoWorkPrPrompt] = useState(
|
|
153
|
+
existing.doWork?.prompts?.prWork ?? DEFAULT_DO_WORK_PR_WORK_PROMPT
|
|
154
|
+
);
|
|
155
|
+
const [pendingRemote, setPendingRemote] = useState(existing.remoteType ?? "gh");
|
|
156
|
+
const [pendingTechnique, setPendingTechnique] = useState(
|
|
157
|
+
existing.issueDiscoveryTechnique ?? "label"
|
|
158
|
+
);
|
|
159
|
+
const { exit } = useApp();
|
|
160
|
+
const textScreens = {
|
|
161
|
+
value: {
|
|
162
|
+
setValue: setDiscoveryValue,
|
|
163
|
+
onSubmit: () => setScreen("system-prompt"),
|
|
164
|
+
onBack: () => setScreen("main")
|
|
165
|
+
},
|
|
166
|
+
"system-prompt": {
|
|
167
|
+
setValue: setSystemPrompt,
|
|
168
|
+
onSubmit: () => {
|
|
169
|
+
let claudeSystemPromptValue;
|
|
170
|
+
if (systemPrompt) {
|
|
171
|
+
writePromptFile("claude-system-prompt.md", systemPrompt);
|
|
172
|
+
claudeSystemPromptValue = "claude-system-prompt.md";
|
|
173
|
+
}
|
|
174
|
+
writeConfig({
|
|
175
|
+
...rawExisting,
|
|
176
|
+
remoteType: pendingRemote,
|
|
177
|
+
issueDiscoveryTechnique: pendingTechnique,
|
|
178
|
+
issueDiscoveryValue: discoveryValue || void 0,
|
|
179
|
+
claudeSystemPrompt: claudeSystemPromptValue
|
|
180
|
+
});
|
|
181
|
+
exit();
|
|
182
|
+
},
|
|
183
|
+
onBack: () => setScreen("main")
|
|
184
|
+
},
|
|
185
|
+
"sonar-prompt": {
|
|
186
|
+
setValue: setSonarPrompt,
|
|
187
|
+
onSubmit: () => {
|
|
188
|
+
savePrompt("sonar-prompt.md", sonarPrompt, (value, current) => ({
|
|
189
|
+
...current,
|
|
190
|
+
prompts: { ...current.prompts, sonar: value }
|
|
191
|
+
}));
|
|
192
|
+
setScreen("prompts-menu");
|
|
193
|
+
},
|
|
194
|
+
onBack: () => setScreen("prompts-menu")
|
|
195
|
+
},
|
|
196
|
+
"fix-comments-prompt": {
|
|
197
|
+
setValue: setFixCommentsPrompt,
|
|
198
|
+
onSubmit: () => {
|
|
199
|
+
savePrompt("fix-comments-prompt.md", fixCommentsPrompt, (value, current) => ({
|
|
200
|
+
...current,
|
|
201
|
+
prompts: { ...current.prompts, fixComments: value }
|
|
202
|
+
}));
|
|
203
|
+
setScreen("prompts-menu");
|
|
204
|
+
},
|
|
205
|
+
onBack: () => setScreen("prompts-menu")
|
|
206
|
+
},
|
|
207
|
+
"check-issue-prompt": {
|
|
208
|
+
setValue: setCheckIssuePrompt,
|
|
209
|
+
onSubmit: () => {
|
|
210
|
+
savePrompt("check-issue-prompt.md", checkIssuePrompt, (value, current) => ({
|
|
211
|
+
...current,
|
|
212
|
+
prompts: { ...current.prompts, checkIssue: value }
|
|
213
|
+
}));
|
|
214
|
+
setScreen("prompts-menu");
|
|
215
|
+
},
|
|
216
|
+
onBack: () => setScreen("prompts-menu")
|
|
217
|
+
},
|
|
218
|
+
"allowed-users": {
|
|
219
|
+
setValue: setAllowedUsers,
|
|
220
|
+
onSubmit: () => setScreen("agent-user"),
|
|
221
|
+
onBack: () => setScreen("main")
|
|
222
|
+
},
|
|
223
|
+
"agent-user": {
|
|
224
|
+
setValue: setAgentUser,
|
|
225
|
+
onSubmit: () => {
|
|
226
|
+
const parsedUsers = parseAllowedUsers(allowedUsers);
|
|
227
|
+
const current = readRawConfig();
|
|
228
|
+
writeConfig({
|
|
229
|
+
...current,
|
|
230
|
+
allowedUsers: parsedUsers.length > 0 ? parsedUsers : void 0,
|
|
231
|
+
agentUser: agentUser.trim() || void 0
|
|
232
|
+
});
|
|
233
|
+
exit();
|
|
234
|
+
},
|
|
235
|
+
onBack: () => setScreen("allowed-users")
|
|
236
|
+
},
|
|
237
|
+
"do-work-base-branch": {
|
|
238
|
+
setValue: setDoWorkBaseBranch,
|
|
239
|
+
onSubmit: () => setScreen("do-work-executor"),
|
|
240
|
+
onBack: () => setScreen("main")
|
|
241
|
+
},
|
|
242
|
+
"do-work-claude-model": {
|
|
243
|
+
setValue: setDoWorkClaudeModel,
|
|
244
|
+
onSubmit: () => setScreen("do-work-codex-model"),
|
|
245
|
+
onBack: () => setScreen("do-work-executor")
|
|
246
|
+
},
|
|
247
|
+
"do-work-codex-model": {
|
|
248
|
+
setValue: setDoWorkCodexModel,
|
|
249
|
+
onSubmit: () => setScreen("do-work-max-runs"),
|
|
250
|
+
onBack: () => setScreen("do-work-claude-model")
|
|
251
|
+
},
|
|
252
|
+
"do-work-max-runs": {
|
|
253
|
+
setValue: setDoWorkMaxRuns,
|
|
254
|
+
onSubmit: () => {
|
|
255
|
+
const parsedMaxRuns = Number.parseInt(doWorkMaxRuns, 10);
|
|
256
|
+
const current = readRawConfig();
|
|
257
|
+
writeConfig({
|
|
258
|
+
...current,
|
|
259
|
+
doWork: {
|
|
260
|
+
...current.doWork,
|
|
261
|
+
baseBranch: doWorkBaseBranch.trim() || void 0,
|
|
262
|
+
executor: EXECUTOR_OPTIONS[doWorkExecutorIndex].value,
|
|
263
|
+
models: {
|
|
264
|
+
claude: doWorkClaudeModel.trim() || void 0,
|
|
265
|
+
codex: doWorkCodexModel.trim() || void 0
|
|
266
|
+
},
|
|
267
|
+
maxRunsPerTick: Number.isNaN(parsedMaxRuns) || parsedMaxRuns < 0 ? void 0 : parsedMaxRuns
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
exit();
|
|
271
|
+
},
|
|
272
|
+
onBack: () => setScreen("do-work-codex-model")
|
|
273
|
+
},
|
|
274
|
+
"do-work-discuss-prompt": {
|
|
275
|
+
setValue: setDoWorkDiscussPrompt,
|
|
276
|
+
onSubmit: () => {
|
|
277
|
+
savePrompt("do-work-issue-discuss.md", doWorkDiscussPrompt, (value, current) => ({
|
|
278
|
+
...current,
|
|
279
|
+
doWork: { ...current.doWork, prompts: { ...current.doWork?.prompts, issueDiscuss: value } }
|
|
280
|
+
}));
|
|
281
|
+
setScreen("prompts-menu");
|
|
282
|
+
},
|
|
283
|
+
onBack: () => setScreen("prompts-menu")
|
|
284
|
+
},
|
|
285
|
+
"do-work-pr-prompt": {
|
|
286
|
+
setValue: setDoWorkPrPrompt,
|
|
287
|
+
onSubmit: () => {
|
|
288
|
+
savePrompt("do-work-pr-work.md", doWorkPrPrompt, (value, current) => ({
|
|
289
|
+
...current,
|
|
290
|
+
doWork: { ...current.doWork, prompts: { ...current.doWork?.prompts, prWork: value } }
|
|
291
|
+
}));
|
|
292
|
+
setScreen("prompts-menu");
|
|
293
|
+
},
|
|
294
|
+
onBack: () => setScreen("prompts-menu")
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
const menus = {
|
|
298
|
+
main: {
|
|
299
|
+
index: mainMenuIndex,
|
|
300
|
+
length: MAIN_MENU_OPTIONS.length,
|
|
301
|
+
setIndex: setMainMenuIndex,
|
|
302
|
+
onSelect: () => {
|
|
303
|
+
const chosen = MAIN_MENU_OPTIONS[mainMenuIndex];
|
|
304
|
+
if (chosen === "Remote / Mode") setScreen("remote");
|
|
305
|
+
else if (chosen === "Implement-Next") setScreen("technique");
|
|
306
|
+
else if (chosen === "Issue Watch") setScreen("allowed-users");
|
|
307
|
+
else if (chosen === "Do Work") setScreen("do-work-base-branch");
|
|
308
|
+
else setScreen("prompts-menu");
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
remote: {
|
|
312
|
+
index: selectedRemoteIndex,
|
|
313
|
+
length: REMOTE_OPTIONS.length,
|
|
314
|
+
setIndex: setSelectedRemoteIndex,
|
|
315
|
+
onSelect: () => {
|
|
316
|
+
setPendingRemote(REMOTE_OPTIONS[selectedRemoteIndex].value);
|
|
317
|
+
setScreen("technique");
|
|
318
|
+
},
|
|
319
|
+
onBack: () => setScreen("main")
|
|
320
|
+
},
|
|
321
|
+
technique: {
|
|
322
|
+
index: selectedTechIndex,
|
|
323
|
+
length: TECHNIQUE_OPTIONS.length,
|
|
324
|
+
setIndex: setSelectedTechIndex,
|
|
325
|
+
onSelect: () => {
|
|
326
|
+
setPendingTechnique(TECHNIQUE_OPTIONS[selectedTechIndex].value);
|
|
327
|
+
setScreen("value");
|
|
328
|
+
},
|
|
329
|
+
onBack: () => setScreen("main")
|
|
330
|
+
},
|
|
331
|
+
"prompts-menu": {
|
|
332
|
+
index: promptsMenuIndex,
|
|
333
|
+
length: PROMPTS_MENU_OPTIONS.length,
|
|
334
|
+
setIndex: setPromptsMenuIndex,
|
|
335
|
+
onSelect: () => setScreen(PROMPT_SCREEN_BY_OPTION[PROMPTS_MENU_OPTIONS[promptsMenuIndex]]),
|
|
336
|
+
onBack: () => setScreen("main")
|
|
337
|
+
},
|
|
338
|
+
"do-work-executor": {
|
|
339
|
+
index: doWorkExecutorIndex,
|
|
340
|
+
length: EXECUTOR_OPTIONS.length,
|
|
341
|
+
setIndex: setDoWorkExecutorIndex,
|
|
342
|
+
onSelect: () => setScreen("do-work-claude-model"),
|
|
343
|
+
onBack: () => setScreen("do-work-base-branch")
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
useInput((input, key) => {
|
|
347
|
+
const textScreen = textScreens[screen];
|
|
348
|
+
if (textScreen) {
|
|
349
|
+
handleTextEntry(input, key, textScreen, exit);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const menu = menus[screen];
|
|
353
|
+
if (menu) {
|
|
354
|
+
handleMenu(input, key, menu, exit);
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
const techLabel = TECHNIQUE_OPTIONS.find((o) => o.value === pendingTechnique)?.label ?? pendingTechnique;
|
|
358
|
+
const textViews = {
|
|
359
|
+
value: {
|
|
360
|
+
title: "Implement-Next \u2014 Issue Discovery Value",
|
|
361
|
+
label: `${techLabel} value:`,
|
|
362
|
+
value: discoveryValue,
|
|
363
|
+
hint: `Type value \xB7 Enter to continue \xB7 ${BACK}`
|
|
364
|
+
},
|
|
365
|
+
"system-prompt": {
|
|
366
|
+
title: "Implement-Next \u2014 Claude System Prompt",
|
|
367
|
+
label: "System prompt (optional):",
|
|
368
|
+
value: systemPrompt,
|
|
369
|
+
hint: `Type prompt \xB7 Enter to save and exit \xB7 ${BACK}`
|
|
370
|
+
},
|
|
371
|
+
"sonar-prompt": {
|
|
372
|
+
title: "Prompts \u2014 Sonar",
|
|
373
|
+
label: "Sonar prompt:",
|
|
374
|
+
value: sonarPrompt,
|
|
375
|
+
hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
|
|
376
|
+
},
|
|
377
|
+
"fix-comments-prompt": {
|
|
378
|
+
title: "Prompts \u2014 Fix-Comments",
|
|
379
|
+
label: "Fix-Comments prompt:",
|
|
380
|
+
value: fixCommentsPrompt,
|
|
381
|
+
hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
|
|
382
|
+
},
|
|
383
|
+
"check-issue-prompt": {
|
|
384
|
+
title: "Prompts \u2014 Check-Issue",
|
|
385
|
+
label: "Check-Issue prompt:",
|
|
386
|
+
value: checkIssuePrompt,
|
|
387
|
+
hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
|
|
388
|
+
},
|
|
389
|
+
"allowed-users": {
|
|
390
|
+
title: "Issue Watch \u2014 Allowed Users",
|
|
391
|
+
label: "Logins allowed to instruct the agent (comma separated):",
|
|
392
|
+
value: allowedUsers,
|
|
393
|
+
hint: `Type logins \xB7 Enter to continue \xB7 ${BACK}`
|
|
394
|
+
},
|
|
395
|
+
"agent-user": {
|
|
396
|
+
title: "Issue Watch \u2014 Agent User",
|
|
397
|
+
label: "Login the agent posts as:",
|
|
398
|
+
value: agentUser,
|
|
399
|
+
hint: `Type login \xB7 Enter to save and exit \xB7 ${BACK}`
|
|
400
|
+
},
|
|
401
|
+
"do-work-base-branch": {
|
|
402
|
+
title: "Do Work \u2014 Base Branch",
|
|
403
|
+
label: "Branch discussion turns return to:",
|
|
404
|
+
value: doWorkBaseBranch,
|
|
405
|
+
hint: `Type branch \xB7 Enter to continue \xB7 ${BACK}`
|
|
406
|
+
},
|
|
407
|
+
"do-work-claude-model": {
|
|
408
|
+
title: "Do Work \u2014 Claude Model",
|
|
409
|
+
label: "Default model when the executor is Claude (blank = the executor's own default):",
|
|
410
|
+
value: doWorkClaudeModel,
|
|
411
|
+
hint: `Type model \xB7 Enter to continue \xB7 ${BACK}`
|
|
412
|
+
},
|
|
413
|
+
"do-work-codex-model": {
|
|
414
|
+
title: "Do Work \u2014 Codex Model",
|
|
415
|
+
label: "Default model when the executor is Codex (blank = the executor's own default):",
|
|
416
|
+
value: doWorkCodexModel,
|
|
417
|
+
hint: `Type model \xB7 Enter to continue \xB7 ${BACK}`
|
|
418
|
+
},
|
|
419
|
+
"do-work-max-runs": {
|
|
420
|
+
title: "Do Work \u2014 Max Runs Per Tick",
|
|
421
|
+
label: "Model runs allowed per tick (0 = unlimited):",
|
|
422
|
+
value: doWorkMaxRuns,
|
|
423
|
+
hint: `Type a number \xB7 Enter to save \xB7 ${BACK}`
|
|
424
|
+
},
|
|
425
|
+
"do-work-discuss-prompt": {
|
|
426
|
+
title: "Prompts \u2014 Do Work \u2014 Discuss",
|
|
427
|
+
label: "Discussion turn instructions:",
|
|
428
|
+
value: doWorkDiscussPrompt,
|
|
429
|
+
hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
|
|
430
|
+
},
|
|
431
|
+
"do-work-pr-prompt": {
|
|
432
|
+
title: "Prompts \u2014 Do Work \u2014 PR",
|
|
433
|
+
label: "Pull request turn instructions:",
|
|
434
|
+
value: doWorkPrPrompt,
|
|
435
|
+
hint: `Type prompt \xB7 Enter to save \xB7 ${BACK}`
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
const menuViews = {
|
|
439
|
+
main: {
|
|
440
|
+
title: "Configure Automata",
|
|
441
|
+
options: MAIN_MENU_OPTIONS,
|
|
442
|
+
index: mainMenuIndex,
|
|
443
|
+
hint: "\u2191/\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to cancel"
|
|
444
|
+
},
|
|
445
|
+
remote: {
|
|
446
|
+
title: "Remote / Mode",
|
|
447
|
+
options: REMOTE_OPTIONS.map((o) => o.label),
|
|
448
|
+
index: selectedRemoteIndex,
|
|
449
|
+
hint: `\u2191/\u2193 to move \xB7 Enter to confirm \xB7 ${BACK}`
|
|
450
|
+
},
|
|
451
|
+
technique: {
|
|
452
|
+
title: "Implement-Next \u2014 Issue Discovery Technique",
|
|
453
|
+
options: TECHNIQUE_OPTIONS.map((o) => o.label),
|
|
454
|
+
index: selectedTechIndex,
|
|
455
|
+
hint: `\u2191/\u2193 to move \xB7 Enter to confirm \xB7 ${BACK}`
|
|
456
|
+
},
|
|
457
|
+
"prompts-menu": {
|
|
458
|
+
title: "Prompts",
|
|
459
|
+
options: PROMPTS_MENU_OPTIONS,
|
|
460
|
+
index: promptsMenuIndex,
|
|
461
|
+
hint: `\u2191/\u2193 to move \xB7 Enter to edit \xB7 ${BACK}`
|
|
462
|
+
},
|
|
463
|
+
"do-work-executor": {
|
|
464
|
+
title: "Do Work \u2014 Executor",
|
|
465
|
+
options: EXECUTOR_OPTIONS.map((o) => o.label),
|
|
466
|
+
index: doWorkExecutorIndex,
|
|
467
|
+
hint: `\u2191/\u2193 to move \xB7 Enter to continue \xB7 ${BACK}`
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
const textView = textViews[screen];
|
|
471
|
+
if (textView) return /* @__PURE__ */ jsx(TextEntryScreen, { ...textView });
|
|
472
|
+
const menuView = menuViews[screen];
|
|
473
|
+
if (menuView) return /* @__PURE__ */ jsx(MenuEntryScreen, { ...menuView });
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
export {
|
|
477
|
+
ConfigWizard
|
|
478
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -183,7 +183,7 @@ var configCommand = new Command("config").description("Configure automata settin
|
|
|
183
183
|
const [{ render }, React, { ConfigWizard }] = await Promise.all([
|
|
184
184
|
import("ink"),
|
|
185
185
|
import("react"),
|
|
186
|
-
import("./ConfigWizard-
|
|
186
|
+
import("./ConfigWizard-NTK7NLAE.js")
|
|
187
187
|
]);
|
|
188
188
|
const { waitUntilExit } = render(React.createElement(ConfigWizard));
|
|
189
189
|
await waitUntilExit();
|
|
@@ -1483,9 +1483,11 @@ import { existsSync } from "fs";
|
|
|
1483
1483
|
import { delimiter, join } from "path";
|
|
1484
1484
|
|
|
1485
1485
|
// src/cli/spawnUtils.ts
|
|
1486
|
+
var SHELL_SAFE = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
1487
|
+
var ESCAPED_QUOTE = String.raw`'\''`;
|
|
1486
1488
|
function shellQuote(arg) {
|
|
1487
|
-
if (
|
|
1488
|
-
return
|
|
1489
|
+
if (SHELL_SAFE.test(arg)) return arg;
|
|
1490
|
+
return "'" + arg.replaceAll("'", ESCAPED_QUOTE) + "'";
|
|
1489
1491
|
}
|
|
1490
1492
|
function truncate(str, max) {
|
|
1491
1493
|
return str.length > max ? str.slice(0, max) + "..." : str;
|
|
@@ -2353,6 +2355,31 @@ query($owner:String!,$repo:String!,$cursor:String){
|
|
|
2353
2355
|
}
|
|
2354
2356
|
}`.trim();
|
|
2355
2357
|
var MAX_LINK_MAP_PAGES = 50;
|
|
2358
|
+
function indexPullRequest(map, node) {
|
|
2359
|
+
const ref = {
|
|
2360
|
+
number: node.number,
|
|
2361
|
+
url: node.url,
|
|
2362
|
+
title: node.title,
|
|
2363
|
+
headRefName: node.headRefName,
|
|
2364
|
+
state: "OPEN",
|
|
2365
|
+
isDraft: node.isDraft,
|
|
2366
|
+
updatedAt: node.updatedAt
|
|
2367
|
+
};
|
|
2368
|
+
if (node.closingIssuesReferences.pageInfo?.hasNextPage) {
|
|
2369
|
+
process.stderr.write(
|
|
2370
|
+
`Warning: pull request #${String(node.number)} closes more than 50 issues; some links were not read.
|
|
2371
|
+
`
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
for (const issue of node.closingIssuesReferences.nodes) {
|
|
2375
|
+
const existing = map.get(issue.number);
|
|
2376
|
+
if (existing) {
|
|
2377
|
+
existing.push(ref);
|
|
2378
|
+
} else {
|
|
2379
|
+
map.set(issue.number, [ref]);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2356
2383
|
function getOpenPrLinkMap() {
|
|
2357
2384
|
const { owner, repo } = getRepoSlug();
|
|
2358
2385
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -2363,29 +2390,7 @@ function getOpenPrLinkMap() {
|
|
|
2363
2390
|
const response = ghJson(args, "query open pull requests");
|
|
2364
2391
|
const connection = response.data.repository.pullRequests;
|
|
2365
2392
|
for (const node of connection.nodes) {
|
|
2366
|
-
|
|
2367
|
-
number: node.number,
|
|
2368
|
-
url: node.url,
|
|
2369
|
-
title: node.title,
|
|
2370
|
-
headRefName: node.headRefName,
|
|
2371
|
-
state: "OPEN",
|
|
2372
|
-
isDraft: node.isDraft,
|
|
2373
|
-
updatedAt: node.updatedAt
|
|
2374
|
-
};
|
|
2375
|
-
if (node.closingIssuesReferences.pageInfo?.hasNextPage) {
|
|
2376
|
-
process.stderr.write(
|
|
2377
|
-
`Warning: pull request #${String(node.number)} closes more than 50 issues; some links were not read.
|
|
2378
|
-
`
|
|
2379
|
-
);
|
|
2380
|
-
}
|
|
2381
|
-
for (const issue of node.closingIssuesReferences.nodes) {
|
|
2382
|
-
const existing = map.get(issue.number);
|
|
2383
|
-
if (existing) {
|
|
2384
|
-
existing.push(ref);
|
|
2385
|
-
} else {
|
|
2386
|
-
map.set(issue.number, [ref]);
|
|
2387
|
-
}
|
|
2388
|
-
}
|
|
2393
|
+
indexPullRequest(map, node);
|
|
2389
2394
|
}
|
|
2390
2395
|
if (!connection.pageInfo?.hasNextPage || connection.pageInfo.endCursor === null) {
|
|
2391
2396
|
return map;
|
|
@@ -2979,17 +2984,21 @@ function planRun(item, settings, silent) {
|
|
|
2979
2984
|
}
|
|
2980
2985
|
function describePlannedRun(item, settings, run5) {
|
|
2981
2986
|
const rule = "\u2500".repeat(72);
|
|
2987
|
+
const branchAction = item.turn === "pr-work" ? " and fast-forward" : " and pull";
|
|
2988
|
+
const assignment = item.needsAssignment ? `would assign to ${settings.participants.agentUser}` : "already assigned";
|
|
2989
|
+
const markerTarget = item.turn === "pr-work" && item.pr ? `pull request #${String(item.pr.number)}` : `issue #${String(item.issue.number)}`;
|
|
2990
|
+
const modelNote = settings.model === void 0 ? " (no model override)" : ` \xB7 model ${settings.model}`;
|
|
2982
2991
|
const lines = [
|
|
2983
2992
|
rule,
|
|
2984
2993
|
`Issue #${String(item.issue.number)} \u2014 ${item.issue.title}`,
|
|
2985
2994
|
rule,
|
|
2986
2995
|
` Turn ${item.turn}`,
|
|
2987
2996
|
` Why ${item.reason}`,
|
|
2988
|
-
` Branch ${item.branch} (would check out${
|
|
2989
|
-
` Assign ${
|
|
2990
|
-
` Marker would post on ${
|
|
2991
|
-
` Executor ${settings.executor}${
|
|
2992
|
-
|
|
2997
|
+
` Branch ${item.branch} (would check out${branchAction})`,
|
|
2998
|
+
` Assign ${assignment}`,
|
|
2999
|
+
` Marker would post on ${markerTarget}`,
|
|
3000
|
+
` Executor ${settings.executor}${modelNote}`,
|
|
3001
|
+
" Permissions bypassed (do-work always runs unattended)",
|
|
2993
3002
|
` Prompt ${String(run5.prompt.length)} chars \u2014 frame + assembled context`,
|
|
2994
3003
|
"",
|
|
2995
3004
|
" Command that would be launched:",
|
|
@@ -3238,40 +3247,7 @@ ${describePlan(decisions)}`;
|
|
|
3238
3247
|
out(planText);
|
|
3239
3248
|
}
|
|
3240
3249
|
if (options.dryRun) {
|
|
3241
|
-
|
|
3242
|
-
const planned = runnableInPlan.map((item) => planRun(item, settings, options.silent === true));
|
|
3243
|
-
if (options.json) {
|
|
3244
|
-
out(
|
|
3245
|
-
JSON.stringify(
|
|
3246
|
-
{
|
|
3247
|
-
dryRun: true,
|
|
3248
|
-
plan: decisions.map(toPlanJson),
|
|
3249
|
-
runs: planned.map((run5, index) => ({
|
|
3250
|
-
issue: runnableInPlan[index].issue.number,
|
|
3251
|
-
turn: runnableInPlan[index].turn,
|
|
3252
|
-
executor: settings.executor,
|
|
3253
|
-
model: settings.model ?? null,
|
|
3254
|
-
bin: run5.bin,
|
|
3255
|
-
args: run5.args,
|
|
3256
|
-
command: run5.command,
|
|
3257
|
-
prompt: run5.prompt
|
|
3258
|
-
}))
|
|
3259
|
-
},
|
|
3260
|
-
null,
|
|
3261
|
-
2
|
|
3262
|
-
) + "\n"
|
|
3263
|
-
);
|
|
3264
|
-
return 0;
|
|
3265
|
-
}
|
|
3266
|
-
for (const [index, run5] of planned.entries()) {
|
|
3267
|
-
out("\n" + describePlannedRun(runnableInPlan[index], settings, run5));
|
|
3268
|
-
}
|
|
3269
|
-
if (items.length > runnableInPlan.length) {
|
|
3270
|
-
out(`
|
|
3271
|
-
(${String(items.length - runnableInPlan.length)} further item(s) deferred by the run cap.)
|
|
3272
|
-
`);
|
|
3273
|
-
}
|
|
3274
|
-
out("\nDry run: nothing was assigned, posted, checked out or executed.\n");
|
|
3250
|
+
reportDryRun(items, decisions, settings, options);
|
|
3275
3251
|
return 0;
|
|
3276
3252
|
}
|
|
3277
3253
|
const runnable = settings.maxRuns > 0 ? items.slice(0, settings.maxRuns) : items;
|
|
@@ -3301,6 +3277,43 @@ ${describePlan(decisions)}`;
|
|
|
3301
3277
|
}
|
|
3302
3278
|
return exitCode;
|
|
3303
3279
|
}
|
|
3280
|
+
function reportDryRun(items, decisions, settings, options) {
|
|
3281
|
+
const describable = settings.maxRuns > 0 ? items.slice(0, settings.maxRuns) : items;
|
|
3282
|
+
const planned = describable.map((item) => planRun(item, settings, options.silent === true));
|
|
3283
|
+
if (options.json) {
|
|
3284
|
+
out(
|
|
3285
|
+
JSON.stringify(
|
|
3286
|
+
{
|
|
3287
|
+
dryRun: true,
|
|
3288
|
+
plan: decisions.map(toPlanJson),
|
|
3289
|
+
runs: planned.map((run5, index) => ({
|
|
3290
|
+
issue: describable[index].issue.number,
|
|
3291
|
+
turn: describable[index].turn,
|
|
3292
|
+
executor: settings.executor,
|
|
3293
|
+
model: settings.model ?? null,
|
|
3294
|
+
bin: run5.bin,
|
|
3295
|
+
args: run5.args,
|
|
3296
|
+
command: run5.command,
|
|
3297
|
+
prompt: run5.prompt
|
|
3298
|
+
}))
|
|
3299
|
+
},
|
|
3300
|
+
null,
|
|
3301
|
+
2
|
|
3302
|
+
) + "\n"
|
|
3303
|
+
);
|
|
3304
|
+
return;
|
|
3305
|
+
}
|
|
3306
|
+
for (const [index, run5] of planned.entries()) {
|
|
3307
|
+
out("\n" + describePlannedRun(describable[index], settings, run5));
|
|
3308
|
+
}
|
|
3309
|
+
const deferred = items.length - describable.length;
|
|
3310
|
+
if (deferred > 0) {
|
|
3311
|
+
out(`
|
|
3312
|
+
(${String(deferred)} further item(s) deferred by the run cap.)
|
|
3313
|
+
`);
|
|
3314
|
+
}
|
|
3315
|
+
out("\nDry run: nothing was assigned, posted, checked out or executed.\n");
|
|
3316
|
+
}
|
|
3304
3317
|
function toPlanJson(decision) {
|
|
3305
3318
|
if (decision.kind === "skip") {
|
|
3306
3319
|
return {
|