@neotx/cli 0.1.0-alpha.2 → 0.1.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +383 -0
- package/dist/activity-LWUVGQVN.js +86 -0
- package/dist/activity-LWUVGQVN.js.map +1 -0
- package/dist/{agents-Y6LREFXP.js → agents-PH3P7G7E.js} +2 -2
- package/dist/{chunk-CP54H7WA.js → chunk-3ZP3BQXB.js} +6 -11
- package/dist/chunk-3ZP3BQXB.js.map +1 -0
- package/dist/{chunk-TNJOG54I.js → chunk-F622JUDY.js} +6 -2
- package/dist/{chunk-TNJOG54I.js.map → chunk-F622JUDY.js.map} +1 -1
- package/dist/config-NYF6AJXU.js +282 -0
- package/dist/config-NYF6AJXU.js.map +1 -0
- package/dist/{cost-DNGKT4UC.js → cost-OQGFNBBG.js} +3 -8
- package/dist/cost-OQGFNBBG.js.map +1 -0
- package/dist/daemon/supervisor-worker.js +7 -1
- package/dist/daemon/supervisor-worker.js.map +1 -1
- package/dist/daemon/worker.js +27 -10
- package/dist/daemon/worker.js.map +1 -1
- package/dist/decision-PNZ2S2TU.js +362 -0
- package/dist/decision-PNZ2S2TU.js.map +1 -0
- package/dist/doctor-ZBO73UID.js +337 -0
- package/dist/doctor-ZBO73UID.js.map +1 -0
- package/dist/guide-UQRNA3FC.js +23 -0
- package/dist/guide-UQRNA3FC.js.map +1 -0
- package/dist/index.js +17 -9
- package/dist/index.js.map +1 -1
- package/dist/{init-YNSPTCA3.js → init-UYS6KS5U.js} +4 -20
- package/dist/init-UYS6KS5U.js.map +1 -0
- package/dist/log-PTHLI7ZN.js +141 -0
- package/dist/log-PTHLI7ZN.js.map +1 -0
- package/dist/{mcp-GH6CCW7A.js → mcp-XHZND5A4.js} +6 -1
- package/dist/mcp-XHZND5A4.js.map +1 -0
- package/dist/memory-6R22DFS7.js +292 -0
- package/dist/memory-6R22DFS7.js.map +1 -0
- package/dist/{run-KIU2ZE72.js → run-OF53USMD.js} +46 -20
- package/dist/run-OF53USMD.js.map +1 -0
- package/dist/{runs-CHA2JM5K.js → runs-TAASM3YF.js} +16 -12
- package/dist/runs-TAASM3YF.js.map +1 -0
- package/dist/status-LQOFOJJI.js +90 -0
- package/dist/status-LQOFOJJI.js.map +1 -0
- package/dist/{supervise-KIB2EYY4.js → supervise-FI6MYULH.js} +33 -28
- package/dist/supervise-FI6MYULH.js.map +1 -0
- package/dist/supervisor-3RUX5SPH.js +16 -0
- package/dist/supervisor-3RUX5SPH.js.map +1 -0
- package/dist/{tui-QS3RPHKH.js → tui-JJ6CD2YW.js} +377 -43
- package/dist/tui-JJ6CD2YW.js.map +1 -0
- package/dist/version-XVOAMGDD.js +26 -0
- package/dist/version-XVOAMGDD.js.map +1 -0
- package/dist/webhooks-PUKAHFHE.js +151 -0
- package/dist/webhooks-PUKAHFHE.js.map +1 -0
- package/package.json +22 -4
- package/dist/chunk-CP54H7WA.js.map +0 -1
- package/dist/cost-DNGKT4UC.js.map +0 -1
- package/dist/doctor-GC4NH7H6.js +0 -173
- package/dist/doctor-GC4NH7H6.js.map +0 -1
- package/dist/init-YNSPTCA3.js.map +0 -1
- package/dist/mcp-GH6CCW7A.js.map +0 -1
- package/dist/run-KIU2ZE72.js.map +0 -1
- package/dist/runs-CHA2JM5K.js.map +0 -1
- package/dist/supervise-KIB2EYY4.js.map +0 -1
- package/dist/tui-QS3RPHKH.js.map +0 -1
- /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-
|
|
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-
|
|
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 {
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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-
|
|
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":[]}
|