@neotx/cli 0.1.0-alpha.0
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/LICENSE +21 -0
- package/dist/agents-Y6LREFXP.js +58 -0
- package/dist/agents-Y6LREFXP.js.map +1 -0
- package/dist/chunk-CP54H7WA.js +85 -0
- package/dist/chunk-CP54H7WA.js.map +1 -0
- package/dist/chunk-EZAJLAUF.js +40 -0
- package/dist/chunk-EZAJLAUF.js.map +1 -0
- package/dist/chunk-TNJOG54I.js +16 -0
- package/dist/chunk-TNJOG54I.js.map +1 -0
- package/dist/chunk-YQIWMDXL.js +33 -0
- package/dist/chunk-YQIWMDXL.js.map +1 -0
- package/dist/cost-DNGKT4UC.js +134 -0
- package/dist/cost-DNGKT4UC.js.map +1 -0
- package/dist/daemon/supervisor-worker.js +28 -0
- package/dist/daemon/supervisor-worker.js.map +1 -0
- package/dist/daemon/worker.js +95 -0
- package/dist/daemon/worker.js.map +1 -0
- package/dist/doctor-CPVIT7IP.js +198 -0
- package/dist/doctor-CPVIT7IP.js.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/init-YNSPTCA3.js +74 -0
- package/dist/init-YNSPTCA3.js.map +1 -0
- package/dist/logs-AWNAMMJC.js +200 -0
- package/dist/logs-AWNAMMJC.js.map +1 -0
- package/dist/mcp-LC5VU65M.js +217 -0
- package/dist/mcp-LC5VU65M.js.map +1 -0
- package/dist/repos-GI6F72NO.js +111 -0
- package/dist/repos-GI6F72NO.js.map +1 -0
- package/dist/run-KIU2ZE72.js +231 -0
- package/dist/run-KIU2ZE72.js.map +1 -0
- package/dist/runs-CHA2JM5K.js +176 -0
- package/dist/runs-CHA2JM5K.js.map +1 -0
- package/dist/supervise-7ZITWRSL.js +298 -0
- package/dist/supervise-7ZITWRSL.js.map +1 -0
- package/dist/tui-W2FHMMMN.js +489 -0
- package/dist/tui-W2FHMMMN.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import {
|
|
2
|
+
printError,
|
|
3
|
+
printSuccess,
|
|
4
|
+
printTable
|
|
5
|
+
} from "./chunk-YQIWMDXL.js";
|
|
6
|
+
|
|
7
|
+
// src/commands/mcp.ts
|
|
8
|
+
import { readFile, writeFile } from "fs/promises";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { loadGlobalConfig } from "@neotx/core";
|
|
12
|
+
import { defineCommand } from "citty";
|
|
13
|
+
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
14
|
+
var MCP_PRESETS = {
|
|
15
|
+
linear: {
|
|
16
|
+
config: {
|
|
17
|
+
type: "stdio",
|
|
18
|
+
command: "npx",
|
|
19
|
+
args: ["-y", "@anthropic/linear-mcp-server"],
|
|
20
|
+
env: { LINEAR_API_KEY: "${LINEAR_API_KEY}" }
|
|
21
|
+
},
|
|
22
|
+
envVars: ["LINEAR_API_KEY"]
|
|
23
|
+
},
|
|
24
|
+
notion: {
|
|
25
|
+
config: {
|
|
26
|
+
type: "stdio",
|
|
27
|
+
command: "npx",
|
|
28
|
+
args: ["-y", "@anthropic/notion-mcp-server"],
|
|
29
|
+
env: { NOTION_API_KEY: "${NOTION_API_KEY}" }
|
|
30
|
+
},
|
|
31
|
+
envVars: ["NOTION_API_KEY"]
|
|
32
|
+
},
|
|
33
|
+
github: {
|
|
34
|
+
config: {
|
|
35
|
+
type: "stdio",
|
|
36
|
+
command: "npx",
|
|
37
|
+
args: ["-y", "@modelcontextprotocol/server-github"],
|
|
38
|
+
env: { GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}" }
|
|
39
|
+
},
|
|
40
|
+
envVars: ["GITHUB_TOKEN"]
|
|
41
|
+
},
|
|
42
|
+
jira: {
|
|
43
|
+
config: {
|
|
44
|
+
type: "stdio",
|
|
45
|
+
command: "npx",
|
|
46
|
+
args: ["-y", "@anthropic/jira-mcp-server"],
|
|
47
|
+
env: { JIRA_API_TOKEN: "${JIRA_API_TOKEN}", JIRA_URL: "${JIRA_URL}" }
|
|
48
|
+
},
|
|
49
|
+
envVars: ["JIRA_API_TOKEN", "JIRA_URL"]
|
|
50
|
+
},
|
|
51
|
+
slack: {
|
|
52
|
+
config: {
|
|
53
|
+
type: "stdio",
|
|
54
|
+
command: "npx",
|
|
55
|
+
args: ["-y", "@modelcontextprotocol/server-slack"],
|
|
56
|
+
env: { SLACK_BOT_TOKEN: "${SLACK_BOT_TOKEN}" }
|
|
57
|
+
},
|
|
58
|
+
envVars: ["SLACK_BOT_TOKEN"]
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
async function loadAndModifyConfig(modify) {
|
|
62
|
+
const configPath = path.join(homedir(), ".neo", "config.yml");
|
|
63
|
+
let config;
|
|
64
|
+
try {
|
|
65
|
+
const raw = await readFile(configPath, "utf-8");
|
|
66
|
+
config = parseYaml(raw) ?? {};
|
|
67
|
+
} catch {
|
|
68
|
+
config = {};
|
|
69
|
+
}
|
|
70
|
+
modify(config);
|
|
71
|
+
await writeFile(configPath, stringifyYaml(config), "utf-8");
|
|
72
|
+
}
|
|
73
|
+
var listCmd = defineCommand({
|
|
74
|
+
meta: { name: "list", description: "List configured MCP servers" },
|
|
75
|
+
async run() {
|
|
76
|
+
const config = await loadGlobalConfig();
|
|
77
|
+
const servers = config.mcpServers ?? {};
|
|
78
|
+
const entries = Object.entries(servers);
|
|
79
|
+
if (entries.length === 0) {
|
|
80
|
+
console.log("No MCP servers configured.");
|
|
81
|
+
console.log("Add one with: neo mcp add <name> or neo mcp add <preset>");
|
|
82
|
+
console.log(`Available presets: ${Object.keys(MCP_PRESETS).join(", ")}`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const rows = entries.map(([name, cfg]) => {
|
|
86
|
+
if (cfg.type === "stdio") {
|
|
87
|
+
return [name, "stdio", `${cfg.command} ${(cfg.args ?? []).join(" ")}`];
|
|
88
|
+
}
|
|
89
|
+
return [name, "http", cfg.url];
|
|
90
|
+
});
|
|
91
|
+
printTable(["Name", "Type", "Config"], rows);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
var addCmd = defineCommand({
|
|
95
|
+
meta: { name: "add", description: "Add an MCP server (use a preset name or custom flags)" },
|
|
96
|
+
args: {
|
|
97
|
+
name: {
|
|
98
|
+
type: "positional",
|
|
99
|
+
description: "Server name or preset (linear, notion, github, jira, slack)"
|
|
100
|
+
},
|
|
101
|
+
type: { type: "string", description: "Server type: stdio or http" },
|
|
102
|
+
command: { type: "string", description: "Command for stdio servers" },
|
|
103
|
+
serverArgs: { type: "string", description: "Comma-separated args for stdio servers" },
|
|
104
|
+
url: { type: "string", description: "URL for http servers" }
|
|
105
|
+
},
|
|
106
|
+
async run({ args }) {
|
|
107
|
+
const name = args.name;
|
|
108
|
+
if (!name) {
|
|
109
|
+
printError("Server name is required. Usage: neo mcp add <name>");
|
|
110
|
+
process.exitCode = 1;
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const preset = MCP_PRESETS[name];
|
|
114
|
+
if (preset) {
|
|
115
|
+
const missing = preset.envVars.filter((v) => !process.env[v]);
|
|
116
|
+
if (missing.length > 0) {
|
|
117
|
+
console.log(`Preset "${name}" requires the following environment variables:`);
|
|
118
|
+
for (const v of missing) {
|
|
119
|
+
console.log(` ${v} (not set)`);
|
|
120
|
+
}
|
|
121
|
+
console.log("\nSet them before starting the supervisor.");
|
|
122
|
+
}
|
|
123
|
+
await loadAndModifyConfig((config) => {
|
|
124
|
+
const servers = config.mcpServers ?? {};
|
|
125
|
+
servers[name] = preset.config;
|
|
126
|
+
config.mcpServers = servers;
|
|
127
|
+
});
|
|
128
|
+
printSuccess(`Added MCP server "${name}" (preset)`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (!args.type) {
|
|
132
|
+
printError(`Unknown preset "${name}". Use --type stdio or --type http for custom servers.`);
|
|
133
|
+
console.log(`Available presets: ${Object.keys(MCP_PRESETS).join(", ")}`);
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
let serverConfig;
|
|
138
|
+
if (args.type === "stdio") {
|
|
139
|
+
if (!args.command) {
|
|
140
|
+
printError("--command is required for stdio servers");
|
|
141
|
+
process.exitCode = 1;
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
serverConfig = {
|
|
145
|
+
type: "stdio",
|
|
146
|
+
command: args.command,
|
|
147
|
+
args: args.serverArgs ? args.serverArgs.split(",") : void 0
|
|
148
|
+
};
|
|
149
|
+
} else if (args.type === "http") {
|
|
150
|
+
if (!args.url) {
|
|
151
|
+
printError("--url is required for http servers");
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
serverConfig = {
|
|
156
|
+
type: "http",
|
|
157
|
+
url: args.url
|
|
158
|
+
};
|
|
159
|
+
} else {
|
|
160
|
+
printError(`Invalid type "${args.type}". Use "stdio" or "http".`);
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
await loadAndModifyConfig((config) => {
|
|
165
|
+
const servers = config.mcpServers ?? {};
|
|
166
|
+
servers[name] = serverConfig;
|
|
167
|
+
config.mcpServers = servers;
|
|
168
|
+
});
|
|
169
|
+
printSuccess(`Added MCP server "${name}"`);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
var removeCmd = defineCommand({
|
|
173
|
+
meta: { name: "remove", description: "Remove an MCP server" },
|
|
174
|
+
args: {
|
|
175
|
+
name: { type: "positional", description: "Server name to remove" }
|
|
176
|
+
},
|
|
177
|
+
async run({ args }) {
|
|
178
|
+
const name = args.name;
|
|
179
|
+
if (!name) {
|
|
180
|
+
printError("Server name is required. Usage: neo mcp remove <name>");
|
|
181
|
+
process.exitCode = 1;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
let found = false;
|
|
185
|
+
await loadAndModifyConfig((config) => {
|
|
186
|
+
const servers = config.mcpServers;
|
|
187
|
+
if (servers && name in servers) {
|
|
188
|
+
delete servers[name];
|
|
189
|
+
found = true;
|
|
190
|
+
if (Object.keys(servers).length === 0) {
|
|
191
|
+
delete config.mcpServers;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
if (found) {
|
|
196
|
+
printSuccess(`Removed MCP server "${name}"`);
|
|
197
|
+
} else {
|
|
198
|
+
printError(`MCP server "${name}" not found`);
|
|
199
|
+
process.exitCode = 1;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
var mcp_default = defineCommand({
|
|
204
|
+
meta: {
|
|
205
|
+
name: "mcp",
|
|
206
|
+
description: "Manage MCP server integrations (Linear, Notion, GitHub, etc.)"
|
|
207
|
+
},
|
|
208
|
+
subCommands: {
|
|
209
|
+
list: () => Promise.resolve(listCmd),
|
|
210
|
+
add: () => Promise.resolve(addCmd),
|
|
211
|
+
remove: () => Promise.resolve(removeCmd)
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
export {
|
|
215
|
+
mcp_default as default
|
|
216
|
+
};
|
|
217
|
+
//# sourceMappingURL=mcp-LC5VU65M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport { loadGlobalConfig, type McpServerConfig } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { printError, printSuccess, printTable } from \"../output.js\";\n\n// ─── Presets for popular MCP servers ─────────────────────\n\nconst MCP_PRESETS: Record<string, { config: McpServerConfig; envVars: string[] }> = {\n linear: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@anthropic/linear-mcp-server\"],\n env: { LINEAR_API_KEY: \"${LINEAR_API_KEY}\" },\n },\n envVars: [\"LINEAR_API_KEY\"],\n },\n notion: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@anthropic/notion-mcp-server\"],\n env: { NOTION_API_KEY: \"${NOTION_API_KEY}\" },\n },\n envVars: [\"NOTION_API_KEY\"],\n },\n github: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@modelcontextprotocol/server-github\"],\n env: { GITHUB_PERSONAL_ACCESS_TOKEN: \"${GITHUB_TOKEN}\" },\n },\n envVars: [\"GITHUB_TOKEN\"],\n },\n jira: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@anthropic/jira-mcp-server\"],\n env: { JIRA_API_TOKEN: \"${JIRA_API_TOKEN}\", JIRA_URL: \"${JIRA_URL}\" },\n },\n envVars: [\"JIRA_API_TOKEN\", \"JIRA_URL\"],\n },\n slack: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@modelcontextprotocol/server-slack\"],\n env: { SLACK_BOT_TOKEN: \"${SLACK_BOT_TOKEN}\" },\n },\n envVars: [\"SLACK_BOT_TOKEN\"],\n },\n};\n\n// ─── Helpers ─────────────────────────────────────────────\n\nasync function loadAndModifyConfig(\n modify: (config: Record<string, unknown>) => void,\n): Promise<void> {\n const configPath = path.join(homedir(), \".neo\", \"config.yml\");\n let config: Record<string, unknown>;\n\n try {\n const raw = await readFile(configPath, \"utf-8\");\n config = (parseYaml(raw) as Record<string, unknown>) ?? {};\n } catch {\n config = {};\n }\n\n modify(config);\n await writeFile(configPath, stringifyYaml(config), \"utf-8\");\n}\n\n// ─── Subcommands ─────────────────────────────────────────\n\nconst listCmd = defineCommand({\n meta: { name: \"list\", description: \"List configured MCP servers\" },\n async run() {\n const config = await loadGlobalConfig();\n const servers = config.mcpServers ?? {};\n const entries = Object.entries(servers);\n\n if (entries.length === 0) {\n console.log(\"No MCP servers configured.\");\n console.log(\"Add one with: neo mcp add <name> or neo mcp add <preset>\");\n console.log(`Available presets: ${Object.keys(MCP_PRESETS).join(\", \")}`);\n return;\n }\n\n const rows = entries.map(([name, cfg]) => {\n if (cfg.type === \"stdio\") {\n return [name, \"stdio\", `${cfg.command} ${(cfg.args ?? []).join(\" \")}`];\n }\n return [name, \"http\", cfg.url];\n });\n\n printTable([\"Name\", \"Type\", \"Config\"], rows);\n },\n});\n\nconst addCmd = defineCommand({\n meta: { name: \"add\", description: \"Add an MCP server (use a preset name or custom flags)\" },\n args: {\n name: {\n type: \"positional\",\n description: \"Server name or preset (linear, notion, github, jira, slack)\",\n },\n type: { type: \"string\", description: \"Server type: stdio or http\" },\n command: { type: \"string\", description: \"Command for stdio servers\" },\n serverArgs: { type: \"string\", description: \"Comma-separated args for stdio servers\" },\n url: { type: \"string\", description: \"URL for http servers\" },\n },\n async run({ args }) {\n const name = args.name as string | undefined;\n if (!name) {\n printError(\"Server name is required. Usage: neo mcp add <name>\");\n process.exitCode = 1;\n return;\n }\n\n // Check if it's a preset\n const preset = MCP_PRESETS[name];\n if (preset) {\n // Check env vars\n const missing = preset.envVars.filter((v: string) => !process.env[v]);\n if (missing.length > 0) {\n console.log(`Preset \"${name}\" requires the following environment variables:`);\n for (const v of missing) {\n console.log(` ${v} (not set)`);\n }\n console.log(\"\\nSet them before starting the supervisor.\");\n }\n\n await loadAndModifyConfig((config) => {\n const servers = (config.mcpServers as Record<string, unknown>) ?? {};\n servers[name] = preset.config;\n config.mcpServers = servers;\n });\n\n printSuccess(`Added MCP server \"${name}\" (preset)`);\n return;\n }\n\n // Custom server\n if (!args.type) {\n printError(`Unknown preset \"${name}\". Use --type stdio or --type http for custom servers.`);\n console.log(`Available presets: ${Object.keys(MCP_PRESETS).join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n let serverConfig: McpServerConfig;\n if (args.type === \"stdio\") {\n if (!args.command) {\n printError(\"--command is required for stdio servers\");\n process.exitCode = 1;\n return;\n }\n serverConfig = {\n type: \"stdio\",\n command: args.command,\n args: args.serverArgs ? args.serverArgs.split(\",\") : undefined,\n };\n } else if (args.type === \"http\") {\n if (!args.url) {\n printError(\"--url is required for http servers\");\n process.exitCode = 1;\n return;\n }\n serverConfig = {\n type: \"http\",\n url: args.url,\n };\n } else {\n printError(`Invalid type \"${args.type}\". Use \"stdio\" or \"http\".`);\n process.exitCode = 1;\n return;\n }\n\n await loadAndModifyConfig((config) => {\n const servers = (config.mcpServers as Record<string, unknown>) ?? {};\n servers[name] = serverConfig;\n config.mcpServers = servers;\n });\n\n printSuccess(`Added MCP server \"${name}\"`);\n },\n});\n\nconst removeCmd = defineCommand({\n meta: { name: \"remove\", description: \"Remove an MCP server\" },\n args: {\n name: { type: \"positional\", description: \"Server name to remove\" },\n },\n async run({ args }) {\n const name = args.name as string | undefined;\n if (!name) {\n printError(\"Server name is required. Usage: neo mcp remove <name>\");\n process.exitCode = 1;\n return;\n }\n\n let found = false;\n\n await loadAndModifyConfig((config) => {\n const servers = config.mcpServers as Record<string, unknown> | undefined;\n if (servers && name in servers) {\n delete servers[name];\n found = true;\n if (Object.keys(servers).length === 0) {\n delete config.mcpServers;\n }\n }\n });\n\n if (found) {\n printSuccess(`Removed MCP server \"${name}\"`);\n } else {\n printError(`MCP server \"${name}\" not found`);\n process.exitCode = 1;\n }\n },\n});\n\n// ─── Main command ────────────────────────────────────────\n\nexport default defineCommand({\n meta: {\n name: \"mcp\",\n description: \"Manage MCP server integrations (Linear, Notion, GitHub, etc.)\",\n },\n subCommands: {\n list: () => Promise.resolve(listCmd),\n add: () => Promise.resolve(addCmd),\n remove: () => Promise.resolve(removeCmd),\n },\n});\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectDefaultBranch,
|
|
3
|
+
isGitRepo
|
|
4
|
+
} from "./chunk-EZAJLAUF.js";
|
|
5
|
+
import {
|
|
6
|
+
printError,
|
|
7
|
+
printJson,
|
|
8
|
+
printSuccess,
|
|
9
|
+
printTable
|
|
10
|
+
} from "./chunk-YQIWMDXL.js";
|
|
11
|
+
|
|
12
|
+
// src/commands/repos.ts
|
|
13
|
+
import path from "path";
|
|
14
|
+
import {
|
|
15
|
+
addRepoToGlobalConfig,
|
|
16
|
+
listReposFromGlobalConfig,
|
|
17
|
+
removeRepoFromGlobalConfig,
|
|
18
|
+
toRepoSlug
|
|
19
|
+
} from "@neotx/core";
|
|
20
|
+
import { defineCommand } from "citty";
|
|
21
|
+
async function listRepos(jsonOutput) {
|
|
22
|
+
const repos = await listReposFromGlobalConfig();
|
|
23
|
+
if (jsonOutput) {
|
|
24
|
+
printJson(repos.map((r) => ({ ...r, slug: toRepoSlug(r) })));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (repos.length === 0) {
|
|
28
|
+
console.log("No repos registered. Run 'neo repos add' or 'neo init'.");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
printTable(
|
|
32
|
+
["NAME", "PATH", "BRANCH", "REMOTE"],
|
|
33
|
+
repos.map((r) => [toRepoSlug(r), r.path, r.defaultBranch, r.pushRemote])
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
async function addRepo(args) {
|
|
37
|
+
const repoPath = path.resolve(args.repoPath);
|
|
38
|
+
if (!await isGitRepo(repoPath)) {
|
|
39
|
+
printError(`Not a git repository: ${repoPath}`);
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const defaultBranch = args.branch ?? await detectDefaultBranch(repoPath);
|
|
44
|
+
await addRepoToGlobalConfig({
|
|
45
|
+
path: repoPath,
|
|
46
|
+
name: args.name,
|
|
47
|
+
defaultBranch
|
|
48
|
+
});
|
|
49
|
+
const slug = toRepoSlug({ name: args.name, path: repoPath });
|
|
50
|
+
printSuccess(`Registered repo "${slug}" at ${repoPath} (branch: ${defaultBranch})`);
|
|
51
|
+
}
|
|
52
|
+
async function removeRepo(nameOrPath) {
|
|
53
|
+
const removed = await removeRepoFromGlobalConfig(nameOrPath);
|
|
54
|
+
if (removed) {
|
|
55
|
+
printSuccess(`Removed repo "${nameOrPath}"`);
|
|
56
|
+
} else {
|
|
57
|
+
printError(`Repo not found: ${nameOrPath}`);
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
var repos_default = defineCommand({
|
|
62
|
+
meta: {
|
|
63
|
+
name: "repos",
|
|
64
|
+
description: "Manage registered repositories (list, add, remove)"
|
|
65
|
+
},
|
|
66
|
+
args: {
|
|
67
|
+
action: {
|
|
68
|
+
type: "positional",
|
|
69
|
+
description: "Action: add, remove (omit to list)",
|
|
70
|
+
required: false
|
|
71
|
+
},
|
|
72
|
+
target: {
|
|
73
|
+
type: "positional",
|
|
74
|
+
description: "Path (for add) or name/path (for remove)",
|
|
75
|
+
required: false
|
|
76
|
+
},
|
|
77
|
+
name: { type: "string", description: "Custom name for the repo (add only)" },
|
|
78
|
+
branch: { type: "string", description: "Default branch (add only, auto-detected if omitted)" },
|
|
79
|
+
output: { type: "string", description: "Output format: json" }
|
|
80
|
+
},
|
|
81
|
+
async run({ args }) {
|
|
82
|
+
const jsonOutput = args.output === "json";
|
|
83
|
+
switch (args.action) {
|
|
84
|
+
case "add":
|
|
85
|
+
await addRepo({
|
|
86
|
+
repoPath: args.target ?? ".",
|
|
87
|
+
name: args.name,
|
|
88
|
+
branch: args.branch
|
|
89
|
+
});
|
|
90
|
+
break;
|
|
91
|
+
case "remove":
|
|
92
|
+
if (!args.target) {
|
|
93
|
+
printError("Usage: neo repos remove <name-or-path>");
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await removeRepo(args.target);
|
|
98
|
+
break;
|
|
99
|
+
case void 0:
|
|
100
|
+
await listRepos(jsonOutput);
|
|
101
|
+
break;
|
|
102
|
+
default:
|
|
103
|
+
printError(`Unknown action: ${args.action}. Use: add, remove, or omit to list.`);
|
|
104
|
+
process.exitCode = 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
export {
|
|
109
|
+
repos_default as default
|
|
110
|
+
};
|
|
111
|
+
//# sourceMappingURL=repos-GI6F72NO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/repos.ts"],"sourcesContent":["import path from \"node:path\";\nimport {\n addRepoToGlobalConfig,\n listReposFromGlobalConfig,\n removeRepoFromGlobalConfig,\n toRepoSlug,\n} from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { detectDefaultBranch, isGitRepo } from \"../git-utils.js\";\nimport { printError, printJson, printSuccess, printTable } from \"../output.js\";\n\nasync function listRepos(jsonOutput: boolean): Promise<void> {\n const repos = await listReposFromGlobalConfig();\n\n if (jsonOutput) {\n printJson(repos.map((r) => ({ ...r, slug: toRepoSlug(r) })));\n return;\n }\n\n if (repos.length === 0) {\n console.log(\"No repos registered. Run 'neo repos add' or 'neo init'.\");\n return;\n }\n\n printTable(\n [\"NAME\", \"PATH\", \"BRANCH\", \"REMOTE\"],\n repos.map((r) => [toRepoSlug(r), r.path, r.defaultBranch, r.pushRemote]),\n );\n}\n\nasync function addRepo(args: {\n repoPath: string;\n name: string | undefined;\n branch: string | undefined;\n}): Promise<void> {\n const repoPath = path.resolve(args.repoPath);\n\n if (!(await isGitRepo(repoPath))) {\n printError(`Not a git repository: ${repoPath}`);\n process.exitCode = 1;\n return;\n }\n\n const defaultBranch = args.branch ?? (await detectDefaultBranch(repoPath));\n\n await addRepoToGlobalConfig({\n path: repoPath,\n name: args.name,\n defaultBranch,\n });\n\n const slug = toRepoSlug({ name: args.name, path: repoPath });\n printSuccess(`Registered repo \"${slug}\" at ${repoPath} (branch: ${defaultBranch})`);\n}\n\nasync function removeRepo(nameOrPath: string): Promise<void> {\n const removed = await removeRepoFromGlobalConfig(nameOrPath);\n if (removed) {\n printSuccess(`Removed repo \"${nameOrPath}\"`);\n } else {\n printError(`Repo not found: ${nameOrPath}`);\n process.exitCode = 1;\n }\n}\n\nexport default defineCommand({\n meta: {\n name: \"repos\",\n description: \"Manage registered repositories (list, add, remove)\",\n },\n args: {\n action: {\n type: \"positional\",\n description: \"Action: add, remove (omit to list)\",\n required: false,\n },\n target: {\n type: \"positional\",\n description: \"Path (for add) or name/path (for remove)\",\n required: false,\n },\n name: { type: \"string\", description: \"Custom name for the repo (add only)\" },\n branch: { type: \"string\", description: \"Default branch (add only, auto-detected if omitted)\" },\n output: { type: \"string\", description: \"Output format: json\" },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n\n switch (args.action) {\n case \"add\":\n await addRepo({\n repoPath: (args.target as string) ?? \".\",\n name: args.name,\n branch: args.branch,\n });\n break;\n\n case \"remove\":\n if (!args.target) {\n printError(\"Usage: neo repos remove <name-or-path>\");\n process.exitCode = 1;\n return;\n }\n await removeRepo(args.target as string);\n break;\n\n case undefined:\n await listRepos(jsonOutput);\n break;\n\n default:\n printError(`Unknown action: ${args.action}. Use: add, remove, or omit to list.`);\n process.exitCode = 1;\n }\n },\n});\n"],"mappings":";;;;;;;;;;;;AAAA,OAAO,UAAU;AACjB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAI9B,eAAe,UAAU,YAAoC;AAC3D,QAAM,QAAQ,MAAM,0BAA0B;AAE9C,MAAI,YAAY;AACd,cAAU,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,WAAW,CAAC,EAAE,EAAE,CAAC;AAC3D;AAAA,EACF;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,YAAQ,IAAI,yDAAyD;AACrE;AAAA,EACF;AAEA;AAAA,IACE,CAAC,QAAQ,QAAQ,UAAU,QAAQ;AAAA,IACnC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,eAAe,EAAE,UAAU,CAAC;AAAA,EACzE;AACF;AAEA,eAAe,QAAQ,MAIL;AAChB,QAAM,WAAW,KAAK,QAAQ,KAAK,QAAQ;AAE3C,MAAI,CAAE,MAAM,UAAU,QAAQ,GAAI;AAChC,eAAW,yBAAyB,QAAQ,EAAE;AAC9C,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,gBAAgB,KAAK,UAAW,MAAM,oBAAoB,QAAQ;AAExE,QAAM,sBAAsB;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM,KAAK;AAAA,IACX;AAAA,EACF,CAAC;AAED,QAAM,OAAO,WAAW,EAAE,MAAM,KAAK,MAAM,MAAM,SAAS,CAAC;AAC3D,eAAa,oBAAoB,IAAI,QAAQ,QAAQ,aAAa,aAAa,GAAG;AACpF;AAEA,eAAe,WAAW,YAAmC;AAC3D,QAAM,UAAU,MAAM,2BAA2B,UAAU;AAC3D,MAAI,SAAS;AACX,iBAAa,iBAAiB,UAAU,GAAG;AAAA,EAC7C,OAAO;AACL,eAAW,mBAAmB,UAAU,EAAE;AAC1C,YAAQ,WAAW;AAAA,EACrB;AACF;AAEA,IAAO,gBAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,MAAM,EAAE,MAAM,UAAU,aAAa,sCAAsC;AAAA,IAC3E,QAAQ,EAAE,MAAM,UAAU,aAAa,sDAAsD;AAAA,IAC7F,QAAQ,EAAE,MAAM,UAAU,aAAa,sBAAsB;AAAA,EAC/D;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,aAAa,KAAK,WAAW;AAEnC,YAAQ,KAAK,QAAQ;AAAA,MACnB,KAAK;AACH,cAAM,QAAQ;AAAA,UACZ,UAAW,KAAK,UAAqB;AAAA,UACrC,MAAM,KAAK;AAAA,UACX,QAAQ,KAAK;AAAA,QACf,CAAC;AACD;AAAA,MAEF,KAAK;AACH,YAAI,CAAC,KAAK,QAAQ;AAChB,qBAAW,wCAAwC;AACnD,kBAAQ,WAAW;AACnB;AAAA,QACF;AACA,cAAM,WAAW,KAAK,MAAgB;AACtC;AAAA,MAEF,KAAK;AACH,cAAM,UAAU,UAAU;AAC1B;AAAA,MAEF;AACE,mBAAW,mBAAmB,KAAK,MAAM,sCAAsC;AAC/E,gBAAQ,WAAW;AAAA,IACvB;AAAA,EACF;AACF,CAAC;","names":[]}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveAgentsDir
|
|
3
|
+
} from "./chunk-TNJOG54I.js";
|
|
4
|
+
import {
|
|
5
|
+
printError,
|
|
6
|
+
printJson,
|
|
7
|
+
printSuccess
|
|
8
|
+
} from "./chunk-YQIWMDXL.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/run.ts
|
|
11
|
+
import { fork } from "child_process";
|
|
12
|
+
import { randomUUID } from "crypto";
|
|
13
|
+
import { existsSync } from "fs";
|
|
14
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
15
|
+
import path from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
import {
|
|
18
|
+
AgentRegistry,
|
|
19
|
+
getRepoRunsDir,
|
|
20
|
+
getRunDispatchPath,
|
|
21
|
+
loadGlobalConfig,
|
|
22
|
+
Orchestrator,
|
|
23
|
+
toRepoSlug
|
|
24
|
+
} from "@neotx/core";
|
|
25
|
+
import { defineCommand } from "citty";
|
|
26
|
+
function printProgress(event) {
|
|
27
|
+
const ts = event.timestamp.slice(11, 19);
|
|
28
|
+
switch (event.type) {
|
|
29
|
+
case "session:start":
|
|
30
|
+
console.log(`[${ts}] ${event.agent}: starting`);
|
|
31
|
+
break;
|
|
32
|
+
case "session:complete":
|
|
33
|
+
console.log(`[${ts}] session complete: $${event.costUsd.toFixed(4)}`);
|
|
34
|
+
break;
|
|
35
|
+
case "session:fail":
|
|
36
|
+
console.log(`[${ts}] session failed: ${event.error}`);
|
|
37
|
+
break;
|
|
38
|
+
case "cost:update":
|
|
39
|
+
break;
|
|
40
|
+
case "budget:alert":
|
|
41
|
+
console.log(`[${ts}] \u26A0 Budget alert: ${event.utilizationPct.toFixed(0)}% used`);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function parseMetadata(meta) {
|
|
46
|
+
if (!meta) return void 0;
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(meta);
|
|
49
|
+
} catch {
|
|
50
|
+
throw new Error(`Invalid --meta JSON: ${meta}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function printResult(result, agentName) {
|
|
54
|
+
console.log("");
|
|
55
|
+
console.log(`Run: ${result.runId}`);
|
|
56
|
+
console.log(`Agent: ${agentName}`);
|
|
57
|
+
console.log(`Status: ${result.status}`);
|
|
58
|
+
console.log(`Cost: $${result.costUsd.toFixed(4)}`);
|
|
59
|
+
console.log(`Duration: ${(result.durationMs / 1e3).toFixed(1)}s`);
|
|
60
|
+
if (result.branch) {
|
|
61
|
+
console.log(`Branch: ${result.branch}`);
|
|
62
|
+
}
|
|
63
|
+
const stepResult = Object.values(result.steps)[0];
|
|
64
|
+
const output = stepResult?.output ?? result.summary;
|
|
65
|
+
if (output) {
|
|
66
|
+
console.log("");
|
|
67
|
+
console.log(typeof output === "string" ? output : JSON.stringify(output, null, 2));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function runDetached(params) {
|
|
71
|
+
const runId = randomUUID();
|
|
72
|
+
const repoSlug = toRepoSlug({ path: params.repo });
|
|
73
|
+
const runsDir = getRepoRunsDir(repoSlug);
|
|
74
|
+
await mkdir(runsDir, { recursive: true });
|
|
75
|
+
const persistedRun = {
|
|
76
|
+
version: 1,
|
|
77
|
+
runId,
|
|
78
|
+
workflow: `_run_${params.agentName}`,
|
|
79
|
+
repo: params.repo,
|
|
80
|
+
prompt: params.prompt,
|
|
81
|
+
status: "running",
|
|
82
|
+
steps: {},
|
|
83
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
84
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
85
|
+
metadata: params.metadata
|
|
86
|
+
};
|
|
87
|
+
await writeFile(
|
|
88
|
+
path.join(runsDir, `${runId}.json`),
|
|
89
|
+
JSON.stringify(persistedRun, null, 2),
|
|
90
|
+
"utf-8"
|
|
91
|
+
);
|
|
92
|
+
const dispatchPath = getRunDispatchPath(repoSlug, runId);
|
|
93
|
+
await writeFile(
|
|
94
|
+
dispatchPath,
|
|
95
|
+
JSON.stringify({
|
|
96
|
+
agentName: params.agentName,
|
|
97
|
+
repo: params.repo,
|
|
98
|
+
prompt: params.prompt,
|
|
99
|
+
priority: params.priority,
|
|
100
|
+
metadata: params.metadata,
|
|
101
|
+
bundledAgentsDir: params.bundledAgentsDir,
|
|
102
|
+
customAgentsDir: params.customAgentsDir
|
|
103
|
+
}),
|
|
104
|
+
"utf-8"
|
|
105
|
+
);
|
|
106
|
+
const workerPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "daemon", "worker.js");
|
|
107
|
+
const child = fork(workerPath, [runId, repoSlug], {
|
|
108
|
+
detached: true,
|
|
109
|
+
stdio: "ignore"
|
|
110
|
+
});
|
|
111
|
+
child.unref();
|
|
112
|
+
if (params.jsonOutput) {
|
|
113
|
+
printJson({ runId, status: "detached", pid: child.pid });
|
|
114
|
+
} else {
|
|
115
|
+
printSuccess(`Detached run started: ${runId}`);
|
|
116
|
+
console.log(` PID: ${String(child.pid)}`);
|
|
117
|
+
console.log(` Logs: neo logs -f ${runId}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
var run_default = defineCommand({
|
|
121
|
+
meta: {
|
|
122
|
+
name: "run",
|
|
123
|
+
description: "Dispatch an agent to execute a task in an isolated worktree"
|
|
124
|
+
},
|
|
125
|
+
args: {
|
|
126
|
+
agent: {
|
|
127
|
+
type: "positional",
|
|
128
|
+
description: "Agent name to run (e.g. developer, architect, reviewer-quality)",
|
|
129
|
+
required: true
|
|
130
|
+
},
|
|
131
|
+
repo: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Target repository path",
|
|
134
|
+
default: "."
|
|
135
|
+
},
|
|
136
|
+
prompt: {
|
|
137
|
+
type: "string",
|
|
138
|
+
description: "Task description for the agent",
|
|
139
|
+
required: true
|
|
140
|
+
},
|
|
141
|
+
priority: {
|
|
142
|
+
type: "string",
|
|
143
|
+
description: "Priority level: critical, high, medium, low"
|
|
144
|
+
},
|
|
145
|
+
meta: {
|
|
146
|
+
type: "string",
|
|
147
|
+
description: "Metadata as JSON string"
|
|
148
|
+
},
|
|
149
|
+
output: {
|
|
150
|
+
type: "string",
|
|
151
|
+
description: "Output format: json"
|
|
152
|
+
},
|
|
153
|
+
detach: {
|
|
154
|
+
type: "boolean",
|
|
155
|
+
alias: "d",
|
|
156
|
+
description: "Run in background and return immediately with the run ID",
|
|
157
|
+
default: false
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
async run({ args }) {
|
|
161
|
+
const jsonOutput = args.output === "json";
|
|
162
|
+
const config = await loadGlobalConfig();
|
|
163
|
+
const repo = path.resolve(args.repo);
|
|
164
|
+
const bundledAgentsDir = resolveAgentsDir();
|
|
165
|
+
const customAgentsDir = path.resolve(".neo/agents");
|
|
166
|
+
const agentRegistry = new AgentRegistry(
|
|
167
|
+
bundledAgentsDir,
|
|
168
|
+
existsSync(customAgentsDir) ? customAgentsDir : void 0
|
|
169
|
+
);
|
|
170
|
+
await agentRegistry.load();
|
|
171
|
+
const agent = agentRegistry.get(args.agent);
|
|
172
|
+
if (!agent) {
|
|
173
|
+
const available = agentRegistry.list().map((a) => a.name).join(", ");
|
|
174
|
+
printError(`Agent "${args.agent}" not found. Available: ${available}`);
|
|
175
|
+
process.exitCode = 1;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (args.detach) {
|
|
179
|
+
await runDetached({
|
|
180
|
+
agentName: args.agent,
|
|
181
|
+
repo,
|
|
182
|
+
prompt: args.prompt,
|
|
183
|
+
priority: args.priority ?? "medium",
|
|
184
|
+
metadata: parseMetadata(args.meta),
|
|
185
|
+
bundledAgentsDir,
|
|
186
|
+
customAgentsDir: existsSync(customAgentsDir) ? customAgentsDir : void 0,
|
|
187
|
+
jsonOutput
|
|
188
|
+
});
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const orchestrator = new Orchestrator(config);
|
|
192
|
+
orchestrator.registerAgent(agent);
|
|
193
|
+
orchestrator.registerWorkflow({
|
|
194
|
+
name: `_run_${args.agent}`,
|
|
195
|
+
description: `Direct dispatch to ${args.agent}`,
|
|
196
|
+
steps: {
|
|
197
|
+
run: { agent: args.agent }
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
if (!jsonOutput) {
|
|
201
|
+
orchestrator.on("*", printProgress);
|
|
202
|
+
}
|
|
203
|
+
try {
|
|
204
|
+
await orchestrator.start();
|
|
205
|
+
const result = await orchestrator.dispatch({
|
|
206
|
+
workflow: `_run_${args.agent}`,
|
|
207
|
+
repo,
|
|
208
|
+
prompt: args.prompt,
|
|
209
|
+
priority: args.priority ?? "medium",
|
|
210
|
+
metadata: parseMetadata(args.meta)
|
|
211
|
+
});
|
|
212
|
+
if (jsonOutput) {
|
|
213
|
+
printJson(result);
|
|
214
|
+
} else {
|
|
215
|
+
printResult(result, args.agent);
|
|
216
|
+
}
|
|
217
|
+
await orchestrator.shutdown();
|
|
218
|
+
if (result.status !== "success") {
|
|
219
|
+
process.exitCode = 1;
|
|
220
|
+
}
|
|
221
|
+
} catch (error) {
|
|
222
|
+
await orchestrator.shutdown();
|
|
223
|
+
printError(error instanceof Error ? error.message : String(error));
|
|
224
|
+
process.exitCode = 1;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
export {
|
|
229
|
+
run_default as default
|
|
230
|
+
};
|
|
231
|
+
//# sourceMappingURL=run-KIU2ZE72.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/run.ts"],"sourcesContent":["import { fork } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NeoEvent, PersistedRun } from \"@neotx/core\";\nimport {\n AgentRegistry,\n getRepoRunsDir,\n getRunDispatchPath,\n loadGlobalConfig,\n Orchestrator,\n toRepoSlug,\n} from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printJson, printSuccess } from \"../output.js\";\nimport { resolveAgentsDir } from \"../resolve.js\";\n\nfunction printProgress(event: NeoEvent): void {\n const ts = event.timestamp.slice(11, 19);\n switch (event.type) {\n case \"session:start\":\n console.log(`[${ts}] ${event.agent}: starting`);\n break;\n case \"session:complete\":\n console.log(`[${ts}] session complete: $${event.costUsd.toFixed(4)}`);\n break;\n case \"session:fail\":\n console.log(`[${ts}] session failed: ${event.error}`);\n break;\n case \"cost:update\":\n break;\n case \"budget:alert\":\n console.log(`[${ts}] ⚠ Budget alert: ${event.utilizationPct.toFixed(0)}% used`);\n break;\n }\n}\n\nfunction parseMetadata(meta: string | undefined): Record<string, unknown> | undefined {\n if (!meta) return undefined;\n try {\n return JSON.parse(meta) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid --meta JSON: ${meta}`);\n }\n}\n\nfunction printResult(result: import(\"@neotx/core\").TaskResult, agentName: string): void {\n console.log(\"\");\n console.log(`Run: ${result.runId}`);\n console.log(`Agent: ${agentName}`);\n console.log(`Status: ${result.status}`);\n console.log(`Cost: $${result.costUsd.toFixed(4)}`);\n console.log(`Duration: ${(result.durationMs / 1000).toFixed(1)}s`);\n if (result.branch) {\n console.log(`Branch: ${result.branch}`);\n }\n\n const stepResult = Object.values(result.steps)[0];\n const output = stepResult?.output ?? result.summary;\n if (output) {\n console.log(\"\");\n console.log(typeof output === \"string\" ? output : JSON.stringify(output, null, 2));\n }\n}\n\ninterface DetachParams {\n agentName: string;\n repo: string;\n prompt: string;\n priority: string;\n metadata: Record<string, unknown> | undefined;\n bundledAgentsDir: string;\n customAgentsDir: string | undefined;\n jsonOutput: boolean;\n}\n\nasync function runDetached(params: DetachParams): Promise<void> {\n const runId = randomUUID();\n const repoSlug = toRepoSlug({ path: params.repo });\n const runsDir = getRepoRunsDir(repoSlug);\n await mkdir(runsDir, { recursive: true });\n\n const persistedRun: PersistedRun = {\n version: 1,\n runId,\n workflow: `_run_${params.agentName}`,\n repo: params.repo,\n prompt: params.prompt,\n status: \"running\",\n steps: {},\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n metadata: params.metadata,\n };\n await writeFile(\n path.join(runsDir, `${runId}.json`),\n JSON.stringify(persistedRun, null, 2),\n \"utf-8\",\n );\n\n const dispatchPath = getRunDispatchPath(repoSlug, runId);\n await writeFile(\n dispatchPath,\n JSON.stringify({\n agentName: params.agentName,\n repo: params.repo,\n prompt: params.prompt,\n priority: params.priority,\n metadata: params.metadata,\n bundledAgentsDir: params.bundledAgentsDir,\n customAgentsDir: params.customAgentsDir,\n }),\n \"utf-8\",\n );\n\n const workerPath = path.join(path.dirname(fileURLToPath(import.meta.url)), \"daemon\", \"worker.js\");\n const child = fork(workerPath, [runId, repoSlug], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n\n if (params.jsonOutput) {\n printJson({ runId, status: \"detached\", pid: child.pid });\n } else {\n printSuccess(`Detached run started: ${runId}`);\n console.log(` PID: ${String(child.pid)}`);\n console.log(` Logs: neo logs -f ${runId}`);\n }\n}\n\nexport default defineCommand({\n meta: {\n name: \"run\",\n description: \"Dispatch an agent to execute a task in an isolated worktree\",\n },\n args: {\n agent: {\n type: \"positional\",\n description: \"Agent name to run (e.g. developer, architect, reviewer-quality)\",\n required: true,\n },\n repo: {\n type: \"string\",\n description: \"Target repository path\",\n default: \".\",\n },\n prompt: {\n type: \"string\",\n description: \"Task description for the agent\",\n required: true,\n },\n priority: {\n type: \"string\",\n description: \"Priority level: critical, high, medium, low\",\n },\n meta: {\n type: \"string\",\n description: \"Metadata as JSON string\",\n },\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n detach: {\n type: \"boolean\",\n alias: \"d\",\n description: \"Run in background and return immediately with the run ID\",\n default: false,\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n\n // Zero-config: only need global config (auto-creates ~/.neo/config.yml if absent)\n const config = await loadGlobalConfig();\n const repo = path.resolve(args.repo);\n\n // Load agent registry (bundled + project-local agents)\n const bundledAgentsDir = resolveAgentsDir();\n const customAgentsDir = path.resolve(\".neo/agents\");\n const agentRegistry = new AgentRegistry(\n bundledAgentsDir,\n existsSync(customAgentsDir) ? customAgentsDir : undefined,\n );\n await agentRegistry.load();\n\n // Validate agent exists\n const agent = agentRegistry.get(args.agent);\n if (!agent) {\n const available = agentRegistry\n .list()\n .map((a) => a.name)\n .join(\", \");\n printError(`Agent \"${args.agent}\" not found. Available: ${available}`);\n process.exitCode = 1;\n return;\n }\n\n if (args.detach) {\n await runDetached({\n agentName: args.agent,\n repo,\n prompt: args.prompt,\n priority: args.priority ?? \"medium\",\n metadata: parseMetadata(args.meta),\n bundledAgentsDir,\n customAgentsDir: existsSync(customAgentsDir) ? customAgentsDir : undefined,\n jsonOutput,\n });\n return;\n }\n\n // ─── Foreground mode (default) ──────────────────────\n const orchestrator = new Orchestrator(config);\n orchestrator.registerAgent(agent);\n orchestrator.registerWorkflow({\n name: `_run_${args.agent}`,\n description: `Direct dispatch to ${args.agent}`,\n steps: {\n run: { agent: args.agent },\n },\n });\n\n if (!jsonOutput) {\n orchestrator.on(\"*\", printProgress);\n }\n\n try {\n await orchestrator.start();\n\n const result = await orchestrator.dispatch({\n workflow: `_run_${args.agent}`,\n repo,\n prompt: args.prompt,\n priority: (args.priority as \"critical\" | \"high\" | \"medium\" | \"low\") ?? \"medium\",\n metadata: parseMetadata(args.meta),\n });\n\n if (jsonOutput) {\n printJson(result);\n } else {\n printResult(result, args.agent);\n }\n\n await orchestrator.shutdown();\n if (result.status !== \"success\") {\n process.exitCode = 1;\n }\n } catch (error) {\n await orchestrator.shutdown();\n printError(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n },\n});\n"],"mappings":"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","names":[]}
|