@neotx/cli 0.1.0-alpha.2 → 0.1.0-alpha.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +383 -0
  2. package/dist/activity-LWUVGQVN.js +86 -0
  3. package/dist/activity-LWUVGQVN.js.map +1 -0
  4. package/dist/{agents-Y6LREFXP.js → agents-PH3P7G7E.js} +2 -2
  5. package/dist/{chunk-CP54H7WA.js → chunk-3ZP3BQXB.js} +6 -11
  6. package/dist/chunk-3ZP3BQXB.js.map +1 -0
  7. package/dist/{chunk-TNJOG54I.js → chunk-F622JUDY.js} +6 -2
  8. package/dist/{chunk-TNJOG54I.js.map → chunk-F622JUDY.js.map} +1 -1
  9. package/dist/config-NYF6AJXU.js +282 -0
  10. package/dist/config-NYF6AJXU.js.map +1 -0
  11. package/dist/{cost-DNGKT4UC.js → cost-OQGFNBBG.js} +3 -8
  12. package/dist/cost-OQGFNBBG.js.map +1 -0
  13. package/dist/daemon/supervisor-worker.js +7 -1
  14. package/dist/daemon/supervisor-worker.js.map +1 -1
  15. package/dist/daemon/worker.js +31 -12
  16. package/dist/daemon/worker.js.map +1 -1
  17. package/dist/decision-PNZ2S2TU.js +362 -0
  18. package/dist/decision-PNZ2S2TU.js.map +1 -0
  19. package/dist/doctor-ZBO73UID.js +337 -0
  20. package/dist/doctor-ZBO73UID.js.map +1 -0
  21. package/dist/guide-UQRNA3FC.js +23 -0
  22. package/dist/guide-UQRNA3FC.js.map +1 -0
  23. package/dist/index.js +17 -9
  24. package/dist/index.js.map +1 -1
  25. package/dist/{init-YNSPTCA3.js → init-UYS6KS5U.js} +4 -20
  26. package/dist/init-UYS6KS5U.js.map +1 -0
  27. package/dist/log-PTHLI7ZN.js +141 -0
  28. package/dist/log-PTHLI7ZN.js.map +1 -0
  29. package/dist/{mcp-GH6CCW7A.js → mcp-XHZND5A4.js} +6 -1
  30. package/dist/mcp-XHZND5A4.js.map +1 -0
  31. package/dist/memory-6R22DFS7.js +292 -0
  32. package/dist/memory-6R22DFS7.js.map +1 -0
  33. package/dist/{run-KIU2ZE72.js → run-OF53USMD.js} +46 -20
  34. package/dist/run-OF53USMD.js.map +1 -0
  35. package/dist/{runs-CHA2JM5K.js → runs-TAASM3YF.js} +16 -12
  36. package/dist/runs-TAASM3YF.js.map +1 -0
  37. package/dist/status-LQOFOJJI.js +90 -0
  38. package/dist/status-LQOFOJJI.js.map +1 -0
  39. package/dist/{supervise-KIB2EYY4.js → supervise-J3GYBSOC.js} +33 -28
  40. package/dist/supervise-J3GYBSOC.js.map +1 -0
  41. package/dist/supervisor-3RUX5SPH.js +16 -0
  42. package/dist/supervisor-3RUX5SPH.js.map +1 -0
  43. package/dist/{tui-QS3RPHKH.js → tui-RYLR4OLF.js} +378 -43
  44. package/dist/tui-RYLR4OLF.js.map +1 -0
  45. package/dist/version-XVOAMGDD.js +26 -0
  46. package/dist/version-XVOAMGDD.js.map +1 -0
  47. package/dist/webhooks-PUKAHFHE.js +151 -0
  48. package/dist/webhooks-PUKAHFHE.js.map +1 -0
  49. package/package.json +22 -4
  50. package/dist/chunk-CP54H7WA.js.map +0 -1
  51. package/dist/cost-DNGKT4UC.js.map +0 -1
  52. package/dist/doctor-GC4NH7H6.js +0 -173
  53. package/dist/doctor-GC4NH7H6.js.map +0 -1
  54. package/dist/init-YNSPTCA3.js.map +0 -1
  55. package/dist/mcp-GH6CCW7A.js.map +0 -1
  56. package/dist/run-KIU2ZE72.js.map +0 -1
  57. package/dist/runs-CHA2JM5K.js.map +0 -1
  58. package/dist/supervise-KIB2EYY4.js.map +0 -1
  59. package/dist/tui-QS3RPHKH.js.map +0 -1
  60. /package/dist/{agents-Y6LREFXP.js.map → agents-PH3P7G7E.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/log.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { appendFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { appendLogBuffer, getSupervisorDir, MemoryStore } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printSuccess } from \"../output.js\";\n\nconst VALID_TYPES = [\n \"progress\",\n \"action\",\n \"decision\",\n \"blocker\",\n \"milestone\",\n \"discovery\",\n] as const;\ntype LogType = (typeof VALID_TYPES)[number];\n\n// Map log types to activity.jsonl entry types (preserve existing behavior)\nconst TYPE_MAP: Record<string, string> = {\n decision: \"decision\",\n action: \"action\",\n blocker: \"error\",\n progress: \"event\",\n milestone: \"event\",\n discovery: \"event\",\n};\n\n// Implicit routing: which target each type gets by default\nconst TARGET_MAP: Record<string, \"memory\" | \"knowledge\" | \"digest\"> = {\n progress: \"digest\",\n action: \"digest\",\n decision: \"memory\",\n milestone: \"memory\",\n blocker: \"memory\",\n discovery: \"knowledge\",\n};\n\nexport default defineCommand({\n meta: {\n name: \"log\",\n description: \"Log a structured progress report to the supervisor activity log\",\n },\n args: {\n type: {\n type: \"positional\",\n description: \"Report type: progress, action, decision, blocker, milestone, discovery\",\n required: true,\n },\n message: {\n type: \"positional\",\n description: \"Message to log\",\n required: true,\n },\n name: {\n type: \"string\",\n description: \"Supervisor instance name\",\n default: \"supervisor\",\n },\n memory: {\n type: \"boolean\",\n description: \"Override routing: send to memory target\",\n default: false,\n },\n knowledge: {\n type: \"boolean\",\n description: \"Override routing: send to knowledge target\",\n default: false,\n },\n repo: {\n type: \"string\",\n description: \"Repository path\",\n },\n procedure: {\n type: \"boolean\",\n description: \"Also write as a procedure memory entry\",\n default: false,\n },\n },\n async run({ args }) {\n const type = args.type as string;\n if (!VALID_TYPES.includes(type as LogType)) {\n printError(`Invalid type \"${type}\". Must be one of: ${VALID_TYPES.join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n const dir = getSupervisorDir(args.name);\n const now = new Date().toISOString();\n const id = randomUUID();\n\n // Resolve agent/run from env vars or flags\n const agent = process.env.NEO_AGENT_NAME ?? undefined;\n const runId = process.env.NEO_RUN_ID ?? undefined;\n const repo = (args.repo as string | undefined) ?? process.env.NEO_REPOSITORY ?? undefined;\n\n // Resolve target with flag overrides\n let target: \"memory\" | \"knowledge\" | \"digest\" = TARGET_MAP[type] ?? \"digest\";\n if (args.memory) target = \"memory\";\n if (args.knowledge) target = \"knowledge\";\n\n // 1. Always: append to activity.jsonl (existing behavior)\n const activityEntry = {\n id,\n type: TYPE_MAP[type] ?? \"event\",\n summary: args.message,\n timestamp: now,\n };\n await appendFile(`${dir}/activity.jsonl`, `${JSON.stringify(activityEntry)}\\n`, \"utf-8\");\n\n // 2. Always: append to log-buffer.jsonl via shared helper\n await appendLogBuffer(dir, {\n id,\n type: type as \"progress\" | \"action\" | \"decision\" | \"blocker\" | \"milestone\" | \"discovery\",\n message: args.message,\n agent,\n runId,\n repo,\n target,\n timestamp: now,\n });\n\n // 3. Write to memory store for knowledge/procedure entries\n if (target === \"knowledge\" || args.procedure) {\n try {\n const store = new MemoryStore(path.join(dir, \"memory.sqlite\"));\n await store.write({\n type: args.procedure ? \"procedure\" : \"fact\",\n scope: repo ?? \"global\",\n content: args.message,\n source: agent ?? \"user\",\n runId,\n });\n store.close();\n } catch {\n // Best-effort — don't crash CLI if store write fails\n }\n }\n\n // 4. If blocker: also append to inbox.jsonl (wake up heartbeat)\n if (type === \"blocker\") {\n const inboxMessage = {\n id: randomUUID(),\n from: \"agent\" as const,\n text: `[BLOCKER]${agent ? ` (${agent})` : \"\"} ${args.message}`,\n timestamp: now,\n };\n await appendFile(`${dir}/inbox.jsonl`, `${JSON.stringify(inboxMessage)}\\n`, \"utf-8\");\n }\n\n printSuccess(`Logged: [${type}] ${args.message.slice(0, 100)}`);\n },\n});\n"],"mappings":"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","names":[]}
@@ -17,6 +17,7 @@ var MCP_PRESETS = {
17
17
  type: "stdio",
18
18
  command: "npx",
19
19
  args: ["-y", "@anthropic/linear-mcp-server"],
20
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code
20
21
  env: { LINEAR_API_KEY: "${LINEAR_API_KEY}" }
21
22
  },
22
23
  envVars: ["LINEAR_API_KEY"]
@@ -26,6 +27,7 @@ var MCP_PRESETS = {
26
27
  type: "stdio",
27
28
  command: "npx",
28
29
  args: ["-y", "@notionhq/notion-mcp-server"],
30
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code
29
31
  env: { NOTION_TOKEN: "${NOTION_TOKEN}" }
30
32
  },
31
33
  envVars: ["NOTION_TOKEN"]
@@ -35,6 +37,7 @@ var MCP_PRESETS = {
35
37
  type: "stdio",
36
38
  command: "npx",
37
39
  args: ["-y", "@modelcontextprotocol/server-github"],
40
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code
38
41
  env: { GITHUB_PERSONAL_ACCESS_TOKEN: "${GITHUB_TOKEN}" }
39
42
  },
40
43
  envVars: ["GITHUB_TOKEN"]
@@ -44,6 +47,7 @@ var MCP_PRESETS = {
44
47
  type: "stdio",
45
48
  command: "npx",
46
49
  args: ["-y", "@anthropic/jira-mcp-server"],
50
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholders interpolated at runtime by Claude Code
47
51
  env: { JIRA_API_TOKEN: "${JIRA_API_TOKEN}", JIRA_URL: "${JIRA_URL}" }
48
52
  },
49
53
  envVars: ["JIRA_API_TOKEN", "JIRA_URL"]
@@ -53,6 +57,7 @@ var MCP_PRESETS = {
53
57
  type: "stdio",
54
58
  command: "npx",
55
59
  args: ["-y", "@modelcontextprotocol/server-slack"],
60
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code
56
61
  env: { SLACK_BOT_TOKEN: "${SLACK_BOT_TOKEN}" }
57
62
  },
58
63
  envVars: ["SLACK_BOT_TOKEN"]
@@ -214,4 +219,4 @@ var mcp_default = defineCommand({
214
219
  export {
215
220
  mcp_default as default
216
221
  };
217
- //# sourceMappingURL=mcp-GH6CCW7A.js.map
222
+ //# sourceMappingURL=mcp-XHZND5A4.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 // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code\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\", \"@notionhq/notion-mcp-server\"],\n // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code\n env: { NOTION_TOKEN: \"${NOTION_TOKEN}\" },\n },\n envVars: [\"NOTION_TOKEN\"],\n },\n github: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@modelcontextprotocol/server-github\"],\n // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code\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 // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholders interpolated at runtime by Claude Code\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 // biome-ignore lint/suspicious/noTemplateCurlyInString: Template placeholder interpolated at runtime by Claude Code\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,292 @@
1
+ import {
2
+ printError,
3
+ printSuccess,
4
+ printTable
5
+ } from "./chunk-YQIWMDXL.js";
6
+
7
+ // src/commands/memory.ts
8
+ import path from "path";
9
+ import { getSupervisorDir, LocalEmbedder, MemoryStore } from "@neotx/core";
10
+ import { defineCommand } from "citty";
11
+ var VALID_TYPES = ["fact", "procedure", "episode", "focus", "feedback", "task"];
12
+ function parseDuration(input) {
13
+ const match = input.match(/^(\d+)(h|m)$/);
14
+ if (!match) return void 0;
15
+ const value = Number(match[1]);
16
+ const unit = match[2];
17
+ const ms = unit === "h" ? value * 60 * 60 * 1e3 : value * 60 * 1e3;
18
+ return new Date(Date.now() + ms).toISOString();
19
+ }
20
+ function truncate(text, max) {
21
+ return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
22
+ }
23
+ function createEmbedder() {
24
+ try {
25
+ return new LocalEmbedder();
26
+ } catch {
27
+ return null;
28
+ }
29
+ }
30
+ function openStore(name, withEmbeddings = false) {
31
+ const dir = getSupervisorDir(name);
32
+ const embedder = withEmbeddings ? createEmbedder() : null;
33
+ return new MemoryStore(path.join(dir, "memory.sqlite"), embedder);
34
+ }
35
+ function formatResultsTable(results) {
36
+ printTable(
37
+ ["ID", "TYPE", "SCOPE", "CONTENT", "ACCESSES"],
38
+ results.map((m) => [m.id, m.type, m.scope, truncate(m.content, 60), String(m.accessCount)])
39
+ );
40
+ }
41
+ async function handleWrite(args) {
42
+ if (!args.value) {
43
+ printError("Usage: neo memory write <content> --type <type> [--scope <scope>]");
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ const type = args.type ?? "fact";
48
+ if (!VALID_TYPES.includes(type)) {
49
+ printError(`Invalid type "${type}". Must be one of: ${VALID_TYPES.join(", ")}`);
50
+ process.exitCode = 1;
51
+ return;
52
+ }
53
+ let expiresAt;
54
+ if (args.expires) {
55
+ expiresAt = parseDuration(args.expires);
56
+ if (!expiresAt) {
57
+ printError('Invalid --expires format. Use e.g. "2h" or "30m".');
58
+ process.exitCode = 1;
59
+ return;
60
+ }
61
+ }
62
+ const store = openStore(args.name, true);
63
+ try {
64
+ const tags = args.tags ? args.tags.split(",").map((t) => t.trim()) : [];
65
+ const id = await store.write({
66
+ type,
67
+ scope: args.scope,
68
+ content: args.value,
69
+ source: args.source,
70
+ tags,
71
+ expiresAt,
72
+ severity: args.severity,
73
+ category: args.category,
74
+ outcome: args.outcome
75
+ });
76
+ printSuccess(`Memory written: ${id}`);
77
+ } finally {
78
+ store.close();
79
+ }
80
+ }
81
+ function handleForget(args) {
82
+ if (!args.value) {
83
+ printError("Usage: neo memory forget <id>");
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ const store = openStore(args.name);
88
+ try {
89
+ store.forget(args.value);
90
+ printSuccess(`Memory forgotten: ${args.value}`);
91
+ } finally {
92
+ store.close();
93
+ }
94
+ }
95
+ var VALID_OUTCOMES = ["pending", "in_progress", "done", "blocked", "abandoned"];
96
+ function handleUpdate(args) {
97
+ if (!args.value) {
98
+ printError('Usage: neo memory update <id> ["new content"] [--outcome <status>]');
99
+ process.exitCode = 1;
100
+ return;
101
+ }
102
+ const argv = process.argv;
103
+ const updateIdx = argv.indexOf("update");
104
+ const idArg = argv[updateIdx + 1];
105
+ const contentArg = argv[updateIdx + 2];
106
+ if (args.outcome && !VALID_OUTCOMES.includes(args.outcome)) {
107
+ printError(`Invalid outcome "${args.outcome}". Must be one of: ${VALID_OUTCOMES.join(", ")}`);
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+ const isContentArgAFlag = contentArg?.startsWith("--");
112
+ const hasContent = contentArg && !isContentArgAFlag;
113
+ if (!hasContent && !args.outcome) {
114
+ printError('Usage: neo memory update <id> ["new content"] [--outcome <status>]');
115
+ process.exitCode = 1;
116
+ return;
117
+ }
118
+ if (!idArg) {
119
+ printError('Usage: neo memory update <id> ["new content"] [--outcome <status>]');
120
+ process.exitCode = 1;
121
+ return;
122
+ }
123
+ const store = openStore(args.name);
124
+ try {
125
+ if (args.outcome) {
126
+ store.updateFields(idArg, {
127
+ ...hasContent && { content: contentArg },
128
+ outcome: args.outcome
129
+ });
130
+ } else {
131
+ store.update(idArg, contentArg);
132
+ }
133
+ printSuccess(`Memory updated: ${idArg}`);
134
+ } finally {
135
+ store.close();
136
+ }
137
+ }
138
+ async function handleSearch(args) {
139
+ if (!args.value) {
140
+ printError("Usage: neo memory search <query>");
141
+ process.exitCode = 1;
142
+ return;
143
+ }
144
+ const store = openStore(args.name, true);
145
+ try {
146
+ const results = await store.search(args.value, {
147
+ ...args.scope !== "global" && { scope: args.scope },
148
+ ...args.type && { types: [args.type] }
149
+ });
150
+ if (results.length === 0) {
151
+ console.log("No memories found.");
152
+ return;
153
+ }
154
+ formatResultsTable(results);
155
+ } finally {
156
+ store.close();
157
+ }
158
+ }
159
+ function handleList(args) {
160
+ const store = openStore(args.name);
161
+ try {
162
+ const results = store.query({
163
+ ...args.scope !== "global" && { scope: args.scope },
164
+ ...args.type && { types: [args.type] }
165
+ });
166
+ if (results.length === 0) {
167
+ console.log("No memories found.");
168
+ return;
169
+ }
170
+ formatResultsTable(results);
171
+ } finally {
172
+ store.close();
173
+ }
174
+ }
175
+ function handleStats(args) {
176
+ const store = openStore(args.name);
177
+ try {
178
+ const s = store.stats();
179
+ console.log(`Total memories: ${s.total}
180
+ `);
181
+ if (Object.keys(s.byType).length > 0) {
182
+ printTable(
183
+ ["TYPE", "COUNT"],
184
+ Object.entries(s.byType).map(([t, c]) => [t, String(c)])
185
+ );
186
+ console.log();
187
+ }
188
+ if (Object.keys(s.byScope).length > 0) {
189
+ printTable(
190
+ ["SCOPE", "COUNT"],
191
+ Object.entries(s.byScope).map(([sc, c]) => [sc, String(c)])
192
+ );
193
+ }
194
+ } finally {
195
+ store.close();
196
+ }
197
+ }
198
+ var memory_default = defineCommand({
199
+ meta: {
200
+ name: "memory",
201
+ description: "Manage the supervisor memory store"
202
+ },
203
+ args: {
204
+ action: {
205
+ type: "positional",
206
+ description: "Action: write, forget, update, search, list, stats",
207
+ required: true
208
+ },
209
+ value: {
210
+ type: "positional",
211
+ description: "Content or ID depending on action",
212
+ required: false
213
+ },
214
+ type: {
215
+ type: "string",
216
+ description: "Memory type: fact, procedure, episode, focus, feedback, task"
217
+ },
218
+ scope: {
219
+ type: "string",
220
+ description: "Scope: global or repo path",
221
+ default: "global"
222
+ },
223
+ source: {
224
+ type: "string",
225
+ description: "Source: developer, reviewer, supervisor, user",
226
+ default: "user"
227
+ },
228
+ expires: {
229
+ type: "string",
230
+ description: "TTL for focus entries (e.g. 2h, 30m)"
231
+ },
232
+ outcome: {
233
+ type: "string",
234
+ description: "Task outcome: pending, in_progress, done, blocked, abandoned"
235
+ },
236
+ severity: {
237
+ type: "string",
238
+ description: "Priority: critical, high, medium, low"
239
+ },
240
+ category: {
241
+ type: "string",
242
+ description: "Context reference (e.g. 'neo runs abc123' or 'cat notes/plan.md')"
243
+ },
244
+ tags: {
245
+ type: "string",
246
+ description: "Comma-separated tags (e.g. 'initiative:auth,depends:mem_abc')"
247
+ },
248
+ name: {
249
+ type: "string",
250
+ description: "Supervisor name",
251
+ default: "supervisor"
252
+ }
253
+ },
254
+ async run({ args }) {
255
+ const action = args.action;
256
+ const parsed = {
257
+ value: args.value,
258
+ type: args.type,
259
+ scope: args.scope,
260
+ source: args.source,
261
+ expires: args.expires,
262
+ name: args.name,
263
+ outcome: args.outcome,
264
+ severity: args.severity,
265
+ category: args.category,
266
+ tags: args.tags
267
+ };
268
+ switch (action) {
269
+ case "write":
270
+ return handleWrite(parsed);
271
+ case "forget":
272
+ return handleForget(parsed);
273
+ case "update":
274
+ return handleUpdate(parsed);
275
+ case "search":
276
+ return handleSearch(parsed);
277
+ case "list":
278
+ return handleList(parsed);
279
+ case "stats":
280
+ return handleStats(parsed);
281
+ default:
282
+ printError(
283
+ `Unknown action "${action}". Must be one of: write, forget, update, search, list, stats`
284
+ );
285
+ process.exitCode = 1;
286
+ }
287
+ }
288
+ });
289
+ export {
290
+ memory_default as default
291
+ };
292
+ //# sourceMappingURL=memory-6R22DFS7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { Embedder, MemoryEntry, MemoryType } from \"@neotx/core\";\nimport { getSupervisorDir, LocalEmbedder, MemoryStore } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printSuccess, printTable } from \"../output.js\";\n\nconst VALID_TYPES = [\"fact\", \"procedure\", \"episode\", \"focus\", \"feedback\", \"task\"] as const;\n\ninterface ParsedArgs {\n value: string | undefined;\n type: string | undefined;\n scope: string;\n source: string;\n expires: string | undefined;\n name: string;\n outcome: string | undefined;\n severity: string | undefined;\n category: string | undefined;\n tags: string | undefined;\n}\n\nfunction parseDuration(input: string): string | undefined {\n const match = input.match(/^(\\d+)(h|m)$/);\n if (!match) return undefined;\n\n const value = Number(match[1]);\n const unit = match[2];\n const ms = unit === \"h\" ? value * 60 * 60 * 1000 : value * 60 * 1000;\n return new Date(Date.now() + ms).toISOString();\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\nfunction createEmbedder(): Embedder | null {\n try {\n return new LocalEmbedder();\n } catch {\n return null;\n }\n}\n\nfunction openStore(name: string, withEmbeddings = false): MemoryStore {\n const dir = getSupervisorDir(name);\n const embedder = withEmbeddings ? createEmbedder() : null;\n return new MemoryStore(path.join(dir, \"memory.sqlite\"), embedder);\n}\n\nfunction formatResultsTable(results: MemoryEntry[]): void {\n printTable(\n [\"ID\", \"TYPE\", \"SCOPE\", \"CONTENT\", \"ACCESSES\"],\n results.map((m) => [m.id, m.type, m.scope, truncate(m.content, 60), String(m.accessCount)]),\n );\n}\n\nasync function handleWrite(args: ParsedArgs): Promise<void> {\n if (!args.value) {\n printError(\"Usage: neo memory write <content> --type <type> [--scope <scope>]\");\n process.exitCode = 1;\n return;\n }\n\n const type = args.type ?? \"fact\";\n if (!VALID_TYPES.includes(type as MemoryType)) {\n printError(`Invalid type \"${type}\". Must be one of: ${VALID_TYPES.join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n let expiresAt: string | undefined;\n if (args.expires) {\n expiresAt = parseDuration(args.expires);\n if (!expiresAt) {\n printError('Invalid --expires format. Use e.g. \"2h\" or \"30m\".');\n process.exitCode = 1;\n return;\n }\n }\n\n const store = openStore(args.name, true);\n try {\n const tags = args.tags ? args.tags.split(\",\").map((t) => t.trim()) : [];\n const id = await store.write({\n type: type as MemoryType,\n scope: args.scope,\n content: args.value,\n source: args.source,\n tags,\n expiresAt,\n severity: args.severity,\n category: args.category,\n outcome: args.outcome,\n });\n printSuccess(`Memory written: ${id}`);\n } finally {\n store.close();\n }\n}\n\nfunction handleForget(args: ParsedArgs): void {\n if (!args.value) {\n printError(\"Usage: neo memory forget <id>\");\n process.exitCode = 1;\n return;\n }\n\n const store = openStore(args.name);\n try {\n store.forget(args.value);\n printSuccess(`Memory forgotten: ${args.value}`);\n } finally {\n store.close();\n }\n}\n\nconst VALID_OUTCOMES = [\"pending\", \"in_progress\", \"done\", \"blocked\", \"abandoned\"] as const;\n\nfunction handleUpdate(args: ParsedArgs): void {\n if (!args.value) {\n printError('Usage: neo memory update <id> [\"new content\"] [--outcome <status>]');\n process.exitCode = 1;\n return;\n }\n\n // The ID is in value, but we need content too.\n // citty only supports 2 positional args — content comes after ID.\n const argv = process.argv;\n const updateIdx = argv.indexOf(\"update\");\n const idArg = argv[updateIdx + 1];\n const contentArg = argv[updateIdx + 2];\n\n // Validate outcome if provided\n if (args.outcome && !VALID_OUTCOMES.includes(args.outcome as (typeof VALID_OUTCOMES)[number])) {\n printError(`Invalid outcome \"${args.outcome}\". Must be one of: ${VALID_OUTCOMES.join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n // Determine if contentArg is actually content or a flag\n const isContentArgAFlag = contentArg?.startsWith(\"--\");\n const hasContent = contentArg && !isContentArgAFlag;\n\n // Need either content or --outcome\n if (!hasContent && !args.outcome) {\n printError('Usage: neo memory update <id> [\"new content\"] [--outcome <status>]');\n process.exitCode = 1;\n return;\n }\n\n // ID is required at this point — validated by args.value check above\n if (!idArg) {\n printError('Usage: neo memory update <id> [\"new content\"] [--outcome <status>]');\n process.exitCode = 1;\n return;\n }\n\n const store = openStore(args.name);\n try {\n // Use updateFields when --outcome is provided\n if (args.outcome) {\n store.updateFields(idArg, {\n ...(hasContent && { content: contentArg }),\n outcome: args.outcome,\n });\n } else {\n // contentArg is guaranteed to be defined when hasContent is true and no outcome\n store.update(idArg, contentArg as string);\n }\n printSuccess(`Memory updated: ${idArg}`);\n } finally {\n store.close();\n }\n}\n\nasync function handleSearch(args: ParsedArgs): Promise<void> {\n if (!args.value) {\n printError(\"Usage: neo memory search <query>\");\n process.exitCode = 1;\n return;\n }\n\n const store = openStore(args.name, true);\n try {\n const results = await store.search(args.value, {\n ...(args.scope !== \"global\" && { scope: args.scope }),\n ...(args.type && { types: [args.type as MemoryType] }),\n });\n\n if (results.length === 0) {\n console.log(\"No memories found.\");\n return;\n }\n\n formatResultsTable(results);\n } finally {\n store.close();\n }\n}\n\nfunction handleList(args: ParsedArgs): void {\n const store = openStore(args.name);\n try {\n const results = store.query({\n ...(args.scope !== \"global\" && { scope: args.scope }),\n ...(args.type && { types: [args.type as MemoryType] }),\n });\n\n if (results.length === 0) {\n console.log(\"No memories found.\");\n return;\n }\n\n formatResultsTable(results);\n } finally {\n store.close();\n }\n}\n\nfunction handleStats(args: ParsedArgs): void {\n const store = openStore(args.name);\n try {\n const s = store.stats();\n console.log(`Total memories: ${s.total}\\n`);\n\n if (Object.keys(s.byType).length > 0) {\n printTable(\n [\"TYPE\", \"COUNT\"],\n Object.entries(s.byType).map(([t, c]) => [t, String(c)]),\n );\n console.log();\n }\n\n if (Object.keys(s.byScope).length > 0) {\n printTable(\n [\"SCOPE\", \"COUNT\"],\n Object.entries(s.byScope).map(([sc, c]) => [sc, String(c)]),\n );\n }\n } finally {\n store.close();\n }\n}\n\nexport default defineCommand({\n meta: {\n name: \"memory\",\n description: \"Manage the supervisor memory store\",\n },\n args: {\n action: {\n type: \"positional\",\n description: \"Action: write, forget, update, search, list, stats\",\n required: true,\n },\n value: {\n type: \"positional\",\n description: \"Content or ID depending on action\",\n required: false,\n },\n type: {\n type: \"string\",\n description: \"Memory type: fact, procedure, episode, focus, feedback, task\",\n },\n scope: {\n type: \"string\",\n description: \"Scope: global or repo path\",\n default: \"global\",\n },\n source: {\n type: \"string\",\n description: \"Source: developer, reviewer, supervisor, user\",\n default: \"user\",\n },\n expires: {\n type: \"string\",\n description: \"TTL for focus entries (e.g. 2h, 30m)\",\n },\n outcome: {\n type: \"string\",\n description: \"Task outcome: pending, in_progress, done, blocked, abandoned\",\n },\n severity: {\n type: \"string\",\n description: \"Priority: critical, high, medium, low\",\n },\n category: {\n type: \"string\",\n description: \"Context reference (e.g. 'neo runs abc123' or 'cat notes/plan.md')\",\n },\n tags: {\n type: \"string\",\n description: \"Comma-separated tags (e.g. 'initiative:auth,depends:mem_abc')\",\n },\n name: {\n type: \"string\",\n description: \"Supervisor name\",\n default: \"supervisor\",\n },\n },\n async run({ args }) {\n const action = args.action as string;\n const parsed: ParsedArgs = {\n value: args.value as string | undefined,\n type: args.type as string | undefined,\n scope: args.scope as string,\n source: args.source as string,\n expires: args.expires as string | undefined,\n name: args.name as string,\n outcome: args.outcome as string | undefined,\n severity: args.severity as string | undefined,\n category: args.category as string | undefined,\n tags: args.tags as string | undefined,\n };\n\n switch (action) {\n case \"write\":\n return handleWrite(parsed);\n case \"forget\":\n return handleForget(parsed);\n case \"update\":\n return handleUpdate(parsed);\n case \"search\":\n return handleSearch(parsed);\n case \"list\":\n return handleList(parsed);\n case \"stats\":\n return handleStats(parsed);\n default:\n printError(\n `Unknown action \"${action}\". Must be one of: write, forget, update, search, list, stats`,\n );\n process.exitCode = 1;\n }\n },\n});\n"],"mappings":"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","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveAgentsDir
3
- } from "./chunk-TNJOG54I.js";
3
+ } from "./chunk-F622JUDY.js";
4
4
  import {
5
5
  printError,
6
6
  printJson,
@@ -8,10 +8,10 @@ import {
8
8
  } from "./chunk-YQIWMDXL.js";
9
9
 
10
10
  // src/commands/run.ts
11
- import { fork } from "child_process";
11
+ import { spawn } from "child_process";
12
12
  import { randomUUID } from "crypto";
13
13
  import { existsSync } from "fs";
14
- import { mkdir, writeFile } from "fs/promises";
14
+ import { mkdir, readFile, writeFile } from "fs/promises";
15
15
  import path from "path";
16
16
  import { fileURLToPath } from "url";
17
17
  import {
@@ -60,6 +60,9 @@ function printResult(result, agentName) {
60
60
  if (result.branch) {
61
61
  console.log(`Branch: ${result.branch}`);
62
62
  }
63
+ if (result.prUrl) {
64
+ console.log(`PR: ${result.prUrl}`);
65
+ }
63
66
  const stepResult = Object.values(result.steps)[0];
64
67
  const output = stepResult?.output ?? result.summary;
65
68
  if (output) {
@@ -75,7 +78,7 @@ async function runDetached(params) {
75
78
  const persistedRun = {
76
79
  version: 1,
77
80
  runId,
78
- workflow: `_run_${params.agentName}`,
81
+ agent: params.agentName,
79
82
  repo: params.repo,
80
83
  prompt: params.prompt,
81
84
  status: "running",
@@ -96,6 +99,7 @@ async function runDetached(params) {
96
99
  agentName: params.agentName,
97
100
  repo: params.repo,
98
101
  prompt: params.prompt,
102
+ branch: params.branch,
99
103
  priority: params.priority,
100
104
  metadata: params.metadata,
101
105
  bundledAgentsDir: params.bundledAgentsDir,
@@ -104,11 +108,22 @@ async function runDetached(params) {
104
108
  "utf-8"
105
109
  );
106
110
  const workerPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "daemon", "worker.js");
107
- const child = fork(workerPath, [runId, repoSlug], {
111
+ const child = spawn(process.execPath, [workerPath, runId, repoSlug], {
108
112
  detached: true,
109
- stdio: "ignore"
113
+ stdio: "ignore",
114
+ env: process.env
110
115
  });
111
116
  child.unref();
117
+ if (child.pid) {
118
+ const runFilePath = path.join(runsDir, `${runId}.json`);
119
+ try {
120
+ const raw = await readFile(runFilePath, "utf-8");
121
+ const run = JSON.parse(raw);
122
+ run.pid = child.pid;
123
+ await writeFile(runFilePath, JSON.stringify(run, null, 2), "utf-8");
124
+ } catch {
125
+ }
126
+ }
112
127
  if (params.jsonOutput) {
113
128
  printJson({ runId, status: "detached", pid: child.pid });
114
129
  } else {
@@ -120,7 +135,7 @@ async function runDetached(params) {
120
135
  var run_default = defineCommand({
121
136
  meta: {
122
137
  name: "run",
123
- description: "Dispatch an agent to execute a task in an isolated worktree"
138
+ description: "Dispatch an agent to execute a task in an isolated clone"
124
139
  },
125
140
  args: {
126
141
  agent: {
@@ -138,13 +153,17 @@ var run_default = defineCommand({
138
153
  description: "Task description for the agent",
139
154
  required: true
140
155
  },
156
+ branch: {
157
+ type: "string",
158
+ description: "Branch name for the session clone (required for writable agents)"
159
+ },
141
160
  priority: {
142
161
  type: "string",
143
162
  description: "Priority level: critical, high, medium, low"
144
163
  },
145
164
  meta: {
146
165
  type: "string",
147
- description: "Metadata as JSON string"
166
+ description: "Metadata as JSON string (for traceability: ticketId, stage, etc.)"
148
167
  },
149
168
  output: {
150
169
  type: "string",
@@ -154,7 +173,17 @@ var run_default = defineCommand({
154
173
  type: "boolean",
155
174
  alias: "d",
156
175
  description: "Run in background and return immediately with the run ID",
176
+ default: true
177
+ },
178
+ sync: {
179
+ type: "boolean",
180
+ alias: "s",
181
+ description: "Run in foreground (blocking) instead of detached",
157
182
  default: false
183
+ },
184
+ "git-strategy": {
185
+ type: "string",
186
+ description: "Git strategy: pr (create PR), branch (push only, default)"
158
187
  }
159
188
  },
160
189
  async run({ args }) {
@@ -175,11 +204,12 @@ var run_default = defineCommand({
175
204
  process.exitCode = 1;
176
205
  return;
177
206
  }
178
- if (args.detach) {
207
+ if (args.detach && !args.sync) {
179
208
  await runDetached({
180
209
  agentName: args.agent,
181
210
  repo,
182
211
  prompt: args.prompt,
212
+ branch: args.branch,
183
213
  priority: args.priority ?? "medium",
184
214
  metadata: parseMetadata(args.meta),
185
215
  bundledAgentsDir,
@@ -188,26 +218,22 @@ var run_default = defineCommand({
188
218
  });
189
219
  return;
190
220
  }
191
- const orchestrator = new Orchestrator(config);
221
+ const orchestrator = new Orchestrator(config, { skipOrphanRecovery: true });
192
222
  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
223
  if (!jsonOutput) {
201
224
  orchestrator.on("*", printProgress);
202
225
  }
203
226
  try {
204
227
  await orchestrator.start();
228
+ const gitStrategy = args["git-strategy"];
205
229
  const result = await orchestrator.dispatch({
206
- workflow: `_run_${args.agent}`,
230
+ agent: args.agent,
207
231
  repo,
208
232
  prompt: args.prompt,
233
+ ...args.branch ? { branch: args.branch } : {},
209
234
  priority: args.priority ?? "medium",
210
- metadata: parseMetadata(args.meta)
235
+ metadata: parseMetadata(args.meta),
236
+ ...gitStrategy ? { gitStrategy } : {}
211
237
  });
212
238
  if (jsonOutput) {
213
239
  printJson(result);
@@ -228,4 +254,4 @@ var run_default = defineCommand({
228
254
  export {
229
255
  run_default as default
230
256
  };
231
- //# sourceMappingURL=run-KIU2ZE72.js.map
257
+ //# sourceMappingURL=run-OF53USMD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/run.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, 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 if (result.prUrl) {\n console.log(`PR: ${result.prUrl}`);\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 branch: string | undefined;\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 agent: 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 branch: params.branch,\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 // Use spawn (not fork) so the child gets its own process group via detached: true.\n // fork() shares the parent's process group, so when the SDK kills the Bash\n // process tree the worker dies too.\n const child = spawn(process.execPath, [workerPath, runId, repoSlug], {\n detached: true,\n stdio: \"ignore\",\n env: process.env,\n });\n child.unref();\n\n // Write PID to persisted run immediately so other workers' recoverOrphanedRuns()\n // can see this process is alive (prevents false orphan detection on concurrent launches)\n if (child.pid) {\n const runFilePath = path.join(runsDir, `${runId}.json`);\n try {\n const raw = await readFile(runFilePath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n run.pid = child.pid;\n await writeFile(runFilePath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch {\n // Non-critical — worker will write PID on startup anyway\n }\n }\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 clone\",\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 branch: {\n type: \"string\",\n description: \"Branch name for the session clone (required for writable agents)\",\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 (for traceability: ticketId, stage, etc.)\",\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: true,\n },\n sync: {\n type: \"boolean\",\n alias: \"s\",\n description: \"Run in foreground (blocking) instead of detached\",\n default: false,\n },\n \"git-strategy\": {\n type: \"string\",\n description: \"Git strategy: pr (create PR), branch (push only, default)\",\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 && !args.sync) {\n await runDetached({\n agentName: args.agent,\n repo,\n prompt: args.prompt,\n branch: args.branch,\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, { skipOrphanRecovery: true });\n orchestrator.registerAgent(agent);\n\n if (!jsonOutput) {\n orchestrator.on(\"*\", printProgress);\n }\n\n try {\n await orchestrator.start();\n\n const gitStrategy = args[\"git-strategy\"] as \"pr\" | \"branch\" | undefined;\n const result = await orchestrator.dispatch({\n agent: args.agent,\n repo,\n prompt: args.prompt,\n ...(args.branch ? { branch: args.branch } : {}),\n priority: (args.priority as \"critical\" | \"high\" | \"medium\" | \"low\") ?? \"medium\",\n metadata: parseMetadata(args.meta),\n ...(gitStrategy ? { gitStrategy } : {}),\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":[]}