automata-cli 0.3.0-develop.59 → 0.3.0-develop.77
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/index.js +193 -24
- package/package.json +1 -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
|
|
4
|
+
import { Command as Command5 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/version.ts
|
|
7
7
|
import { readFileSync } from "fs";
|
|
@@ -876,9 +876,6 @@ var gitCommand = new Command2("git").description("Git workflow commands (some re
|
|
|
876
876
|
|
|
877
877
|
// src/commands/getReady.ts
|
|
878
878
|
import { Command as Command3 } from "commander";
|
|
879
|
-
import { spawnSync as spawnSync4 } from "child_process";
|
|
880
|
-
import { existsSync } from "fs";
|
|
881
|
-
import { delimiter, join as join2 } from "path";
|
|
882
879
|
|
|
883
880
|
// src/config/githubService.ts
|
|
884
881
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
@@ -937,7 +934,42 @@ function postComment(issueNumber, body) {
|
|
|
937
934
|
}
|
|
938
935
|
}
|
|
939
936
|
|
|
940
|
-
// src/
|
|
937
|
+
// src/claude/claudeService.ts
|
|
938
|
+
import { spawn, spawnSync as spawnSync4 } from "child_process";
|
|
939
|
+
import { createInterface } from "readline";
|
|
940
|
+
import { existsSync } from "fs";
|
|
941
|
+
import { delimiter, join as join2 } from "path";
|
|
942
|
+
|
|
943
|
+
// src/cli/spawnUtils.ts
|
|
944
|
+
function truncate(str, max) {
|
|
945
|
+
return str.length > max ? str.slice(0, max) + "..." : str;
|
|
946
|
+
}
|
|
947
|
+
function handleSpawnError(error, toolName) {
|
|
948
|
+
if (!error) return;
|
|
949
|
+
const err = error;
|
|
950
|
+
if (err.code === "ENOENT") {
|
|
951
|
+
process.stderr.write(`Error: \`${toolName}\` CLI is not installed or not on PATH.
|
|
952
|
+
`);
|
|
953
|
+
process.exit(1);
|
|
954
|
+
}
|
|
955
|
+
process.stderr.write(`Error: ${err.message}
|
|
956
|
+
`);
|
|
957
|
+
process.exit(1);
|
|
958
|
+
}
|
|
959
|
+
function handleExitCode(status, toolName) {
|
|
960
|
+
if (status === null) {
|
|
961
|
+
process.stderr.write(`Error: ${toolName} terminated abnormally (exit code is null, likely due to a signal).
|
|
962
|
+
`);
|
|
963
|
+
process.exit(1);
|
|
964
|
+
}
|
|
965
|
+
if (status !== 0) {
|
|
966
|
+
process.stderr.write(`Error: ${toolName} exited with code ${status}.
|
|
967
|
+
`);
|
|
968
|
+
process.exit(status);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// src/claude/claudeService.ts
|
|
941
973
|
function resolveCommand(name) {
|
|
942
974
|
const pathDirs = (process.env["PATH"] ?? "").split(delimiter);
|
|
943
975
|
for (const dir of pathDirs) {
|
|
@@ -946,30 +978,147 @@ function resolveCommand(name) {
|
|
|
946
978
|
}
|
|
947
979
|
return name;
|
|
948
980
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
981
|
+
var MODEL_IDS = {
|
|
982
|
+
opus: "claude-opus-4-6",
|
|
983
|
+
sonnet: "claude-sonnet-4-6",
|
|
984
|
+
haiku: "claude-haiku-4-5-20251001"
|
|
985
|
+
};
|
|
986
|
+
function resolveModelOption(opts) {
|
|
987
|
+
const selected = ["opus", "sonnet", "haiku"].filter((m) => opts[m]);
|
|
988
|
+
if (selected.length > 1) {
|
|
989
|
+
process.stderr.write(`Error: --${selected[0]} and --${selected[1]} are mutually exclusive.
|
|
990
|
+
`);
|
|
991
|
+
process.exit(1);
|
|
992
|
+
}
|
|
993
|
+
return selected.length === 1 ? MODEL_IDS[selected[0]] : void 0;
|
|
994
|
+
}
|
|
995
|
+
function invokeClaudeCode(prompt, options = {}) {
|
|
996
|
+
if (options.verbose) {
|
|
997
|
+
return invokeClaudeCodeVerbose(prompt, options.yolo ?? false, options.model);
|
|
998
|
+
}
|
|
999
|
+
invokeClaudeCodeSync(prompt, options.yolo ?? false, options.model);
|
|
1000
|
+
}
|
|
1001
|
+
function invokeClaudeCodeSync(prompt, yolo, model) {
|
|
953
1002
|
const claudeBin = resolveCommand("claude");
|
|
954
|
-
const args =
|
|
1003
|
+
const args = [];
|
|
1004
|
+
if (yolo) args.push("--dangerously-skip-permissions");
|
|
1005
|
+
if (model) args.push("--model", model);
|
|
1006
|
+
args.push("-p", prompt);
|
|
955
1007
|
const result = spawnSync4(claudeBin, args, { encoding: "utf8", stdio: "inherit" });
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1008
|
+
handleSpawnError(result.error, "claude");
|
|
1009
|
+
handleExitCode(result.status, "Claude Code");
|
|
1010
|
+
}
|
|
1011
|
+
function invokeClaudeCodeVerbose(prompt, yolo, model) {
|
|
1012
|
+
return new Promise((resolve2) => {
|
|
1013
|
+
const claudeBin = resolveCommand("claude");
|
|
1014
|
+
const args = [];
|
|
1015
|
+
if (yolo) args.push("--dangerously-skip-permissions");
|
|
1016
|
+
if (model) args.push("--model", model);
|
|
1017
|
+
args.push("--verbose", "--output-format", "stream-json", "-p", prompt);
|
|
1018
|
+
const child = spawn(claudeBin, args, { stdio: ["inherit", "pipe", "inherit"] });
|
|
1019
|
+
const rl = createInterface({ input: child.stdout });
|
|
1020
|
+
let turnCount = 0;
|
|
1021
|
+
child.on("error", (err) => {
|
|
1022
|
+
handleSpawnError(err, "claude");
|
|
1023
|
+
});
|
|
1024
|
+
rl.on("line", (line) => {
|
|
1025
|
+
try {
|
|
1026
|
+
const event = JSON.parse(line);
|
|
1027
|
+
formatEvent(event, turnCount);
|
|
1028
|
+
if (event["type"] === "assistant") turnCount++;
|
|
1029
|
+
} catch {
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
child.on("close", (code) => {
|
|
1033
|
+
handleExitCode(code, "Claude Code");
|
|
1034
|
+
resolve2();
|
|
1035
|
+
});
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
function formatEvent(event, turnCount) {
|
|
1039
|
+
const type = event["type"];
|
|
1040
|
+
if (type === "assistant") {
|
|
1041
|
+
const message = event["message"];
|
|
1042
|
+
const content = message?.["content"];
|
|
1043
|
+
if (!content) return;
|
|
1044
|
+
for (const block of content) {
|
|
1045
|
+
if (block["type"] === "tool_use") {
|
|
1046
|
+
const toolName = block["name"];
|
|
1047
|
+
const input = block["input"];
|
|
1048
|
+
const summary = summarizeTool(toolName, input);
|
|
1049
|
+
process.stderr.write(` [step ${turnCount + 1}] ${summary}
|
|
1050
|
+
`);
|
|
1051
|
+
} else if (block["type"] === "text") {
|
|
1052
|
+
const text = block["text"] ?? "";
|
|
1053
|
+
if (text.length > 0) {
|
|
1054
|
+
const preview = text.length > 120 ? text.slice(0, 120) + "..." : text;
|
|
1055
|
+
const firstLine = preview.split("\n")[0];
|
|
1056
|
+
process.stderr.write(` [step ${turnCount + 1}] ${firstLine}
|
|
1057
|
+
`);
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
961
1060
|
}
|
|
962
|
-
|
|
1061
|
+
} else if (type === "result") {
|
|
1062
|
+
const result = event["result"];
|
|
1063
|
+
const cost = event["cost_usd"];
|
|
1064
|
+
const duration = event["duration_ms"];
|
|
1065
|
+
const turns = event["num_turns"];
|
|
1066
|
+
process.stderr.write("\n--- Result ---\n");
|
|
1067
|
+
if (cost !== void 0 || duration !== void 0 || turns !== void 0) {
|
|
1068
|
+
const parts = [];
|
|
1069
|
+
if (turns !== void 0) parts.push(`${turns} turns`);
|
|
1070
|
+
if (duration !== void 0) parts.push(`${(duration / 1e3).toFixed(1)}s`);
|
|
1071
|
+
if (cost !== void 0) parts.push(`$${cost.toFixed(4)}`);
|
|
1072
|
+
process.stderr.write(` [info] ${parts.join(" | ")}
|
|
963
1073
|
`);
|
|
964
|
-
|
|
1074
|
+
}
|
|
1075
|
+
if (result) {
|
|
1076
|
+
process.stdout.write(result + "\n");
|
|
1077
|
+
}
|
|
965
1078
|
}
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
`
|
|
969
|
-
|
|
1079
|
+
}
|
|
1080
|
+
function summarizeTool(name, input) {
|
|
1081
|
+
if (!input) return `tool: ${name}`;
|
|
1082
|
+
switch (name) {
|
|
1083
|
+
case "Read":
|
|
1084
|
+
return `reading ${input["file_path"] ?? "file"}`;
|
|
1085
|
+
case "Write":
|
|
1086
|
+
return `writing ${input["file_path"] ?? "file"}`;
|
|
1087
|
+
case "Edit":
|
|
1088
|
+
return `editing ${input["file_path"] ?? "file"}`;
|
|
1089
|
+
case "Bash":
|
|
1090
|
+
return `running: ${truncate(String(input["command"] ?? ""), 80)}`;
|
|
1091
|
+
case "Glob":
|
|
1092
|
+
return `searching files: ${input["pattern"] ?? ""}`;
|
|
1093
|
+
case "Grep":
|
|
1094
|
+
return `searching content: ${truncate(String(input["pattern"] ?? ""), 60)}`;
|
|
1095
|
+
case "Agent":
|
|
1096
|
+
return `spawning agent: ${input["description"] ?? name}`;
|
|
1097
|
+
default:
|
|
1098
|
+
return `tool: ${name}`;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// src/codex/codexService.ts
|
|
1103
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
1104
|
+
function invokeCodexCode(prompt, options = {}) {
|
|
1105
|
+
if (options.verbose) {
|
|
1106
|
+
process.stderr.write("Warning: --verbose is not supported for Codex and will be ignored.\n");
|
|
970
1107
|
}
|
|
1108
|
+
invokeCodexCodeSync(prompt, options.yolo ?? false);
|
|
1109
|
+
}
|
|
1110
|
+
function invokeCodexCodeSync(prompt, yolo) {
|
|
1111
|
+
const codexBin = resolveCommand("codex");
|
|
1112
|
+
const args = ["exec"];
|
|
1113
|
+
if (yolo) args.push("--dangerously-bypass-approvals-and-sandbox");
|
|
1114
|
+
args.push(prompt);
|
|
1115
|
+
const result = spawnSync5(codexBin, args, { encoding: "utf8", stdio: "inherit" });
|
|
1116
|
+
handleSpawnError(result.error, "codex");
|
|
1117
|
+
handleExitCode(result.status, "Codex");
|
|
971
1118
|
}
|
|
972
|
-
|
|
1119
|
+
|
|
1120
|
+
// src/commands/getReady.ts
|
|
1121
|
+
var implementNextCommand = new Command3("implement-next").description("Find the next open GitHub issue matching the configured filter, claim it, and invoke the AI code assistant (Claude or Codex)").option("--json", "Output issue details as JSON").option("--no-claude", "Skip all AI invocation (Claude or Codex) after claiming the issue").option("--codex", "Use Codex CLI instead of Claude Code").option("--query-only", "Print issue content and exit without claiming or invoking any AI tools").option("--yolo", "Launch with --dangerously-skip-permissions (Claude) or --dangerously-bypass-approvals-and-sandbox (Codex)").option("--verbose", "Show step-by-step progress summary and final result").option("--opus", "Use claude-opus-4-6").option("--sonnet", "Use claude-sonnet-4-6").option("--haiku", "Use claude-haiku-4-5-20251001").action(async (options) => {
|
|
973
1122
|
const config = readConfig();
|
|
974
1123
|
if (config.remoteType !== "gh") {
|
|
975
1124
|
process.stderr.write(
|
|
@@ -1022,16 +1171,36 @@ ${issue.body}
|
|
|
1022
1171
|
process.exit(1);
|
|
1023
1172
|
}
|
|
1024
1173
|
if (options.claude !== false) {
|
|
1025
|
-
|
|
1174
|
+
const prompt = config.claudeSystemPrompt ? `${config.claudeSystemPrompt}
|
|
1175
|
+
|
|
1176
|
+
${issue.body}` : issue.body;
|
|
1177
|
+
if (options.codex) {
|
|
1178
|
+
await invokeCodexCode(prompt, { yolo: options.yolo, verbose: options.verbose });
|
|
1179
|
+
} else {
|
|
1180
|
+
const model = resolveModelOption(options);
|
|
1181
|
+
await invokeClaudeCode(prompt, { yolo: options.yolo, verbose: options.verbose, model });
|
|
1182
|
+
}
|
|
1026
1183
|
}
|
|
1027
1184
|
});
|
|
1028
1185
|
|
|
1186
|
+
// src/commands/test.ts
|
|
1187
|
+
import { Command as Command4 } from "commander";
|
|
1188
|
+
var testClaudeCmd = new Command4("claude").description("Test Claude Code invocation with a user-supplied prompt").requiredOption("--prompt <string>", "Prompt to send to Claude Code").option("--yolo", "Launch Claude Code with --dangerously-skip-permissions").option("--verbose", "Show step-by-step progress summary and final result").option("--opus", "Use claude-opus-4-6").option("--sonnet", "Use claude-sonnet-4-6").option("--haiku", "Use claude-haiku-4-5-20251001").action(async (options) => {
|
|
1189
|
+
const model = resolveModelOption(options);
|
|
1190
|
+
await invokeClaudeCode(options.prompt, { yolo: options.yolo, verbose: options.verbose, model });
|
|
1191
|
+
});
|
|
1192
|
+
var testCodexCmd = new Command4("codex").description("Test Codex CLI invocation with a user-supplied prompt").requiredOption("--prompt <string>", "Prompt to send to Codex CLI").option("--yolo", "Launch Codex with --dangerously-bypass-approvals-and-sandbox").option("--verbose", "Not supported for Codex; prints a warning and is otherwise ignored").action((options) => {
|
|
1193
|
+
invokeCodexCode(options.prompt, { yolo: options.yolo, verbose: options.verbose });
|
|
1194
|
+
});
|
|
1195
|
+
var testCommand = new Command4("test").description("Test commands for verifying automata integrations").addCommand(testClaudeCmd).addCommand(testCodexCmd);
|
|
1196
|
+
|
|
1029
1197
|
// src/index.ts
|
|
1030
|
-
var program = new
|
|
1198
|
+
var program = new Command5();
|
|
1031
1199
|
program.name("automata").description("Automata CLI tool").version(version, "-v, --version");
|
|
1032
1200
|
program.addCommand(configCommand);
|
|
1033
1201
|
program.addCommand(gitCommand);
|
|
1034
1202
|
program.addCommand(implementNextCommand);
|
|
1203
|
+
program.addCommand(testCommand);
|
|
1035
1204
|
program.showHelpAfterError();
|
|
1036
1205
|
program.parse();
|
|
1037
1206
|
if (process.argv.length <= 2) {
|