@neotx/cli 0.1.0-alpha.1 → 0.1.0-alpha.11
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 +381 -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/{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 +26 -2
- package/dist/daemon/worker.js.map +1 -1
- package/dist/doctor-ZBO73UID.js +337 -0
- package/dist/doctor-ZBO73UID.js.map +1 -0
- package/dist/index.js +12 -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-QB2JHTLX.js} +44 -11
- package/dist/run-QB2JHTLX.js.map +1 -0
- package/dist/{runs-CHA2JM5K.js → runs-SSBMKO53.js} +17 -12
- package/dist/runs-SSBMKO53.js.map +1 -0
- package/dist/{supervise-UF5WHQG3.js → supervise-R3W7ZF33.js} +52 -112
- package/dist/supervise-R3W7ZF33.js.map +1 -0
- package/dist/{tui-QS3RPHKH.js → tui-ODHFX3ZZ.js} +107 -34
- package/dist/tui-ODHFX3ZZ.js.map +1 -0
- package/dist/version-XVOAMGDD.js +26 -0
- package/dist/version-XVOAMGDD.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-CPVIT7IP.js +0 -198
- package/dist/doctor-CPVIT7IP.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-UF5WHQG3.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/tui/index.ts","../src/tui/supervisor-tui.tsx"],"sourcesContent":["import { render } from \"ink\";\nimport React from \"react\";\nimport { SupervisorTui } from \"./supervisor-tui.js\";\n\n/**\n * Render the supervisor TUI. Returns a promise that resolves when the user exits.\n */\nexport async function renderSupervisorTui(name: string): Promise<void> {\n const { waitUntilExit } = render(React.createElement(SupervisorTui, { name }));\n await waitUntilExit();\n}\n","import { randomUUID } from \"node:crypto\";\nimport { appendFile, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { ActivityEntry, MemoryEntry, SupervisorDaemonState } from \"@neotx/core\";\nimport {\n getSupervisorActivityPath,\n getSupervisorDir,\n getSupervisorInboxPath,\n getSupervisorStatePath,\n loadGlobalConfig,\n MemoryStore,\n} from \"@neotx/core\";\nimport { Box, Text, useApp, useInput, useStdout } from \"ink\";\nimport TextInput from \"ink-text-input\";\nimport { useCallback, useEffect, useState } from \"react\";\n\n// ─── Constants ───────────────────────────────────────────\n\nconst MAX_VISIBLE_ENTRIES = 24;\nconst POLL_INTERVAL_MS = 1_500;\nconst ANIMATION_TICK_MS = 400;\n\n// ─── Unicode Visual Elements ─────────────────────────────\n\nconst SPARK_CHARS = [\"▁\", \"▂\", \"▃\", \"▄\", \"▅\", \"▆\", \"▇\", \"█\"];\nconst BLOCK_FULL = \"█\";\nconst BLOCK_EMPTY = \"░\";\nconst PULSE_FRAMES = [\"◉\", \"◎\", \"○\", \"◎\"];\nconst IDLE_FRAMES = [\"◌\", \"◌\", \"◌\", \"◌\"];\n\nconst TYPE_ICONS: Record<string, string> = {\n heartbeat: \"♥\",\n decision: \"★\",\n action: \"⚡\",\n error: \"✖\",\n event: \"◆\",\n message: \"✉\",\n thinking: \"◇\",\n plan: \"▸\",\n dispatch: \"↗\",\n tool_use: \"⊘\",\n};\n\nconst TYPE_COLORS: Record<string, string> = {\n heartbeat: \"#6ee7b7\",\n decision: \"#fbbf24\",\n action: \"#60a5fa\",\n error: \"#f87171\",\n event: \"#c084fc\",\n message: \"#67e8f9\",\n thinking: \"#a78bfa\",\n plan: \"#34d399\",\n dispatch: \"#f472b6\",\n tool_use: \"#38bdf8\",\n};\n\nconst TYPE_LABELS: Record<string, string> = {\n heartbeat: \"BEAT\",\n decision: \"DECIDE\",\n action: \"ACTION\",\n error: \"ERROR\",\n event: \"EVENT\",\n message: \"MSG\",\n thinking: \"THINK\",\n plan: \"PLAN\",\n dispatch: \"SEND\",\n tool_use: \"TOOL\",\n};\n\n// ─── Helpers ─────────────────────────────────────────────\n\nfunction formatTime(timestamp: string): string {\n return timestamp.slice(11, 19);\n}\n\nfunction formatUptime(startedAt: string): string {\n const ms = Date.now() - new Date(startedAt).getTime();\n const seconds = Math.floor(ms / 1000);\n const minutes = Math.floor(seconds / 60);\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n if (days > 0) return `${days}d ${hours % 24}h`;\n if (hours > 0) return `${hours}h ${minutes % 60}m`;\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\n return `${seconds}s`;\n}\n\nfunction formatTimeAgo(timestamp: string): string {\n const ms = Date.now() - new Date(timestamp).getTime();\n const seconds = Math.floor(ms / 1000);\n if (seconds < 60) return `${seconds}s ago`;\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n return `${hours}h ago`;\n}\n\nfunction buildProgressBar(ratio: number, width: number): { filled: string; empty: string } {\n const clamped = Math.max(0, Math.min(1, ratio));\n const filledCount = Math.round(clamped * width);\n return {\n filled: BLOCK_FULL.repeat(filledCount),\n empty: BLOCK_EMPTY.repeat(width - filledCount),\n };\n}\n\nfunction buildSparkline(values: number[], width: number): string {\n if (values.length === 0) return \"▁\".repeat(width);\n const recent = values.slice(-width);\n const max = Math.max(...recent, 0.001);\n return recent\n .map((v) => {\n const idx = Math.min(\n Math.floor((v / max) * (SPARK_CHARS.length - 1)),\n SPARK_CHARS.length - 1,\n );\n return SPARK_CHARS[idx];\n })\n .join(\"\");\n}\n\nfunction extractCostHistory(entries: ActivityEntry[]): number[] {\n return entries\n .filter((e) => e.type === \"heartbeat\" && e.summary.includes(\"complete\"))\n .map((e) => {\n const detail = e.detail as Record<string, unknown> | undefined;\n return typeof detail?.costUsd === \"number\" ? detail.costUsd : 0;\n });\n}\n\n// ─── Animated Hooks ──────────────────────────────────────\n\nfunction useAnimationFrame(): number {\n const [frame, setFrame] = useState(0);\n useEffect(() => {\n const interval = setInterval(() => setFrame((f) => f + 1), ANIMATION_TICK_MS);\n return () => clearInterval(interval);\n }, []);\n return frame;\n}\n\nfunction useClock(): string {\n const [time, setTime] = useState(() => new Date().toLocaleTimeString());\n useEffect(() => {\n const interval = setInterval(() => setTime(new Date().toLocaleTimeString()), 1000);\n return () => clearInterval(interval);\n }, []);\n return time;\n}\n\n// ─── Components ──────────────────────────────────────────\n\nfunction Logo() {\n return (\n <Box paddingX={1} gap={1}>\n <Text color=\"#c084fc\" bold>\n ◆\n </Text>\n <Text bold>\n <Text color=\"#c084fc\">N</Text>\n <Text color=\"#a78bfa\">E</Text>\n <Text color=\"#818cf8\">O</Text>\n </Text>\n <Text dimColor>SUPERVISOR</Text>\n </Box>\n );\n}\n\nfunction LiveIndicator({ frame, isRunning }: { frame: number; isRunning: boolean }) {\n const frames = isRunning ? PULSE_FRAMES : IDLE_FRAMES;\n const dot = frames[frame % frames.length];\n return (\n <Box paddingX={1}>\n <Text color={isRunning ? \"#4ade80\" : \"#6b7280\"} bold>\n {dot}\n </Text>\n <Text color={isRunning ? \"#4ade80\" : \"#6b7280\"} bold>\n {\" \"}\n {isRunning ? \"LIVE\" : \"IDLE\"}\n </Text>\n </Box>\n );\n}\n\nfunction HeaderBar({\n state,\n name,\n frame,\n clock,\n}: {\n state: SupervisorDaemonState | null;\n name: string;\n frame: number;\n clock: string;\n}) {\n if (!state) {\n return (\n <Box borderStyle=\"round\" borderColor=\"#6b7280\" paddingX={1} flexDirection=\"column\">\n <Box justifyContent=\"space-between\">\n <Logo />\n <Box paddingX={1}>\n <Text dimColor>{clock}</Text>\n </Box>\n </Box>\n <Box paddingX={1}>\n <Text color=\"#fbbf24\">⟳ Connecting to \"{name}\"...</Text>\n </Box>\n </Box>\n );\n }\n\n const isRunning = state.status === \"running\";\n\n return (\n <Box\n borderStyle=\"round\"\n borderColor={isRunning ? \"#6ee7b7\" : \"#f87171\"}\n paddingX={0}\n flexDirection=\"column\"\n >\n <Box justifyContent=\"space-between\">\n <Logo />\n <Box gap={2}>\n <LiveIndicator frame={frame} isRunning={isRunning} />\n <Box paddingX={1}>\n <Text dimColor>{clock}</Text>\n </Box>\n </Box>\n </Box>\n\n <Box paddingX={1} gap={1}>\n <Text dimColor>│</Text>\n <Text>\n <Text dimColor>pid</Text> <Text bold>{state.pid}</Text>\n </Text>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>port</Text> <Text bold>:{state.port}</Text>\n </Text>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>beats</Text>{\" \"}\n <Text bold color=\"#6ee7b7\">\n ▲{state.heartbeatCount}\n </Text>\n </Text>\n {state.lastHeartbeat && (\n <>\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>last</Text> <Text>{formatTimeAgo(state.lastHeartbeat)}</Text>\n </Text>\n </>\n )}\n <Text dimColor>·</Text>\n <Text>\n <Text dimColor>up</Text> <Text>{formatUptime(state.startedAt)}</Text>\n </Text>\n </Box>\n </Box>\n );\n}\n\nfunction BudgetPanel({\n state,\n dailyCap,\n costHistory,\n}: {\n state: SupervisorDaemonState | null;\n dailyCap: number;\n costHistory: number[];\n}) {\n if (!state) return null;\n\n const todayCost = state.todayCostUsd ?? 0;\n const totalCost = state.totalCostUsd ?? 0;\n const ratio = dailyCap > 0 ? todayCost / dailyCap : 0;\n const barWidth = 20;\n const bar = buildProgressBar(ratio, barWidth);\n const pct = Math.round(ratio * 100);\n\n const barColor = pct < 50 ? \"#4ade80\" : pct < 80 ? \"#fbbf24\" : \"#f87171\";\n\n const sparkline = buildSparkline(costHistory, 12);\n\n return (\n <Box paddingX={2} gap={2}>\n <Box gap={1}>\n <Text dimColor>budget</Text>\n <Text color={barColor}>{bar.filled}</Text>\n <Text dimColor>{bar.empty}</Text>\n <Text bold color={barColor}>\n {pct}%\n </Text>\n <Text dimColor>\n (${todayCost.toFixed(2)}/${dailyCap})\n </Text>\n </Box>\n <Text dimColor>│</Text>\n <Box gap={1}>\n <Text dimColor>total</Text>\n <Text bold>${totalCost.toFixed(2)}</Text>\n </Box>\n <Text dimColor>│</Text>\n <Box gap={1}>\n <Text dimColor>cost/beat</Text>\n <Text color=\"#818cf8\">{sparkline}</Text>\n </Box>\n </Box>\n );\n}\n\nfunction ActivityRow({\n entry,\n isLatest,\n isOld,\n}: {\n entry: ActivityEntry;\n isLatest: boolean;\n isOld: boolean;\n}) {\n const icon = TYPE_ICONS[entry.type] ?? \"·\";\n const color = TYPE_COLORS[entry.type] ?? \"#9ca3af\";\n const label = (TYPE_LABELS[entry.type] ?? (entry.type as string).toUpperCase()).padEnd(7);\n\n return (\n <Box gap={1} paddingX={2}>\n <Text dimColor={isOld}>{isLatest ? \"│\" : \"│\"}</Text>\n <Text dimColor={isOld}>{formatTime(entry.timestamp)}</Text>\n <Text color={color} dimColor={isOld} bold={isLatest}>\n {icon}\n </Text>\n <Text color={color} dimColor={isOld} bold>\n {label}\n </Text>\n <Text dimColor={isOld} bold={isLatest}>\n {entry.summary}\n </Text>\n </Box>\n );\n}\n\nconst TASK_STATUS_COLORS: Record<string, string> = {\n in_progress: \"#60a5fa\",\n blocked: \"#f87171\",\n pending: \"#6b7280\",\n done: \"#4ade80\",\n};\n\nconst TASK_STATUS_LABELS: Record<string, string> = {\n in_progress: \"ACTIVE\",\n blocked: \"BLOCK\",\n pending: \"·\",\n};\n\nfunction TaskPanel({ tasks }: { tasks: MemoryEntry[] }) {\n const active = tasks.filter((t) => t.outcome !== \"done\" && t.outcome !== \"abandoned\");\n const doneCount = tasks.filter((t) => t.outcome === \"done\").length;\n\n if (tasks.length === 0) return null;\n\n const MAX_VISIBLE = 6;\n const visible = active.slice(0, MAX_VISIBLE);\n const overflow = active.length - visible.length;\n\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text dimColor bold>\n TASKS\n </Text>\n <Text dimColor>\n ({active.length} active, {doneCount} done)\n </Text>\n <Text dimColor>{\"─\".repeat(30)}</Text>\n </Box>\n {visible.map((t) => {\n const status = t.outcome ?? \"pending\";\n const color = TASK_STATUS_COLORS[status] ?? \"#6b7280\";\n const label = (TASK_STATUS_LABELS[status] ?? \"·\").padEnd(6);\n const prio = t.severity ? `[${t.severity.slice(0, 3)}] ` : \"\";\n const repo = t.scope !== \"global\" ? path.basename(t.scope) : \"\";\n const run = t.runId ? `run:${t.runId.slice(0, 4)}` : \"\";\n const meta = [repo, run].filter(Boolean).join(\" \");\n\n return (\n <Box key={t.id} gap={1} paddingX={2}>\n <Text dimColor>│</Text>\n <Text color={color} bold>\n {label}\n </Text>\n {prio && <Text dimColor>{prio.padEnd(5)}</Text>}\n <Text wrap=\"truncate\">{t.content}</Text>\n {meta && <Text dimColor>({meta})</Text>}\n </Box>\n );\n })}\n {overflow > 0 && (\n <Box paddingX={2}>\n <Text dimColor>│ ... +{overflow} more pending</Text>\n </Box>\n )}\n </Box>\n );\n}\n\n/** Types shown in the activity feed — plan/thinking are internal, not shown */\nconst ACTIVITY_TYPES = new Set([\n \"heartbeat\",\n \"decision\",\n \"action\",\n \"dispatch\",\n \"error\",\n \"event\",\n \"message\",\n]);\n\nfunction ActivityPanel({ entries, termHeight }: { entries: ActivityEntry[]; termHeight: number }) {\n // Reserve lines for header (5), budget (1), separator (1), input (2), footer (1) = 10\n const maxVisible = Math.max(5, Math.min(MAX_VISIBLE_ENTRIES, termHeight - 10));\n const filtered = entries.filter((e) => ACTIVITY_TYPES.has(e.type));\n const visible = filtered.slice(-maxVisible);\n\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>├</Text>\n <Text dimColor bold>\n ACTIVITY\n </Text>\n <Text dimColor>{\"─\".repeat(40)}</Text>\n </Box>\n\n {visible.length === 0 ? (\n <Box paddingX={2}>\n <Text dimColor>│ Waiting for heartbeats...</Text>\n </Box>\n ) : (\n visible.map((entry, idx) => (\n <ActivityRow\n key={entry.id}\n entry={entry}\n isLatest={idx === visible.length - 1}\n isOld={idx < visible.length - 5}\n />\n ))\n )}\n\n <Box paddingX={2}>\n <Text dimColor>│</Text>\n </Box>\n </Box>\n );\n}\n\nfunction InputPanel({\n value,\n onChange,\n onSubmit,\n lastSent,\n}: {\n value: string;\n onChange: (v: string) => void;\n onSubmit: (v: string) => void;\n lastSent: string;\n}) {\n return (\n <Box flexDirection=\"column\">\n <Box paddingX={2} gap={1}>\n <Text dimColor>└</Text>\n <Text bold color=\"#60a5fa\">\n ❯\n </Text>\n <TextInput\n value={value}\n onChange={onChange}\n onSubmit={onSubmit}\n placeholder=\"message the supervisor...\"\n />\n </Box>\n <Box paddingX={2} gap={1}>\n <Text dimColor> </Text>\n {lastSent ? <Text color=\"#6b7280\">✓ \"{lastSent}\"</Text> : null}\n </Box>\n </Box>\n );\n}\n\nfunction Footer() {\n return (\n <Box paddingX={2} gap={1} justifyContent=\"center\">\n <Text dimColor>\n <Text bold>esc</Text> quit\n </Text>\n <Text dimColor>·</Text>\n <Text dimColor>\n <Text bold>enter</Text> send\n </Text>\n <Text dimColor>·</Text>\n <Text dimColor>daemon keeps running</Text>\n </Box>\n );\n}\n\n// ─── Data Fetching ───────────────────────────────────────\n\nasync function readState(name: string): Promise<SupervisorDaemonState | null> {\n try {\n const raw = await readFile(getSupervisorStatePath(name), \"utf-8\");\n return JSON.parse(raw) as SupervisorDaemonState;\n } catch {\n return null;\n }\n}\n\nasync function readActivity(name: string, maxEntries: number): Promise<ActivityEntry[]> {\n try {\n const content = await readFile(getSupervisorActivityPath(name), \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n const lastLines = lines.slice(-maxEntries);\n const entries: ActivityEntry[] = [];\n for (const line of lastLines) {\n try {\n entries.push(JSON.parse(line) as ActivityEntry);\n } catch {\n // Skip malformed\n }\n }\n return entries;\n } catch {\n return [];\n }\n}\n\nfunction readTasks(name: string): MemoryEntry[] {\n try {\n const dir = getSupervisorDir(name);\n const store = new MemoryStore(path.join(dir, \"memory.sqlite\"));\n const tasks = store.query({ types: [\"task\"], limit: 20, sortBy: \"createdAt\" });\n store.close();\n return tasks;\n } catch {\n return [];\n }\n}\n\nasync function sendMessage(name: string, text: string): Promise<void> {\n const id = randomUUID();\n const timestamp = new Date().toISOString();\n\n const message = { id, from: \"tui\" as const, text, timestamp };\n const inboxPath = getSupervisorInboxPath(name);\n await appendFile(inboxPath, `${JSON.stringify(message)}\\n`, \"utf-8\");\n\n // Write to activity.jsonl so the message appears in the TUI conversation\n const activityEntry = { id, type: \"message\", summary: text, timestamp };\n const activityPath = getSupervisorActivityPath(name);\n await appendFile(activityPath, `${JSON.stringify(activityEntry)}\\n`, \"utf-8\");\n}\n\n// ─── Main Component ──────────────────────────────────────\n\nexport function SupervisorTui({ name }: { name: string }) {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const frame = useAnimationFrame();\n const clock = useClock();\n\n const [state, setState] = useState<SupervisorDaemonState | null>(null);\n const [entries, setEntries] = useState<ActivityEntry[]>([]);\n const [tasks, setTasks] = useState<MemoryEntry[]>([]);\n const [dailyCap, setDailyCap] = useState(50);\n const [input, setInput] = useState(\"\");\n const [lastSent, setLastSent] = useState(\"\");\n const [termHeight, setTermHeight] = useState(stdout?.rows ?? 30);\n\n // Track terminal resize\n useEffect(() => {\n function onResize() {\n if (stdout) setTermHeight(stdout.rows);\n }\n stdout?.on(\"resize\", onResize);\n return () => {\n stdout?.off(\"resize\", onResize);\n };\n }, [stdout]);\n\n // Load daily cap from config\n useEffect(() => {\n loadGlobalConfig()\n .then((cfg) => setDailyCap(cfg.supervisor.dailyCapUsd))\n .catch(() => {});\n }, []);\n\n // Poll state and activity\n useEffect(() => {\n let active = true;\n\n async function poll() {\n if (!active) return;\n const [newState, newEntries] = await Promise.all([\n readState(name),\n readActivity(name, MAX_VISIBLE_ENTRIES),\n ]);\n if (!active) return;\n setState(newState);\n setEntries(newEntries);\n setTasks(readTasks(name));\n }\n\n poll();\n const interval = setInterval(poll, POLL_INTERVAL_MS);\n return () => {\n active = false;\n clearInterval(interval);\n };\n }, [name]);\n\n useInput((_input, key) => {\n if (key.escape) {\n exit();\n }\n });\n\n const handleSubmit = useCallback(\n (text: string) => {\n if (!text.trim()) return;\n sendMessage(name, text.trim());\n setLastSent(text.trim());\n setInput(\"\");\n },\n [name],\n );\n\n const costHistory = extractCostHistory(entries);\n\n return (\n <Box flexDirection=\"column\">\n <HeaderBar state={state} name={name} frame={frame} clock={clock} />\n <BudgetPanel state={state} dailyCap={dailyCap} costHistory={costHistory} />\n <TaskPanel tasks={tasks} />\n <ActivityPanel\n entries={entries}\n termHeight={\n termHeight -\n (tasks.length > 0\n ? Math.min(\n tasks.filter((t) => t.outcome !== \"done\" && t.outcome !== \"abandoned\").length,\n 6,\n ) + 2\n : 0)\n }\n />\n <InputPanel value={input} onChange={setInput} onSubmit={handleSubmit} lastSent={lastSent} />\n <Footer />\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/commands/version.ts
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { dirname, join } from "path";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { defineCommand } from "citty";
|
|
6
|
+
async function getVersion() {
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const pkgPath = join(__dirname, "..", "..", "package.json");
|
|
9
|
+
const content = await readFile(pkgPath, "utf-8");
|
|
10
|
+
const pkg = JSON.parse(content);
|
|
11
|
+
return pkg.version;
|
|
12
|
+
}
|
|
13
|
+
var version_default = defineCommand({
|
|
14
|
+
meta: {
|
|
15
|
+
name: "version",
|
|
16
|
+
description: "Display the current neo version"
|
|
17
|
+
},
|
|
18
|
+
async run() {
|
|
19
|
+
const version = await getVersion();
|
|
20
|
+
console.log(`neo v${version}`);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
export {
|
|
24
|
+
version_default as default
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=version-XVOAMGDD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/version.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { defineCommand } from \"citty\";\n\nasync function getVersion(): Promise<string> {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(__dirname, \"..\", \"..\", \"package.json\");\n const content = await readFile(pkgPath, \"utf-8\");\n const pkg = JSON.parse(content) as { version: string };\n return pkg.version;\n}\n\nexport default defineCommand({\n meta: {\n name: \"version\",\n description: \"Display the current neo version\",\n },\n async run() {\n const version = await getVersion();\n console.log(`neo v${version}`);\n },\n});\n"],"mappings":";AAAA,SAAS,gBAAgB;AACzB,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAE9B,eAAe,aAA8B;AAC3C,QAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,QAAM,UAAU,KAAK,WAAW,MAAM,MAAM,cAAc;AAC1D,QAAM,UAAU,MAAM,SAAS,SAAS,OAAO;AAC/C,QAAM,MAAM,KAAK,MAAM,OAAO;AAC9B,SAAO,IAAI;AACb;AAEA,IAAO,kBAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM,MAAM;AACV,UAAM,UAAU,MAAM,WAAW;AACjC,YAAQ,IAAI,QAAQ,OAAO,EAAE;AAAA,EAC/B;AACF,CAAC;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neotx/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.11",
|
|
4
4
|
"description": "CLI for the Neo orchestration framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -29,25 +29,43 @@
|
|
|
29
29
|
"engines": {
|
|
30
30
|
"node": ">=22"
|
|
31
31
|
},
|
|
32
|
+
"man": [
|
|
33
|
+
"../../man/man1/neo.1",
|
|
34
|
+
"../../man/man1/neo-agents.1",
|
|
35
|
+
"../../man/man1/neo-cost.1",
|
|
36
|
+
"../../man/man1/neo-doctor.1",
|
|
37
|
+
"../../man/man1/neo-init.1",
|
|
38
|
+
"../../man/man1/neo-log.1",
|
|
39
|
+
"../../man/man1/neo-logs.1",
|
|
40
|
+
"../../man/man1/neo-mcp.1",
|
|
41
|
+
"../../man/man1/neo-memory.1",
|
|
42
|
+
"../../man/man1/neo-repos.1",
|
|
43
|
+
"../../man/man1/neo-run.1",
|
|
44
|
+
"../../man/man1/neo-runs.1",
|
|
45
|
+
"../../man/man1/neo-supervise.1",
|
|
46
|
+
"../../man/man1/neo-version.1"
|
|
47
|
+
],
|
|
32
48
|
"dependencies": {
|
|
33
49
|
"citty": "^0.2.1",
|
|
34
50
|
"ink": "^6.8.0",
|
|
35
51
|
"ink-text-input": "^6.0.0",
|
|
36
52
|
"react": "^19.2.4",
|
|
37
53
|
"yaml": "^2.8.2",
|
|
38
|
-
"@neotx/agents": "0.1.0-alpha.
|
|
39
|
-
"@neotx/core": "0.1.0-alpha.
|
|
54
|
+
"@neotx/agents": "0.1.0-alpha.11",
|
|
55
|
+
"@neotx/core": "0.1.0-alpha.11"
|
|
40
56
|
},
|
|
41
57
|
"devDependencies": {
|
|
42
58
|
"@anthropic-ai/claude-agent-sdk": "^0.1.0",
|
|
43
59
|
"@types/node": "^25.5.0",
|
|
44
60
|
"@types/react": "^19.2.14",
|
|
61
|
+
"@vitest/coverage-v8": "^3.0.0",
|
|
45
62
|
"tsup": "^8.5.1"
|
|
46
63
|
},
|
|
47
64
|
"scripts": {
|
|
48
65
|
"build": "tsup",
|
|
49
66
|
"typecheck": "tsc --noEmit",
|
|
50
67
|
"lint": "biome check src/",
|
|
51
|
-
"test": "vitest run"
|
|
68
|
+
"test": "vitest run",
|
|
69
|
+
"install-man": "mkdir -p /usr/local/share/man/man1 && cp ../../man/man1/*.1 /usr/local/share/man/man1/ && mandb 2>/dev/null || true"
|
|
52
70
|
}
|
|
53
71
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/repo-filter.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { PersistedRun } from \"@neotx/core\";\nimport { getRunsDir, listReposFromGlobalConfig, toRepoSlug } from \"@neotx/core\";\n\nexport interface RepoFilter {\n mode: \"cwd\" | \"all\" | \"named\";\n repoSlug?: string;\n repoPath?: string;\n}\n\n/**\n * Resolve which repos to query based on --all / --repo flags.\n * Default: CWD-based (finds the matching registered repo slug, or uses basename).\n */\nexport async function resolveRepoFilter(args: {\n all?: boolean | undefined;\n repo?: string | undefined;\n}): Promise<RepoFilter> {\n if (args.all) return { mode: \"all\" };\n\n if (args.repo) {\n const repo = args.repo;\n // Could be a name/slug or a path\n const repos = await listReposFromGlobalConfig();\n const match = repos.find(\n (r) => toRepoSlug(r) === repo || path.resolve(r.path) === path.resolve(repo),\n );\n if (match) {\n return { mode: \"named\", repoSlug: toRepoSlug(match), repoPath: match.path };\n }\n // Treat as path, derive slug\n return { mode: \"named\", repoSlug: toRepoSlug({ path: repo }), repoPath: repo };\n }\n\n // Default: CWD\n const cwd = process.cwd();\n const repos = await listReposFromGlobalConfig();\n const match = repos.find((r) => path.resolve(r.path) === cwd);\n const slug = match ? toRepoSlug(match) : toRepoSlug({ path: cwd });\n return { mode: \"cwd\", repoSlug: slug, repoPath: cwd };\n}\n\n/**\n * Load persisted runs, filtered by RepoFilter.\n */\nexport async function loadRunsFiltered(filter: RepoFilter): Promise<PersistedRun[]> {\n const runsDir = getRunsDir();\n if (!existsSync(runsDir)) return [];\n\n const runs: PersistedRun[] = [];\n\n if (filter.mode === \"all\") {\n // Scan all slug subdirs + legacy flat files\n const entries = await readdir(runsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (entry.isDirectory()) {\n await loadRunsFromDir(path.join(runsDir, entry.name), runs);\n } else if (entry.name.endsWith(\".json\")) {\n await loadRunFile(path.join(runsDir, entry.name), runs);\n }\n }\n } else {\n // Specific slug dir\n const slugDir = path.join(runsDir, filter.repoSlug ?? \"unknown\");\n await loadRunsFromDir(slugDir, runs);\n // Also check legacy flat files matching this repo\n await loadLegacyRuns(runsDir, filter.repoPath, runs);\n }\n\n runs.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n return runs;\n}\n\nasync function loadRunsFromDir(dir: string, runs: PersistedRun[]): Promise<void> {\n if (!existsSync(dir)) return;\n const files = await readdir(dir);\n for (const file of files) {\n if (!file.endsWith(\".json\")) continue;\n await loadRunFile(path.join(dir, file), runs);\n }\n}\n\nasync function loadRunFile(filePath: string, runs: PersistedRun[]): Promise<void> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n runs.push(JSON.parse(content) as PersistedRun);\n } catch {\n // Skip corrupt files\n }\n}\n\nasync function loadLegacyRuns(\n runsDir: string,\n repoPath: string | undefined,\n runs: PersistedRun[],\n): Promise<void> {\n if (!repoPath) return;\n const resolvedRepo = path.resolve(repoPath);\n\n try {\n const entries = await readdir(runsDir, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".json\")) continue;\n const filePath = path.join(runsDir, entry.name);\n const content = await readFile(filePath, \"utf-8\");\n const run = JSON.parse(content) as PersistedRun;\n if (path.resolve(run.repo) === resolvedRepo) {\n // Avoid duplicates\n if (!runs.some((r) => r.runId === run.runId)) {\n runs.push(run);\n }\n }\n }\n } catch {\n // Non-critical\n }\n}\n"],"mappings":"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","names":["repos","match"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/cost.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { CostEntry } from \"@neotx/core\";\nimport { getJournalsDir, toRepoSlug } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printJson, printTable } from \"../output.js\";\nimport { resolveRepoFilter } from \"../repo-filter.js\";\n\nasync function readCostEntries(journalDir: string): Promise<CostEntry[]> {\n if (!existsSync(journalDir)) return [];\n const files = await readdir(journalDir);\n const costFiles = files\n .filter((f) => f.startsWith(\"cost-\"))\n .sort()\n .reverse();\n const entries: CostEntry[] = [];\n\n for (const file of costFiles) {\n const content = await readFile(path.join(journalDir, file), \"utf-8\");\n for (const line of content.trim().split(\"\\n\")) {\n if (!line.trim()) continue;\n entries.push(JSON.parse(line) as CostEntry);\n }\n }\n\n return entries;\n}\n\nfunction isToday(timestamp: string): boolean {\n const d = new Date(timestamp);\n const now = new Date();\n return (\n d.getUTCFullYear() === now.getUTCFullYear() &&\n d.getUTCMonth() === now.getUTCMonth() &&\n d.getUTCDate() === now.getUTCDate()\n );\n}\n\nexport default defineCommand({\n meta: {\n name: \"cost\",\n description: \"Show cost breakdown from journals (today, by agent, by run)\",\n },\n args: {\n all: {\n type: \"boolean\",\n description: \"Show costs from all repos\",\n default: false,\n },\n repo: {\n type: \"string\",\n description: \"Filter by repo name or path\",\n },\n short: {\n type: \"boolean\",\n description: \"Compact output for supervisor agents (saves tokens)\",\n default: false,\n },\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n const journalDir = getJournalsDir();\n let entries = await readCostEntries(journalDir);\n\n if (entries.length === 0) {\n printError(\"No cost data found.\");\n process.exitCode = 1;\n return;\n }\n\n // Filter by repo unless --all\n const filter = await resolveRepoFilter({ all: args.all, repo: args.repo });\n if (filter.mode !== \"all\") {\n const slug = filter.repoSlug;\n entries = entries.filter((e) => {\n if (!e.repo) return false;\n return toRepoSlug({ path: e.repo }) === slug;\n });\n }\n\n const todayEntries = entries.filter((e) => isToday(e.timestamp));\n const todayTotal = todayEntries.reduce((sum, e) => sum + e.costUsd, 0);\n const allTimeTotal = entries.reduce((sum, e) => sum + e.costUsd, 0);\n\n // Breakdown by agent (today)\n const byAgent = new Map<string, { cost: number; runs: number }>();\n for (const e of todayEntries) {\n const prev = byAgent.get(e.agent) ?? { cost: 0, runs: 0 };\n byAgent.set(e.agent, { cost: prev.cost + e.costUsd, runs: prev.runs + 1 });\n }\n\n // Breakdown by repo (today, only in --all mode)\n const byRepo = new Map<string, { cost: number; runs: number }>();\n if (filter.mode === \"all\") {\n for (const e of todayEntries) {\n const repo = e.repo ?? \"unknown\";\n const prev = byRepo.get(repo) ?? { cost: 0, runs: 0 };\n byRepo.set(repo, { cost: prev.cost + e.costUsd, runs: prev.runs + 1 });\n }\n }\n\n if (jsonOutput) {\n printJson({\n today: {\n total: todayTotal,\n sessions: todayEntries.length,\n byAgent: Object.fromEntries(byAgent),\n ...(byRepo.size > 0 ? { byRepo: Object.fromEntries(byRepo) } : {}),\n },\n allTime: {\n total: allTimeTotal,\n sessions: entries.length,\n },\n });\n return;\n }\n\n if (args.short) {\n const agents = [...byAgent.entries()]\n .map(([name, data]) => `${name}=$${data.cost.toFixed(4)}`)\n .join(\" \");\n console.log(`today=$${todayTotal.toFixed(4)} sessions=${todayEntries.length} ${agents}`);\n return;\n }\n\n console.log(`Today: $${todayTotal.toFixed(4)} (${todayEntries.length} sessions)`);\n console.log(`All time: $${allTimeTotal.toFixed(4)} (${entries.length} sessions)`);\n\n if (byAgent.size > 0) {\n console.log(\"\");\n printTable(\n [\"AGENT\", \"COST TODAY\", \"SESSIONS\"],\n [...byAgent.entries()]\n .sort((a, b) => b[1].cost - a[1].cost)\n .map(([name, data]) => [name, `$${data.cost.toFixed(4)}`, String(data.runs)]),\n );\n }\n\n if (byRepo.size > 0) {\n console.log(\"\");\n printTable(\n [\"REPO\", \"COST TODAY\", \"SESSIONS\"],\n [...byRepo.entries()]\n .sort((a, b) => b[1].cost - a[1].cost)\n .map(([repo, data]) => [repo, `$${data.cost.toFixed(4)}`, String(data.runs)]),\n );\n }\n },\n});\n"],"mappings":";;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,gBAAgB;AAClC,OAAO,UAAU;AAEjB,SAAS,gBAAgB,kBAAkB;AAC3C,SAAS,qBAAqB;AAI9B,eAAe,gBAAgB,YAA0C;AACvE,MAAI,CAAC,WAAW,UAAU,EAAG,QAAO,CAAC;AACrC,QAAM,QAAQ,MAAM,QAAQ,UAAU;AACtC,QAAM,YAAY,MACf,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,CAAC,EACnC,KAAK,EACL,QAAQ;AACX,QAAM,UAAuB,CAAC;AAE9B,aAAW,QAAQ,WAAW;AAC5B,UAAM,UAAU,MAAM,SAAS,KAAK,KAAK,YAAY,IAAI,GAAG,OAAO;AACnE,eAAW,QAAQ,QAAQ,KAAK,EAAE,MAAM,IAAI,GAAG;AAC7C,UAAI,CAAC,KAAK,KAAK,EAAG;AAClB,cAAQ,KAAK,KAAK,MAAM,IAAI,CAAc;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,QAAQ,WAA4B;AAC3C,QAAM,IAAI,IAAI,KAAK,SAAS;AAC5B,QAAM,MAAM,oBAAI,KAAK;AACrB,SACE,EAAE,eAAe,MAAM,IAAI,eAAe,KAC1C,EAAE,YAAY,MAAM,IAAI,YAAY,KACpC,EAAE,WAAW,MAAM,IAAI,WAAW;AAEtC;AAEA,IAAO,eAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,KAAK;AAAA,MACH,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,aAAa,KAAK,WAAW;AACnC,UAAM,aAAa,eAAe;AAClC,QAAI,UAAU,MAAM,gBAAgB,UAAU;AAE9C,QAAI,QAAQ,WAAW,GAAG;AACxB,iBAAW,qBAAqB;AAChC,cAAQ,WAAW;AACnB;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,kBAAkB,EAAE,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,CAAC;AACzE,QAAI,OAAO,SAAS,OAAO;AACzB,YAAM,OAAO,OAAO;AACpB,gBAAU,QAAQ,OAAO,CAAC,MAAM;AAC9B,YAAI,CAAC,EAAE,KAAM,QAAO;AACpB,eAAO,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM;AAAA,MAC1C,CAAC;AAAA,IACH;AAEA,UAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,QAAQ,EAAE,SAAS,CAAC;AAC/D,UAAM,aAAa,aAAa,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS,CAAC;AACrE,UAAM,eAAe,QAAQ,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,SAAS,CAAC;AAGlE,UAAM,UAAU,oBAAI,IAA4C;AAChE,eAAW,KAAK,cAAc;AAC5B,YAAM,OAAO,QAAQ,IAAI,EAAE,KAAK,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;AACxD,cAAQ,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,EAAE,SAAS,MAAM,KAAK,OAAO,EAAE,CAAC;AAAA,IAC3E;AAGA,UAAM,SAAS,oBAAI,IAA4C;AAC/D,QAAI,OAAO,SAAS,OAAO;AACzB,iBAAW,KAAK,cAAc;AAC5B,cAAM,OAAO,EAAE,QAAQ;AACvB,cAAM,OAAO,OAAO,IAAI,IAAI,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;AACpD,eAAO,IAAI,MAAM,EAAE,MAAM,KAAK,OAAO,EAAE,SAAS,MAAM,KAAK,OAAO,EAAE,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,QAAI,YAAY;AACd,gBAAU;AAAA,QACR,OAAO;AAAA,UACL,OAAO;AAAA,UACP,UAAU,aAAa;AAAA,UACvB,SAAS,OAAO,YAAY,OAAO;AAAA,UACnC,GAAI,OAAO,OAAO,IAAI,EAAE,QAAQ,OAAO,YAAY,MAAM,EAAE,IAAI,CAAC;AAAA,QAClE;AAAA,QACA,SAAS;AAAA,UACP,OAAO;AAAA,UACP,UAAU,QAAQ;AAAA,QACpB;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAEA,QAAI,KAAK,OAAO;AACd,YAAM,SAAS,CAAC,GAAG,QAAQ,QAAQ,CAAC,EACjC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,GAAG,IAAI,KAAK,KAAK,KAAK,QAAQ,CAAC,CAAC,EAAE,EACxD,KAAK,GAAG;AACX,cAAQ,IAAI,UAAU,WAAW,QAAQ,CAAC,CAAC,aAAa,aAAa,MAAM,IAAI,MAAM,EAAE;AACvF;AAAA,IACF;AAEA,YAAQ,IAAI,cAAc,WAAW,QAAQ,CAAC,CAAC,KAAK,aAAa,MAAM,YAAY;AACnF,YAAQ,IAAI,cAAc,aAAa,QAAQ,CAAC,CAAC,KAAK,QAAQ,MAAM,YAAY;AAEhF,QAAI,QAAQ,OAAO,GAAG;AACpB,cAAQ,IAAI,EAAE;AACd;AAAA,QACE,CAAC,SAAS,cAAc,UAAU;AAAA,QAClC,CAAC,GAAG,QAAQ,QAAQ,CAAC,EAClB,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EACpC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK,KAAK,QAAQ,CAAC,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC;AAAA,MAChF;AAAA,IACF;AAEA,QAAI,OAAO,OAAO,GAAG;AACnB,cAAQ,IAAI,EAAE;AACd;AAAA,QACE,CAAC,QAAQ,cAAc,UAAU;AAAA,QACjC,CAAC,GAAG,OAAO,QAAQ,CAAC,EACjB,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EACpC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK,KAAK,QAAQ,CAAC,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC;AAAA,MAChF;AAAA,IACF;AAAA,EACF;AACF,CAAC;","names":[]}
|
package/dist/doctor-CPVIT7IP.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
resolveAgentsDir
|
|
3
|
-
} from "./chunk-TNJOG54I.js";
|
|
4
|
-
import {
|
|
5
|
-
printError,
|
|
6
|
-
printJson,
|
|
7
|
-
printSuccess
|
|
8
|
-
} from "./chunk-YQIWMDXL.js";
|
|
9
|
-
|
|
10
|
-
// src/commands/doctor.ts
|
|
11
|
-
import { execFile } from "child_process";
|
|
12
|
-
import { existsSync } from "fs";
|
|
13
|
-
import { access, constants } from "fs/promises";
|
|
14
|
-
import path from "path";
|
|
15
|
-
import { promisify } from "util";
|
|
16
|
-
import {
|
|
17
|
-
AgentRegistry,
|
|
18
|
-
getDataDir,
|
|
19
|
-
getJournalsDir,
|
|
20
|
-
listReposFromGlobalConfig,
|
|
21
|
-
loadGlobalConfig,
|
|
22
|
-
toRepoSlug
|
|
23
|
-
} from "@neotx/core";
|
|
24
|
-
import { defineCommand } from "citty";
|
|
25
|
-
var execFileAsync = promisify(execFile);
|
|
26
|
-
async function checkNodeVersion() {
|
|
27
|
-
const version = process.versions.node;
|
|
28
|
-
const major = Number.parseInt(version.split(".")[0] ?? "0", 10);
|
|
29
|
-
if (major >= 22) {
|
|
30
|
-
return { name: "Node.js", status: "pass", message: `v${version}` };
|
|
31
|
-
}
|
|
32
|
-
return { name: "Node.js", status: "fail", message: `v${version} (requires >= 22)` };
|
|
33
|
-
}
|
|
34
|
-
async function checkGit() {
|
|
35
|
-
try {
|
|
36
|
-
const { stdout } = await execFileAsync("git", ["--version"]);
|
|
37
|
-
const match = stdout.match(/(\d+\.\d+)/);
|
|
38
|
-
const version = match?.[1] ?? "unknown";
|
|
39
|
-
const [major, minor] = version.split(".").map(Number);
|
|
40
|
-
if ((major ?? 0) > 2 || (major ?? 0) === 2 && (minor ?? 0) >= 20) {
|
|
41
|
-
return { name: "git", status: "pass", message: `v${version}` };
|
|
42
|
-
}
|
|
43
|
-
return { name: "git", status: "fail", message: `v${version} (requires >= 2.20)` };
|
|
44
|
-
} catch {
|
|
45
|
-
return { name: "git", status: "fail", message: "not installed" };
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
async function checkGlobalConfig() {
|
|
49
|
-
try {
|
|
50
|
-
const config = await loadGlobalConfig();
|
|
51
|
-
const globalDir = getDataDir();
|
|
52
|
-
const repoCount = config.repos.length;
|
|
53
|
-
return {
|
|
54
|
-
name: "Global config",
|
|
55
|
-
status: "pass",
|
|
56
|
-
message: `${globalDir}/config.yml (budget: $${config.budget.dailyCapUsd}/day, ${repoCount} repos)`
|
|
57
|
-
};
|
|
58
|
-
} catch (error) {
|
|
59
|
-
return {
|
|
60
|
-
name: "Global config",
|
|
61
|
-
status: "fail",
|
|
62
|
-
message: `Invalid: ${error instanceof Error ? error.message : String(error)}`
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
async function checkRepoRegistered() {
|
|
67
|
-
const cwd = process.cwd();
|
|
68
|
-
const repos = await listReposFromGlobalConfig();
|
|
69
|
-
const match = repos.find((r) => path.resolve(r.path) === cwd);
|
|
70
|
-
if (match) {
|
|
71
|
-
return {
|
|
72
|
-
name: "Repo registered",
|
|
73
|
-
status: "pass",
|
|
74
|
-
message: `"${toRepoSlug(match)}" (branch: ${match.defaultBranch})`
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
return {
|
|
78
|
-
name: "Repo registered",
|
|
79
|
-
status: "info",
|
|
80
|
-
message: "CWD not registered. Run 'neo init' or 'neo repos add'. Zero-config mode works without registration."
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
async function checkLegacyConfig() {
|
|
84
|
-
const legacyPath = path.resolve(".neo/config.yml");
|
|
85
|
-
if (existsSync(legacyPath)) {
|
|
86
|
-
return {
|
|
87
|
-
name: "Legacy config",
|
|
88
|
-
status: "info",
|
|
89
|
-
message: ".neo/config.yml detected \u2014 this file is no longer needed. Config is now in ~/.neo/config.yml."
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
async function checkTmux() {
|
|
95
|
-
try {
|
|
96
|
-
const { stdout } = await execFileAsync("tmux", ["-V"]);
|
|
97
|
-
return { name: "tmux", status: "pass", message: stdout.trim() };
|
|
98
|
-
} catch {
|
|
99
|
-
return {
|
|
100
|
-
name: "tmux",
|
|
101
|
-
status: "info",
|
|
102
|
-
message: "not installed (required for neo supervise)"
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
async function checkClaudeCli() {
|
|
107
|
-
try {
|
|
108
|
-
const { stdout } = await execFileAsync("claude", ["--version"]);
|
|
109
|
-
return { name: "Claude CLI", status: "pass", message: stdout.trim() };
|
|
110
|
-
} catch {
|
|
111
|
-
return { name: "Claude CLI", status: "fail", message: "not installed or not in PATH" };
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
async function checkAgents() {
|
|
115
|
-
try {
|
|
116
|
-
const agentsDir = resolveAgentsDir();
|
|
117
|
-
if (!existsSync(agentsDir)) {
|
|
118
|
-
return { name: "Agents", status: "fail", message: "Agent definitions not found" };
|
|
119
|
-
}
|
|
120
|
-
const registry = new AgentRegistry(agentsDir);
|
|
121
|
-
await registry.load();
|
|
122
|
-
const count = registry.list().length;
|
|
123
|
-
return { name: "Agents", status: "pass", message: `${count} agents loaded` };
|
|
124
|
-
} catch (error) {
|
|
125
|
-
return {
|
|
126
|
-
name: "Agents",
|
|
127
|
-
status: "fail",
|
|
128
|
-
message: error instanceof Error ? error.message : String(error)
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
async function checkJournalDirs() {
|
|
133
|
-
const journalDir = getJournalsDir();
|
|
134
|
-
if (!existsSync(journalDir)) {
|
|
135
|
-
return {
|
|
136
|
-
name: "Journals",
|
|
137
|
-
status: "pass",
|
|
138
|
-
message: "Directory will be created on first write"
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
try {
|
|
142
|
-
await access(journalDir, constants.W_OK);
|
|
143
|
-
return { name: "Journals", status: "pass", message: journalDir };
|
|
144
|
-
} catch {
|
|
145
|
-
return { name: "Journals", status: "fail", message: `${journalDir} is not writable` };
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
var doctor_default = defineCommand({
|
|
149
|
-
meta: {
|
|
150
|
-
name: "doctor",
|
|
151
|
-
description: "Check environment prerequisites (Node.js, git, config, Claude CLI)"
|
|
152
|
-
},
|
|
153
|
-
args: {
|
|
154
|
-
output: {
|
|
155
|
-
type: "string",
|
|
156
|
-
description: "Output format: json"
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
async run({ args }) {
|
|
160
|
-
const jsonOutput = args.output === "json";
|
|
161
|
-
const checks = (await Promise.all([
|
|
162
|
-
checkNodeVersion(),
|
|
163
|
-
checkGit(),
|
|
164
|
-
checkGlobalConfig(),
|
|
165
|
-
checkRepoRegistered(),
|
|
166
|
-
checkLegacyConfig(),
|
|
167
|
-
checkTmux(),
|
|
168
|
-
checkClaudeCli(),
|
|
169
|
-
checkAgents(),
|
|
170
|
-
checkJournalDirs()
|
|
171
|
-
])).filter((c) => c !== null);
|
|
172
|
-
if (jsonOutput) {
|
|
173
|
-
printJson({ checks });
|
|
174
|
-
if (checks.some((c) => c.status === "fail")) {
|
|
175
|
-
process.exitCode = 1;
|
|
176
|
-
}
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
let hasFailure = false;
|
|
180
|
-
for (const check of checks) {
|
|
181
|
-
if (check.status === "pass") {
|
|
182
|
-
printSuccess(`${check.name}: ${check.message ?? "OK"}`);
|
|
183
|
-
} else if (check.status === "info") {
|
|
184
|
-
console.log(` ${check.name}: ${check.message ?? ""}`);
|
|
185
|
-
} else {
|
|
186
|
-
printError(`${check.name}: ${check.message ?? "FAILED"}`);
|
|
187
|
-
hasFailure = true;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
if (hasFailure) {
|
|
191
|
-
process.exitCode = 1;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
export {
|
|
196
|
-
doctor_default as default
|
|
197
|
-
};
|
|
198
|
-
//# sourceMappingURL=doctor-CPVIT7IP.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/doctor.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { access, constants } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\nimport {\n AgentRegistry,\n getDataDir,\n getJournalsDir,\n listReposFromGlobalConfig,\n loadGlobalConfig,\n toRepoSlug,\n} from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printJson, printSuccess } from \"../output.js\";\nimport { resolveAgentsDir } from \"../resolve.js\";\n\nconst execFileAsync = promisify(execFile);\n\ninterface CheckResult {\n name: string;\n status: \"pass\" | \"fail\" | \"info\";\n message?: string;\n}\n\nasync function checkNodeVersion(): Promise<CheckResult> {\n const version = process.versions.node;\n const major = Number.parseInt(version.split(\".\")[0] ?? \"0\", 10);\n if (major >= 22) {\n return { name: \"Node.js\", status: \"pass\", message: `v${version}` };\n }\n return { name: \"Node.js\", status: \"fail\", message: `v${version} (requires >= 22)` };\n}\n\nasync function checkGit(): Promise<CheckResult> {\n try {\n const { stdout } = await execFileAsync(\"git\", [\"--version\"]);\n const match = stdout.match(/(\\d+\\.\\d+)/);\n const version = match?.[1] ?? \"unknown\";\n const [major, minor] = version.split(\".\").map(Number);\n if ((major ?? 0) > 2 || ((major ?? 0) === 2 && (minor ?? 0) >= 20)) {\n return { name: \"git\", status: \"pass\", message: `v${version}` };\n }\n return { name: \"git\", status: \"fail\", message: `v${version} (requires >= 2.20)` };\n } catch {\n return { name: \"git\", status: \"fail\", message: \"not installed\" };\n }\n}\n\nasync function checkGlobalConfig(): Promise<CheckResult> {\n try {\n const config = await loadGlobalConfig();\n const globalDir = getDataDir();\n const repoCount = config.repos.length;\n return {\n name: \"Global config\",\n status: \"pass\",\n message: `${globalDir}/config.yml (budget: $${config.budget.dailyCapUsd}/day, ${repoCount} repos)`,\n };\n } catch (error) {\n return {\n name: \"Global config\",\n status: \"fail\",\n message: `Invalid: ${error instanceof Error ? error.message : String(error)}`,\n };\n }\n}\n\nasync function checkRepoRegistered(): Promise<CheckResult> {\n const cwd = process.cwd();\n const repos = await listReposFromGlobalConfig();\n const match = repos.find((r) => path.resolve(r.path) === cwd);\n\n if (match) {\n return {\n name: \"Repo registered\",\n status: \"pass\",\n message: `\"${toRepoSlug(match)}\" (branch: ${match.defaultBranch})`,\n };\n }\n\n return {\n name: \"Repo registered\",\n status: \"info\",\n message:\n \"CWD not registered. Run 'neo init' or 'neo repos add'. Zero-config mode works without registration.\",\n };\n}\n\nasync function checkLegacyConfig(): Promise<CheckResult | null> {\n const legacyPath = path.resolve(\".neo/config.yml\");\n if (existsSync(legacyPath)) {\n return {\n name: \"Legacy config\",\n status: \"info\",\n message:\n \".neo/config.yml detected — this file is no longer needed. Config is now in ~/.neo/config.yml.\",\n };\n }\n return null;\n}\n\nasync function checkTmux(): Promise<CheckResult> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\"-V\"]);\n return { name: \"tmux\", status: \"pass\", message: stdout.trim() };\n } catch {\n return {\n name: \"tmux\",\n status: \"info\",\n message: \"not installed (required for neo supervise)\",\n };\n }\n}\n\nasync function checkClaudeCli(): Promise<CheckResult> {\n try {\n const { stdout } = await execFileAsync(\"claude\", [\"--version\"]);\n return { name: \"Claude CLI\", status: \"pass\", message: stdout.trim() };\n } catch {\n return { name: \"Claude CLI\", status: \"fail\", message: \"not installed or not in PATH\" };\n }\n}\n\nasync function checkAgents(): Promise<CheckResult> {\n try {\n const agentsDir = resolveAgentsDir();\n if (!existsSync(agentsDir)) {\n return { name: \"Agents\", status: \"fail\", message: \"Agent definitions not found\" };\n }\n const registry = new AgentRegistry(agentsDir);\n await registry.load();\n const count = registry.list().length;\n return { name: \"Agents\", status: \"pass\", message: `${count} agents loaded` };\n } catch (error) {\n return {\n name: \"Agents\",\n status: \"fail\",\n message: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nasync function checkJournalDirs(): Promise<CheckResult> {\n const journalDir = getJournalsDir();\n if (!existsSync(journalDir)) {\n return {\n name: \"Journals\",\n status: \"pass\",\n message: \"Directory will be created on first write\",\n };\n }\n try {\n await access(journalDir, constants.W_OK);\n return { name: \"Journals\", status: \"pass\", message: journalDir };\n } catch {\n return { name: \"Journals\", status: \"fail\", message: `${journalDir} is not writable` };\n }\n}\n\nexport default defineCommand({\n meta: {\n name: \"doctor\",\n description: \"Check environment prerequisites (Node.js, git, config, Claude CLI)\",\n },\n args: {\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n\n const checks = (\n await Promise.all([\n checkNodeVersion(),\n checkGit(),\n checkGlobalConfig(),\n checkRepoRegistered(),\n checkLegacyConfig(),\n checkTmux(),\n checkClaudeCli(),\n checkAgents(),\n checkJournalDirs(),\n ])\n ).filter((c): c is CheckResult => c !== null);\n\n if (jsonOutput) {\n printJson({ checks });\n if (checks.some((c) => c.status === \"fail\")) {\n process.exitCode = 1;\n }\n return;\n }\n\n let hasFailure = false;\n for (const check of checks) {\n if (check.status === \"pass\") {\n printSuccess(`${check.name}: ${check.message ?? \"OK\"}`);\n } else if (check.status === \"info\") {\n console.log(` ${check.name}: ${check.message ?? \"\"}`);\n } else {\n printError(`${check.name}: ${check.message ?? \"FAILED\"}`);\n hasFailure = true;\n }\n }\n\n if (hasFailure) {\n process.exitCode = 1;\n }\n },\n});\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { addRepoToGlobalConfig, getDataDir, loadGlobalConfig } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { detectDefaultBranch } from \"../git-utils.js\";\nimport { printError, printSuccess } from \"../output.js\";\n\nconst GITIGNORE_ENTRY = \".neo/worktrees/\";\n\nasync function ensureGitignore(): Promise<boolean> {\n const gitignorePath = path.resolve(\".gitignore\");\n\n if (existsSync(gitignorePath)) {\n const content = await readFile(gitignorePath, \"utf-8\");\n if (content.includes(GITIGNORE_ENTRY)) return false;\n await appendFile(gitignorePath, `\\n# neo worktrees (ephemeral)\\n${GITIGNORE_ENTRY}\\n`);\n } else {\n await appendFile(gitignorePath, `# neo worktrees (ephemeral)\\n${GITIGNORE_ENTRY}\\n`);\n }\n\n return true;\n}\n\nexport default defineCommand({\n meta: {\n name: \"init\",\n description: \"Initialize a .neo/ project directory and register the repo\",\n },\n args: {\n force: {\n type: \"boolean\",\n description: \"Re-register even if already initialized\",\n default: false,\n },\n },\n async run({ args }) {\n const agentsDir = path.resolve(\".neo/agents\");\n\n if (existsSync(agentsDir) && !args.force) {\n printError(\".neo/agents/ already exists. Use --force to re-register.\");\n process.exitCode = 1;\n return;\n }\n\n // Create .neo/agents/ for project-local agent definitions\n await mkdir(agentsDir, { recursive: true });\n printSuccess(\"Created .neo/agents/\");\n\n // Ensure .neo/worktrees/ is in .gitignore\n if (await ensureGitignore()) {\n printSuccess(`Added ${GITIGNORE_ENTRY} to .gitignore`);\n }\n\n // Detect default branch and register repo in global config\n const branch = await detectDefaultBranch();\n const repoPath = path.resolve(\".\");\n\n await addRepoToGlobalConfig({\n path: repoPath,\n defaultBranch: branch,\n });\n printSuccess(`Registered repo in global config (branch: ${branch})`);\n\n // Ensure global config exists (creates with defaults if missing)\n const globalConfig = await loadGlobalConfig();\n const globalDir = getDataDir();\n printSuccess(\n `Global config at ${globalDir}/config.yml (budget: $${globalConfig.budget.dailyCapUsd}/day)`,\n );\n\n printSuccess(\"neo initialized. Run 'neo doctor' to verify setup.\");\n },\n});\n"],"mappings":";;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,YAAY,OAAO,gBAAgB;AAC5C,OAAO,UAAU;AACjB,SAAS,uBAAuB,YAAY,wBAAwB;AACpE,SAAS,qBAAqB;AAI9B,IAAM,kBAAkB;AAExB,eAAe,kBAAoC;AACjD,QAAM,gBAAgB,KAAK,QAAQ,YAAY;AAE/C,MAAI,WAAW,aAAa,GAAG;AAC7B,UAAM,UAAU,MAAM,SAAS,eAAe,OAAO;AACrD,QAAI,QAAQ,SAAS,eAAe,EAAG,QAAO;AAC9C,UAAM,WAAW,eAAe;AAAA;AAAA,EAAkC,eAAe;AAAA,CAAI;AAAA,EACvF,OAAO;AACL,UAAM,WAAW,eAAe;AAAA,EAAgC,eAAe;AAAA,CAAI;AAAA,EACrF;AAEA,SAAO;AACT;AAEA,IAAO,eAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,YAAY,KAAK,QAAQ,aAAa;AAE5C,QAAI,WAAW,SAAS,KAAK,CAAC,KAAK,OAAO;AACxC,iBAAW,0DAA0D;AACrE,cAAQ,WAAW;AACnB;AAAA,IACF;AAGA,UAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,iBAAa,sBAAsB;AAGnC,QAAI,MAAM,gBAAgB,GAAG;AAC3B,mBAAa,SAAS,eAAe,gBAAgB;AAAA,IACvD;AAGA,UAAM,SAAS,MAAM,oBAAoB;AACzC,UAAM,WAAW,KAAK,QAAQ,GAAG;AAEjC,UAAM,sBAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,eAAe;AAAA,IACjB,CAAC;AACD,iBAAa,6CAA6C,MAAM,GAAG;AAGnE,UAAM,eAAe,MAAM,iBAAiB;AAC5C,UAAM,YAAY,WAAW;AAC7B;AAAA,MACE,oBAAoB,SAAS,yBAAyB,aAAa,OAAO,WAAW;AAAA,IACvF;AAEA,iBAAa,oDAAoD;AAAA,EACnE;AACF,CAAC;","names":[]}
|
package/dist/mcp-GH6CCW7A.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport { loadGlobalConfig, type McpServerConfig } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { printError, printSuccess, printTable } from \"../output.js\";\n\n// ─── Presets for popular MCP servers ─────────────────────\n\nconst MCP_PRESETS: Record<string, { config: McpServerConfig; envVars: string[] }> = {\n linear: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@anthropic/linear-mcp-server\"],\n env: { LINEAR_API_KEY: \"${LINEAR_API_KEY}\" },\n },\n envVars: [\"LINEAR_API_KEY\"],\n },\n notion: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@notionhq/notion-mcp-server\"],\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 env: { GITHUB_PERSONAL_ACCESS_TOKEN: \"${GITHUB_TOKEN}\" },\n },\n envVars: [\"GITHUB_TOKEN\"],\n },\n jira: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@anthropic/jira-mcp-server\"],\n env: { JIRA_API_TOKEN: \"${JIRA_API_TOKEN}\", JIRA_URL: \"${JIRA_URL}\" },\n },\n envVars: [\"JIRA_API_TOKEN\", \"JIRA_URL\"],\n },\n slack: {\n config: {\n type: \"stdio\",\n command: \"npx\",\n args: [\"-y\", \"@modelcontextprotocol/server-slack\"],\n env: { SLACK_BOT_TOKEN: \"${SLACK_BOT_TOKEN}\" },\n },\n envVars: [\"SLACK_BOT_TOKEN\"],\n },\n};\n\n// ─── Helpers ─────────────────────────────────────────────\n\nasync function loadAndModifyConfig(\n modify: (config: Record<string, unknown>) => void,\n): Promise<void> {\n const configPath = path.join(homedir(), \".neo\", \"config.yml\");\n let config: Record<string, unknown>;\n\n try {\n const raw = await readFile(configPath, \"utf-8\");\n config = (parseYaml(raw) as Record<string, unknown>) ?? {};\n } catch {\n config = {};\n }\n\n modify(config);\n await writeFile(configPath, stringifyYaml(config), \"utf-8\");\n}\n\n// ─── Subcommands ─────────────────────────────────────────\n\nconst listCmd = defineCommand({\n meta: { name: \"list\", description: \"List configured MCP servers\" },\n async run() {\n const config = await loadGlobalConfig();\n const servers = config.mcpServers ?? {};\n const entries = Object.entries(servers);\n\n if (entries.length === 0) {\n console.log(\"No MCP servers configured.\");\n console.log(\"Add one with: neo mcp add <name> or neo mcp add <preset>\");\n console.log(`Available presets: ${Object.keys(MCP_PRESETS).join(\", \")}`);\n return;\n }\n\n const rows = entries.map(([name, cfg]) => {\n if (cfg.type === \"stdio\") {\n return [name, \"stdio\", `${cfg.command} ${(cfg.args ?? []).join(\" \")}`];\n }\n return [name, \"http\", cfg.url];\n });\n\n printTable([\"Name\", \"Type\", \"Config\"], rows);\n },\n});\n\nconst addCmd = defineCommand({\n meta: { name: \"add\", description: \"Add an MCP server (use a preset name or custom flags)\" },\n args: {\n name: {\n type: \"positional\",\n description: \"Server name or preset (linear, notion, github, jira, slack)\",\n },\n type: { type: \"string\", description: \"Server type: stdio or http\" },\n command: { type: \"string\", description: \"Command for stdio servers\" },\n serverArgs: { type: \"string\", description: \"Comma-separated args for stdio servers\" },\n url: { type: \"string\", description: \"URL for http servers\" },\n },\n async run({ args }) {\n const name = args.name as string | undefined;\n if (!name) {\n printError(\"Server name is required. Usage: neo mcp add <name>\");\n process.exitCode = 1;\n return;\n }\n\n // Check if it's a preset\n const preset = MCP_PRESETS[name];\n if (preset) {\n // Check env vars\n const missing = preset.envVars.filter((v: string) => !process.env[v]);\n if (missing.length > 0) {\n console.log(`Preset \"${name}\" requires the following environment variables:`);\n for (const v of missing) {\n console.log(` ${v} (not set)`);\n }\n console.log(\"\\nSet them before starting the supervisor.\");\n }\n\n await loadAndModifyConfig((config) => {\n const servers = (config.mcpServers as Record<string, unknown>) ?? {};\n servers[name] = preset.config;\n config.mcpServers = servers;\n });\n\n printSuccess(`Added MCP server \"${name}\" (preset)`);\n return;\n }\n\n // Custom server\n if (!args.type) {\n printError(`Unknown preset \"${name}\". Use --type stdio or --type http for custom servers.`);\n console.log(`Available presets: ${Object.keys(MCP_PRESETS).join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n let serverConfig: McpServerConfig;\n if (args.type === \"stdio\") {\n if (!args.command) {\n printError(\"--command is required for stdio servers\");\n process.exitCode = 1;\n return;\n }\n serverConfig = {\n type: \"stdio\",\n command: args.command,\n args: args.serverArgs ? args.serverArgs.split(\",\") : undefined,\n };\n } else if (args.type === \"http\") {\n if (!args.url) {\n printError(\"--url is required for http servers\");\n process.exitCode = 1;\n return;\n }\n serverConfig = {\n type: \"http\",\n url: args.url,\n };\n } else {\n printError(`Invalid type \"${args.type}\". Use \"stdio\" or \"http\".`);\n process.exitCode = 1;\n return;\n }\n\n await loadAndModifyConfig((config) => {\n const servers = (config.mcpServers as Record<string, unknown>) ?? {};\n servers[name] = serverConfig;\n config.mcpServers = servers;\n });\n\n printSuccess(`Added MCP server \"${name}\"`);\n },\n});\n\nconst removeCmd = defineCommand({\n meta: { name: \"remove\", description: \"Remove an MCP server\" },\n args: {\n name: { type: \"positional\", description: \"Server name to remove\" },\n },\n async run({ args }) {\n const name = args.name as string | undefined;\n if (!name) {\n printError(\"Server name is required. Usage: neo mcp remove <name>\");\n process.exitCode = 1;\n return;\n }\n\n let found = false;\n\n await loadAndModifyConfig((config) => {\n const servers = config.mcpServers as Record<string, unknown> | undefined;\n if (servers && name in servers) {\n delete servers[name];\n found = true;\n if (Object.keys(servers).length === 0) {\n delete config.mcpServers;\n }\n }\n });\n\n if (found) {\n printSuccess(`Removed MCP server \"${name}\"`);\n } else {\n printError(`MCP server \"${name}\" not found`);\n process.exitCode = 1;\n }\n },\n});\n\n// ─── Main command ────────────────────────────────────────\n\nexport default defineCommand({\n meta: {\n name: \"mcp\",\n description: \"Manage MCP server integrations (Linear, Notion, GitHub, etc.)\",\n },\n subCommands: {\n list: () => Promise.resolve(listCmd),\n add: () => Promise.resolve(addCmd),\n remove: () => Promise.resolve(removeCmd),\n },\n});\n"],"mappings":"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","names":[]}
|
package/dist/run-KIU2ZE72.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/run.ts"],"sourcesContent":["import { fork } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NeoEvent, PersistedRun } from \"@neotx/core\";\nimport {\n AgentRegistry,\n getRepoRunsDir,\n getRunDispatchPath,\n loadGlobalConfig,\n Orchestrator,\n toRepoSlug,\n} from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printJson, printSuccess } from \"../output.js\";\nimport { resolveAgentsDir } from \"../resolve.js\";\n\nfunction printProgress(event: NeoEvent): void {\n const ts = event.timestamp.slice(11, 19);\n switch (event.type) {\n case \"session:start\":\n console.log(`[${ts}] ${event.agent}: starting`);\n break;\n case \"session:complete\":\n console.log(`[${ts}] session complete: $${event.costUsd.toFixed(4)}`);\n break;\n case \"session:fail\":\n console.log(`[${ts}] session failed: ${event.error}`);\n break;\n case \"cost:update\":\n break;\n case \"budget:alert\":\n console.log(`[${ts}] ⚠ Budget alert: ${event.utilizationPct.toFixed(0)}% used`);\n break;\n }\n}\n\nfunction parseMetadata(meta: string | undefined): Record<string, unknown> | undefined {\n if (!meta) return undefined;\n try {\n return JSON.parse(meta) as Record<string, unknown>;\n } catch {\n throw new Error(`Invalid --meta JSON: ${meta}`);\n }\n}\n\nfunction printResult(result: import(\"@neotx/core\").TaskResult, agentName: string): void {\n console.log(\"\");\n console.log(`Run: ${result.runId}`);\n console.log(`Agent: ${agentName}`);\n console.log(`Status: ${result.status}`);\n console.log(`Cost: $${result.costUsd.toFixed(4)}`);\n console.log(`Duration: ${(result.durationMs / 1000).toFixed(1)}s`);\n if (result.branch) {\n console.log(`Branch: ${result.branch}`);\n }\n\n const stepResult = Object.values(result.steps)[0];\n const output = stepResult?.output ?? result.summary;\n if (output) {\n console.log(\"\");\n console.log(typeof output === \"string\" ? output : JSON.stringify(output, null, 2));\n }\n}\n\ninterface DetachParams {\n agentName: string;\n repo: string;\n prompt: string;\n priority: string;\n metadata: Record<string, unknown> | undefined;\n bundledAgentsDir: string;\n customAgentsDir: string | undefined;\n jsonOutput: boolean;\n}\n\nasync function runDetached(params: DetachParams): Promise<void> {\n const runId = randomUUID();\n const repoSlug = toRepoSlug({ path: params.repo });\n const runsDir = getRepoRunsDir(repoSlug);\n await mkdir(runsDir, { recursive: true });\n\n const persistedRun: PersistedRun = {\n version: 1,\n runId,\n workflow: `_run_${params.agentName}`,\n repo: params.repo,\n prompt: params.prompt,\n status: \"running\",\n steps: {},\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n metadata: params.metadata,\n };\n await writeFile(\n path.join(runsDir, `${runId}.json`),\n JSON.stringify(persistedRun, null, 2),\n \"utf-8\",\n );\n\n const dispatchPath = getRunDispatchPath(repoSlug, runId);\n await writeFile(\n dispatchPath,\n JSON.stringify({\n agentName: params.agentName,\n repo: params.repo,\n prompt: params.prompt,\n priority: params.priority,\n metadata: params.metadata,\n bundledAgentsDir: params.bundledAgentsDir,\n customAgentsDir: params.customAgentsDir,\n }),\n \"utf-8\",\n );\n\n const workerPath = path.join(path.dirname(fileURLToPath(import.meta.url)), \"daemon\", \"worker.js\");\n const child = fork(workerPath, [runId, repoSlug], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n\n if (params.jsonOutput) {\n printJson({ runId, status: \"detached\", pid: child.pid });\n } else {\n printSuccess(`Detached run started: ${runId}`);\n console.log(` PID: ${String(child.pid)}`);\n console.log(` Logs: neo logs -f ${runId}`);\n }\n}\n\nexport default defineCommand({\n meta: {\n name: \"run\",\n description: \"Dispatch an agent to execute a task in an isolated worktree\",\n },\n args: {\n agent: {\n type: \"positional\",\n description: \"Agent name to run (e.g. developer, architect, reviewer-quality)\",\n required: true,\n },\n repo: {\n type: \"string\",\n description: \"Target repository path\",\n default: \".\",\n },\n prompt: {\n type: \"string\",\n description: \"Task description for the agent\",\n required: true,\n },\n priority: {\n type: \"string\",\n description: \"Priority level: critical, high, medium, low\",\n },\n meta: {\n type: \"string\",\n description: \"Metadata as JSON string\",\n },\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n detach: {\n type: \"boolean\",\n alias: \"d\",\n description: \"Run in background and return immediately with the run ID\",\n default: false,\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n\n // Zero-config: only need global config (auto-creates ~/.neo/config.yml if absent)\n const config = await loadGlobalConfig();\n const repo = path.resolve(args.repo);\n\n // Load agent registry (bundled + project-local agents)\n const bundledAgentsDir = resolveAgentsDir();\n const customAgentsDir = path.resolve(\".neo/agents\");\n const agentRegistry = new AgentRegistry(\n bundledAgentsDir,\n existsSync(customAgentsDir) ? customAgentsDir : undefined,\n );\n await agentRegistry.load();\n\n // Validate agent exists\n const agent = agentRegistry.get(args.agent);\n if (!agent) {\n const available = agentRegistry\n .list()\n .map((a) => a.name)\n .join(\", \");\n printError(`Agent \"${args.agent}\" not found. Available: ${available}`);\n process.exitCode = 1;\n return;\n }\n\n if (args.detach) {\n await runDetached({\n agentName: args.agent,\n repo,\n prompt: args.prompt,\n priority: args.priority ?? \"medium\",\n metadata: parseMetadata(args.meta),\n bundledAgentsDir,\n customAgentsDir: existsSync(customAgentsDir) ? customAgentsDir : undefined,\n jsonOutput,\n });\n return;\n }\n\n // ─── Foreground mode (default) ──────────────────────\n const orchestrator = new Orchestrator(config);\n orchestrator.registerAgent(agent);\n orchestrator.registerWorkflow({\n name: `_run_${args.agent}`,\n description: `Direct dispatch to ${args.agent}`,\n steps: {\n run: { agent: args.agent },\n },\n });\n\n if (!jsonOutput) {\n orchestrator.on(\"*\", printProgress);\n }\n\n try {\n await orchestrator.start();\n\n const result = await orchestrator.dispatch({\n workflow: `_run_${args.agent}`,\n repo,\n prompt: args.prompt,\n priority: (args.priority as \"critical\" | \"high\" | \"medium\" | \"low\") ?? \"medium\",\n metadata: parseMetadata(args.meta),\n });\n\n if (jsonOutput) {\n printJson(result);\n } else {\n printResult(result, args.agent);\n }\n\n await orchestrator.shutdown();\n if (result.status !== \"success\") {\n process.exitCode = 1;\n }\n } catch (error) {\n await orchestrator.shutdown();\n printError(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n },\n});\n"],"mappings":";;;;;;;;;;AAAA,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,OAAO,iBAAiB;AACjC,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,qBAAqB;AAI9B,SAAS,cAAc,OAAuB;AAC5C,QAAM,KAAK,MAAM,UAAU,MAAM,IAAI,EAAE;AACvC,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AACH,cAAQ,IAAI,IAAI,EAAE,KAAK,MAAM,KAAK,YAAY;AAC9C;AAAA,IACF,KAAK;AACH,cAAQ,IAAI,IAAI,EAAE,wBAAwB,MAAM,QAAQ,QAAQ,CAAC,CAAC,EAAE;AACpE;AAAA,IACF,KAAK;AACH,cAAQ,IAAI,IAAI,EAAE,qBAAqB,MAAM,KAAK,EAAE;AACpD;AAAA,IACF,KAAK;AACH;AAAA,IACF,KAAK;AACH,cAAQ,IAAI,IAAI,EAAE,0BAAqB,MAAM,eAAe,QAAQ,CAAC,CAAC,QAAQ;AAC9E;AAAA,EACJ;AACF;AAEA,SAAS,cAAc,MAA+D;AACpF,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,UAAM,IAAI,MAAM,wBAAwB,IAAI,EAAE;AAAA,EAChD;AACF;AAEA,SAAS,YAAY,QAA0C,WAAyB;AACtF,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,aAAa,OAAO,KAAK,EAAE;AACvC,UAAQ,IAAI,aAAa,SAAS,EAAE;AACpC,UAAQ,IAAI,aAAa,OAAO,MAAM,EAAE;AACxC,UAAQ,IAAI,cAAc,OAAO,QAAQ,QAAQ,CAAC,CAAC,EAAE;AACrD,UAAQ,IAAI,cAAc,OAAO,aAAa,KAAM,QAAQ,CAAC,CAAC,GAAG;AACjE,MAAI,OAAO,QAAQ;AACjB,YAAQ,IAAI,aAAa,OAAO,MAAM,EAAE;AAAA,EAC1C;AAEA,QAAM,aAAa,OAAO,OAAO,OAAO,KAAK,EAAE,CAAC;AAChD,QAAM,SAAS,YAAY,UAAU,OAAO;AAC5C,MAAI,QAAQ;AACV,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAAA,EACnF;AACF;AAaA,eAAe,YAAY,QAAqC;AAC9D,QAAM,QAAQ,WAAW;AACzB,QAAM,WAAW,WAAW,EAAE,MAAM,OAAO,KAAK,CAAC;AACjD,QAAM,UAAU,eAAe,QAAQ;AACvC,QAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AAExC,QAAM,eAA6B;AAAA,IACjC,SAAS;AAAA,IACT;AAAA,IACA,UAAU,QAAQ,OAAO,SAAS;AAAA,IAClC,MAAM,OAAO;AAAA,IACb,QAAQ,OAAO;AAAA,IACf,QAAQ;AAAA,IACR,OAAO,CAAC;AAAA,IACR,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,UAAU,OAAO;AAAA,EACnB;AACA,QAAM;AAAA,IACJ,KAAK,KAAK,SAAS,GAAG,KAAK,OAAO;AAAA,IAClC,KAAK,UAAU,cAAc,MAAM,CAAC;AAAA,IACpC;AAAA,EACF;AAEA,QAAM,eAAe,mBAAmB,UAAU,KAAK;AACvD,QAAM;AAAA,IACJ;AAAA,IACA,KAAK,UAAU;AAAA,MACb,WAAW,OAAO;AAAA,MAClB,MAAM,OAAO;AAAA,MACb,QAAQ,OAAO;AAAA,MACf,UAAU,OAAO;AAAA,MACjB,UAAU,OAAO;AAAA,MACjB,kBAAkB,OAAO;AAAA,MACzB,iBAAiB,OAAO;AAAA,IAC1B,CAAC;AAAA,IACD;AAAA,EACF;AAEA,QAAM,aAAa,KAAK,KAAK,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC,GAAG,UAAU,WAAW;AAChG,QAAM,QAAQ,KAAK,YAAY,CAAC,OAAO,QAAQ,GAAG;AAAA,IAChD,UAAU;AAAA,IACV,OAAO;AAAA,EACT,CAAC;AACD,QAAM,MAAM;AAEZ,MAAI,OAAO,YAAY;AACrB,cAAU,EAAE,OAAO,QAAQ,YAAY,KAAK,MAAM,IAAI,CAAC;AAAA,EACzD,OAAO;AACL,iBAAa,yBAAyB,KAAK,EAAE;AAC7C,YAAQ,IAAI,WAAW,OAAO,MAAM,GAAG,CAAC,EAAE;AAC1C,YAAQ,IAAI,uBAAuB,KAAK,EAAE;AAAA,EAC5C;AACF;AAEA,IAAO,cAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ;AAAA,IACA,UAAU;AAAA,MACR,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,aAAa,KAAK,WAAW;AAGnC,UAAM,SAAS,MAAM,iBAAiB;AACtC,UAAM,OAAO,KAAK,QAAQ,KAAK,IAAI;AAGnC,UAAM,mBAAmB,iBAAiB;AAC1C,UAAM,kBAAkB,KAAK,QAAQ,aAAa;AAClD,UAAM,gBAAgB,IAAI;AAAA,MACxB;AAAA,MACA,WAAW,eAAe,IAAI,kBAAkB;AAAA,IAClD;AACA,UAAM,cAAc,KAAK;AAGzB,UAAM,QAAQ,cAAc,IAAI,KAAK,KAAK;AAC1C,QAAI,CAAC,OAAO;AACV,YAAM,YAAY,cACf,KAAK,EACL,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,IAAI;AACZ,iBAAW,UAAU,KAAK,KAAK,2BAA2B,SAAS,EAAE;AACrE,cAAQ,WAAW;AACnB;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ;AACf,YAAM,YAAY;AAAA,QAChB,WAAW,KAAK;AAAA,QAChB;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,UAAU,KAAK,YAAY;AAAA,QAC3B,UAAU,cAAc,KAAK,IAAI;AAAA,QACjC;AAAA,QACA,iBAAiB,WAAW,eAAe,IAAI,kBAAkB;AAAA,QACjE;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAGA,UAAM,eAAe,IAAI,aAAa,MAAM;AAC5C,iBAAa,cAAc,KAAK;AAChC,iBAAa,iBAAiB;AAAA,MAC5B,MAAM,QAAQ,KAAK,KAAK;AAAA,MACxB,aAAa,sBAAsB,KAAK,KAAK;AAAA,MAC7C,OAAO;AAAA,QACL,KAAK,EAAE,OAAO,KAAK,MAAM;AAAA,MAC3B;AAAA,IACF,CAAC;AAED,QAAI,CAAC,YAAY;AACf,mBAAa,GAAG,KAAK,aAAa;AAAA,IACpC;AAEA,QAAI;AACF,YAAM,aAAa,MAAM;AAEzB,YAAM,SAAS,MAAM,aAAa,SAAS;AAAA,QACzC,UAAU,QAAQ,KAAK,KAAK;AAAA,QAC5B;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,UAAW,KAAK,YAAuD;AAAA,QACvE,UAAU,cAAc,KAAK,IAAI;AAAA,MACnC,CAAC;AAED,UAAI,YAAY;AACd,kBAAU,MAAM;AAAA,MAClB,OAAO;AACL,oBAAY,QAAQ,KAAK,KAAK;AAAA,MAChC;AAEA,YAAM,aAAa,SAAS;AAC5B,UAAI,OAAO,WAAW,WAAW;AAC/B,gBAAQ,WAAW;AAAA,MACrB;AAAA,IACF,SAAS,OAAO;AACd,YAAM,aAAa,SAAS;AAC5B,iBAAW,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACjE,cAAQ,WAAW;AAAA,IACrB;AAAA,EACF;AACF,CAAC;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/runs.ts"],"sourcesContent":["import type { PersistedRun } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printJson, printTable } from \"../output.js\";\nimport { loadRunsFiltered, resolveRepoFilter } from \"../repo-filter.js\";\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction totalCost(run: PersistedRun): number {\n return Object.values(run.steps).reduce((sum, s) => sum + s.costUsd, 0);\n}\n\nfunction totalDuration(run: PersistedRun): number {\n return Object.values(run.steps).reduce((sum, s) => sum + s.durationMs, 0);\n}\n\nfunction shortId(runId: string): string {\n return runId.slice(0, 8);\n}\n\nfunction showRunDetail(match: PersistedRun, short: boolean): void {\n if (short) {\n console.log(`${match.runId} ${match.status} $${totalCost(match).toFixed(4)}`);\n for (const [name, step] of Object.entries(match.steps)) {\n const out = typeof step.output === \"string\" ? step.output.slice(0, 200) : \"\";\n console.log(` ${name}: ${step.status} ${step.agent} ${out}`);\n }\n return;\n }\n\n console.log(`Run: ${match.runId}`);\n console.log(`Status: ${match.status}`);\n console.log(`Repo: ${match.repo}`);\n console.log(`Prompt: ${match.prompt}`);\n if (match.branch) console.log(`Branch: ${match.branch}`);\n console.log(`Cost: $${totalCost(match).toFixed(4)}`);\n console.log(`Duration: ${formatDuration(totalDuration(match))}`);\n console.log(`Created: ${match.createdAt}`);\n console.log(\"\");\n for (const [name, step] of Object.entries(match.steps)) {\n console.log(`Step: ${name}`);\n console.log(` Agent: ${step.agent}`);\n console.log(` Status: ${step.status}`);\n console.log(` Cost: $${step.costUsd.toFixed(4)}`);\n console.log(` Duration: ${formatDuration(step.durationMs)}`);\n if (step.error) console.log(` Error: ${step.error}`);\n if (step.output) {\n const out = typeof step.output === \"string\" ? step.output : JSON.stringify(step.output);\n console.log(` Output: ${out}`);\n }\n }\n}\n\nfunction listRuns(runs: PersistedRun[], short: boolean): void {\n if (short) {\n for (const r of runs) {\n const agent = Object.values(r.steps)[0]?.agent ?? \"?\";\n console.log(\n `${shortId(r.runId)} ${r.status.padEnd(9)} ${agent.padEnd(18)} $${totalCost(r).toFixed(4).padStart(8)} ${formatDuration(totalDuration(r)).padStart(7)}`,\n );\n }\n return;\n }\n\n if (runs.length === 0) {\n console.log(\"No runs found.\");\n return;\n }\n\n printTable(\n [\"RUN\", \"STATUS\", \"AGENT\", \"COST\", \"DURATION\", \"BRANCH\"],\n runs.map((r) => [\n shortId(r.runId),\n r.status,\n Object.values(r.steps)[0]?.agent ?? \"unknown\",\n `$${totalCost(r).toFixed(4)}`,\n formatDuration(totalDuration(r)),\n r.branch?.replace(\"feat/run-\", \"\").slice(0, 8) ?? \"-\",\n ]),\n );\n}\n\nexport default defineCommand({\n meta: {\n name: \"runs\",\n description: \"List runs or show details of a specific run\",\n },\n args: {\n runId: {\n type: \"positional\",\n description: \"Run ID to show details (omit to list all runs)\",\n required: false,\n },\n all: {\n type: \"boolean\",\n description: \"Show runs from all repos\",\n default: false,\n },\n repo: {\n type: \"string\",\n description: \"Filter by repo name or path\",\n },\n last: {\n type: \"string\",\n description: \"Show only the last N runs\",\n },\n status: {\n type: \"string\",\n description: \"Filter by status: completed, failed, running\",\n },\n short: {\n type: \"boolean\",\n description: \"Compact output for supervisor agents (saves tokens)\",\n default: false,\n },\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n const filter = await resolveRepoFilter({ all: args.all, repo: args.repo });\n let runs = await loadRunsFiltered(filter);\n\n if (runs.length === 0) {\n if (!jsonOutput) {\n printError(\"No runs found. Run 'neo run <agent>' first.\");\n } else {\n printJson([]);\n }\n return;\n }\n\n // If a runId is given (full or prefix), show details\n if (args.runId) {\n const match = runs.find(\n (r) => r.runId === args.runId || r.runId.startsWith(args.runId as string),\n );\n if (!match) {\n printError(`Run \"${args.runId}\" not found.`);\n process.exitCode = 1;\n return;\n }\n\n if (jsonOutput) {\n printJson(match);\n return;\n }\n\n showRunDetail(match, args.short);\n return;\n }\n\n // List mode\n if (args.status) {\n runs = runs.filter((r) => r.status === args.status);\n }\n\n if (args.last) {\n runs = runs.slice(0, Number(args.last));\n }\n\n if (jsonOutput) {\n printJson(\n runs.map((r) => ({\n runId: r.runId,\n status: r.status,\n repo: r.repo,\n agent: Object.values(r.steps)[0]?.agent ?? \"unknown\",\n costUsd: totalCost(r),\n durationMs: totalDuration(r),\n branch: r.branch,\n updatedAt: r.updatedAt,\n })),\n );\n return;\n }\n\n listRuns(runs, args.short);\n },\n});\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/supervise.ts","../src/tmux.ts"],"sourcesContent":["import { spawn } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { closeSync, existsSync, openSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile, rm } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n getSupervisorDir,\n getSupervisorInboxPath,\n getSupervisorLockPath,\n getSupervisorStatePath,\n loadGlobalConfig,\n type SupervisorDaemonState,\n supervisorDaemonStateSchema,\n} from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printSuccess } from \"../output.js\";\nimport { isTmuxInstalled, tmuxKill, tmuxNewSession, tmuxSessionExists } from \"../tmux.js\";\n\nconst DEFAULT_NAME = \"supervisor\";\n\nasync function readState(name: string): Promise<SupervisorDaemonState | null> {\n const statePath = getSupervisorStatePath(name);\n if (!existsSync(statePath)) return null;\n try {\n const raw = await readFile(statePath, \"utf-8\");\n return supervisorDaemonStateSchema.parse(JSON.parse(raw));\n } catch {\n return null;\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isDaemonRunning(name: string): Promise<SupervisorDaemonState | null> {\n const state = await readState(name);\n if (!state || state.status === \"stopped\") return null;\n if (!isProcessAlive(state.pid)) return null;\n return state;\n}\n\nasync function handleStatus(name: string): Promise<void> {\n const state = await isDaemonRunning(name);\n if (!state) {\n console.log(`No supervisor daemon running (name: ${name}).`);\n return;\n }\n\n const config = await loadGlobalConfig();\n printSuccess(`Supervisor \"${name}\" running`);\n console.log(` PID: ${state.pid}`);\n console.log(` Port: ${state.port}`);\n console.log(` Session: ${state.sessionId}`);\n console.log(` Started: ${state.startedAt}`);\n console.log(\n ` Interval: ${config.supervisor.idleIntervalMs / 1000}s (skip up to ${config.supervisor.idleSkipMax} idle)`,\n );\n console.log(` Heartbeats: ${state.heartbeatCount}`);\n if (state.lastHeartbeat) {\n console.log(` Last beat: ${state.lastHeartbeat}`);\n }\n console.log(` Cost today: $${state.todayCostUsd?.toFixed(2) ?? \"0.00\"}`);\n console.log(` Cost total: $${state.totalCostUsd?.toFixed(2) ?? \"0.00\"}`);\n console.log(` Status: ${state.status}`);\n console.log(\"\");\n console.log(` Health: curl localhost:${state.port}/health`);\n console.log(\" Attach: neo supervise --attach\");\n console.log(\" Stop: neo supervise --kill\");\n}\n\nasync function handleKill(name: string): Promise<void> {\n const state = await isDaemonRunning(name);\n if (!state) {\n printError(`No supervisor daemon running (name: ${name}).`);\n\n // Clean up stale lock if exists\n const lockPath = getSupervisorLockPath(name);\n if (existsSync(lockPath)) {\n await rm(lockPath, { force: true });\n }\n process.exitCode = 1;\n return;\n }\n\n // Send SIGTERM for graceful shutdown, then SIGKILL after 10s\n const pid = state.pid;\n try {\n process.kill(pid, \"SIGTERM\");\n printSuccess(`Sent SIGTERM to supervisor \"${name}\" (PID ${pid})`);\n } catch {\n printError(`Failed to send signal to PID ${pid}. Cleaning up.`);\n const lockPath = getSupervisorLockPath(name);\n await rm(lockPath, { force: true });\n return;\n }\n\n // Wait up to 10s for graceful exit, then force kill\n const deadline = Date.now() + 10_000;\n while (Date.now() < deadline) {\n await new Promise((r) => setTimeout(r, 500));\n if (!isProcessAlive(pid)) {\n printSuccess(\"Daemon stopped.\");\n return;\n }\n }\n\n // Force kill\n try {\n process.kill(pid, \"SIGKILL\");\n printSuccess(`Daemon did not exit in time — sent SIGKILL (PID ${pid}).`);\n } catch {\n // Already dead\n }\n\n // Clean up lock\n const lockPath = getSupervisorLockPath(name);\n await rm(lockPath, { force: true });\n\n // Also kill tmux session if it exists\n const tmuxName = `neo-${name}`;\n const tmuxExists = await tmuxSessionExists(tmuxName);\n if (tmuxExists) {\n await tmuxKill(tmuxName);\n }\n}\n\nasync function startDaemon(name: string, useTmux: boolean): Promise<void> {\n const running = await isDaemonRunning(name);\n if (running) {\n printError(`Supervisor \"${name}\" is already running (PID ${running.pid}).`);\n printError(\"Use --kill first, or --attach to connect.\");\n process.exitCode = 1;\n return;\n }\n\n // Clean up stale lock\n const lockPath = getSupervisorLockPath(name);\n if (existsSync(lockPath)) {\n await rm(lockPath, { force: true });\n }\n\n // Resolve the worker script path and package root (for module resolution)\n const __dirname = path.dirname(fileURLToPath(import.meta.url));\n const workerPath = path.join(__dirname, \"daemon\", \"supervisor-worker.js\");\n const packageRoot = path.resolve(__dirname, \"..\");\n\n if (useTmux) {\n const tmuxAvailable = await isTmuxInstalled();\n if (!tmuxAvailable) {\n printError(\"tmux not found. Install: brew install tmux\");\n printError(\"Or use --daemon to run without tmux.\");\n process.exitCode = 1;\n return;\n }\n\n const tmuxName = `neo-${name}`;\n const exists = await tmuxSessionExists(tmuxName);\n if (exists) {\n await tmuxKill(tmuxName);\n }\n\n // Launch via tmux so it persists after terminal closes\n await tmuxNewSession(tmuxName, \"node\", [workerPath, name], packageRoot);\n\n const config = await loadGlobalConfig();\n printSuccess(`Supervisor \"${name}\" started in tmux session neo-${name}`);\n console.log(` Port: ${config.supervisor.port}`);\n console.log(` Health: curl localhost:${config.supervisor.port}/health`);\n console.log(` Webhook: curl -X POST localhost:${config.supervisor.port}/webhook -d '{}'`);\n console.log(` Logs: ${getSupervisorDir(name)}/daemon.log`);\n console.log(` Attach: neo supervise --attach`);\n console.log(` Status: neo supervise --status`);\n console.log(` Stop: neo supervise --kill`);\n } else {\n // Spawn as detached child process with stdio to log file\n const logDir = getSupervisorDir(name);\n await mkdir(logDir, { recursive: true });\n const logFd = openSync(path.join(logDir, \"daemon.log\"), \"a\");\n const child = spawn(process.execPath, [workerPath, name], {\n detached: true,\n stdio: [\"ignore\", logFd, logFd],\n cwd: packageRoot,\n });\n child.unref();\n closeSync(logFd);\n\n const config = await loadGlobalConfig();\n printSuccess(`Supervisor \"${name}\" started (PID ${child.pid})`);\n console.log(` Port: ${config.supervisor.port}`);\n console.log(` Health: curl localhost:${config.supervisor.port}/health`);\n console.log(` Webhook: curl -X POST localhost:${config.supervisor.port}/webhook -d '{}'`);\n console.log(` Logs: ${getSupervisorDir(name)}/daemon.log`);\n console.log(` Status: neo supervise --status`);\n console.log(` Stop: neo supervise --kill`);\n }\n}\n\nasync function handleAttach(name: string): Promise<void> {\n const running = await isDaemonRunning(name);\n if (!running) {\n printError(`No supervisor daemon running (name: ${name}).`);\n printError(\"Start with: neo supervise\");\n process.exitCode = 1;\n return;\n }\n\n const { renderSupervisorTui } = await import(\"../tui/index.js\");\n await renderSupervisorTui(name);\n}\n\nasync function handleMessage(name: string, text: string): Promise<void> {\n const running = await isDaemonRunning(name);\n if (!running) {\n printError(`No supervisor daemon running (name: ${name}).`);\n process.exitCode = 1;\n return;\n }\n\n const inboxPath = getSupervisorInboxPath(name);\n const message = {\n id: randomUUID(),\n from: \"api\" as const,\n text,\n timestamp: new Date().toISOString(),\n };\n\n await appendFile(inboxPath, `${JSON.stringify(message)}\\n`, \"utf-8\");\n printSuccess(`Message sent to supervisor \"${name}\".`);\n}\n\nexport default defineCommand({\n meta: {\n name: \"supervise\",\n description: \"Manage the autonomous supervisor daemon\",\n },\n args: {\n name: {\n type: \"string\",\n description: \"Supervisor instance name\",\n default: DEFAULT_NAME,\n },\n status: {\n type: \"boolean\",\n description: \"Show supervisor status\",\n default: false,\n },\n kill: {\n type: \"boolean\",\n description: \"Stop the running supervisor\",\n default: false,\n },\n daemon: {\n type: \"boolean\",\n description: \"Start daemon without tmux (detached process)\",\n default: false,\n },\n attach: {\n type: \"boolean\",\n description: \"Open the TUI for a running supervisor\",\n default: false,\n },\n message: {\n type: \"string\",\n description: \"Send a message to the supervisor inbox\",\n },\n },\n async run({ args }) {\n const name = args.name;\n\n if (args.status) {\n await handleStatus(name);\n return;\n }\n\n if (args.kill) {\n await handleKill(name);\n return;\n }\n\n if (args.attach) {\n await handleAttach(name);\n return;\n }\n\n if (args.message) {\n await handleMessage(name, args.message);\n return;\n }\n\n // Default: start daemon + open TUI\n const alreadyRunning = await isDaemonRunning(name);\n if (!alreadyRunning) {\n await startDaemon(name, !args.daemon);\n // Give daemon a moment to initialize\n await new Promise((r) => setTimeout(r, 1_000));\n }\n\n // Open TUI unless --daemon (headless mode)\n if (!args.daemon) {\n const { renderSupervisorTui } = await import(\"../tui/index.js\");\n await renderSupervisorTui(name);\n }\n },\n});\n","import { execFile, spawnSync } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Check if tmux binary is available. */\nexport async function isTmuxInstalled(): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"-V\"]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Get tmux version string, or null if not installed. */\nexport async function getTmuxVersion(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\"-V\"]);\n return stdout.trim();\n } catch {\n return null;\n }\n}\n\n/** Check if a tmux session with the given name exists. */\nexport async function tmuxSessionExists(name: string): Promise<boolean> {\n try {\n await execFileAsync(\"tmux\", [\"has-session\", \"-t\", name]);\n return true;\n } catch {\n return false;\n }\n}\n\n/** Create a new detached tmux session running the given command.\n * Sets remain-on-exit so the pane stays alive when the process exits. */\nexport async function tmuxNewSession(\n name: string,\n command: string,\n args: string[],\n cwd: string,\n): Promise<void> {\n await execFileAsync(\"tmux\", [\"new-session\", \"-d\", \"-s\", name, \"-c\", cwd, command, ...args]);\n // Keep the pane alive when the process exits so we can respawn it\n await execFileAsync(\"tmux\", [\"set-option\", \"-t\", name, \"remain-on-exit\", \"on\"]);\n}\n\n/** Check if the first pane in the session has a dead process. */\nexport async function tmuxPaneDead(name: string): Promise<boolean> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\n \"list-panes\",\n \"-t\",\n name,\n \"-F\",\n \"#{pane_dead}\",\n ]);\n return stdout.trim() === \"1\";\n } catch {\n return false;\n }\n}\n\n/** Respawn the dead pane in a session with a new command. */\nexport async function tmuxRespawnPane(\n name: string,\n command: string,\n args: string[],\n): Promise<void> {\n await execFileAsync(\"tmux\", [\"respawn-pane\", \"-t\", name, \"-k\", command, ...args]);\n}\n\n/** Attach the current terminal to an existing tmux session. */\nexport function tmuxAttach(name: string): void {\n spawnSync(\"tmux\", [\"attach-session\", \"-t\", name], { stdio: \"inherit\" });\n}\n\n/** Kill a tmux session by name. */\nexport async function tmuxKill(name: string): Promise<void> {\n await execFileAsync(\"tmux\", [\"kill-session\", \"-t\", name]);\n}\n\nexport interface TmuxSessionInfo {\n created: string;\n windows: number;\n}\n\n/** Get session info, or null if the session does not exist. */\nexport async function tmuxSessionInfo(name: string): Promise<TmuxSessionInfo | null> {\n try {\n const { stdout } = await execFileAsync(\"tmux\", [\n \"list-sessions\",\n \"-F\",\n \"#{session_created} #{session_windows}\",\n \"-f\",\n `#{==:#{session_name},${name}}`,\n ]);\n const line = stdout.trim();\n if (!line) return null;\n\n const [timestamp, windows] = line.split(\" \");\n const epoch = Number(timestamp);\n return {\n created: Number.isNaN(epoch) ? \"unknown\" : new Date(epoch * 1000).toISOString(),\n windows: Number(windows) || 1,\n };\n } catch {\n return null;\n }\n}\n"],"mappings":";;;;;;AAAA,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,SAAS,WAAW,YAAY,gBAAgB;AAChD,SAAS,YAAY,OAAO,UAAU,UAAU;AAChD,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP,SAAS,qBAAqB;;;ACf9B,SAAS,UAAU,iBAAiB;AACpC,SAAS,iBAAiB;AAE1B,IAAM,gBAAgB,UAAU,QAAQ;AAGxC,eAAsB,kBAAoC;AACxD,MAAI;AACF,UAAM,cAAc,QAAQ,CAAC,IAAI,CAAC;AAClC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAaA,eAAsB,kBAAkB,MAAgC;AACtE,MAAI;AACF,UAAM,cAAc,QAAQ,CAAC,eAAe,MAAM,IAAI,CAAC;AACvD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAIA,eAAsB,eACpB,MACA,SACA,MACA,KACe;AACf,QAAM,cAAc,QAAQ,CAAC,eAAe,MAAM,MAAM,MAAM,MAAM,KAAK,SAAS,GAAG,IAAI,CAAC;AAE1F,QAAM,cAAc,QAAQ,CAAC,cAAc,MAAM,MAAM,kBAAkB,IAAI,CAAC;AAChF;AAiCA,eAAsB,SAAS,MAA6B;AAC1D,QAAM,cAAc,QAAQ,CAAC,gBAAgB,MAAM,IAAI,CAAC;AAC1D;;;AD9DA,IAAM,eAAe;AAErB,eAAe,UAAU,MAAqD;AAC5E,QAAM,YAAY,uBAAuB,IAAI;AAC7C,MAAI,CAAC,WAAW,SAAS,EAAG,QAAO;AACnC,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,WAAW,OAAO;AAC7C,WAAO,4BAA4B,MAAM,KAAK,MAAM,GAAG,CAAC;AAAA,EAC1D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,eAAe,KAAsB;AAC5C,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,gBAAgB,MAAqD;AAClF,QAAM,QAAQ,MAAM,UAAU,IAAI;AAClC,MAAI,CAAC,SAAS,MAAM,WAAW,UAAW,QAAO;AACjD,MAAI,CAAC,eAAe,MAAM,GAAG,EAAG,QAAO;AACvC,SAAO;AACT;AAEA,eAAe,aAAa,MAA6B;AACvD,QAAM,QAAQ,MAAM,gBAAgB,IAAI;AACxC,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,uCAAuC,IAAI,IAAI;AAC3D;AAAA,EACF;AAEA,QAAM,SAAS,MAAM,iBAAiB;AACtC,eAAa,eAAe,IAAI,WAAW;AAC3C,UAAQ,IAAI,iBAAiB,MAAM,GAAG,EAAE;AACxC,UAAQ,IAAI,iBAAiB,MAAM,IAAI,EAAE;AACzC,UAAQ,IAAI,iBAAiB,MAAM,SAAS,EAAE;AAC9C,UAAQ,IAAI,iBAAiB,MAAM,SAAS,EAAE;AAC9C,UAAQ;AAAA,IACN,iBAAiB,OAAO,WAAW,iBAAiB,GAAI,iBAAiB,OAAO,WAAW,WAAW;AAAA,EACxG;AACA,UAAQ,IAAI,iBAAiB,MAAM,cAAc,EAAE;AACnD,MAAI,MAAM,eAAe;AACvB,YAAQ,IAAI,iBAAiB,MAAM,aAAa,EAAE;AAAA,EACpD;AACA,UAAQ,IAAI,kBAAkB,MAAM,cAAc,QAAQ,CAAC,KAAK,MAAM,EAAE;AACxE,UAAQ,IAAI,kBAAkB,MAAM,cAAc,QAAQ,CAAC,KAAK,MAAM,EAAE;AACxE,UAAQ,IAAI,iBAAiB,MAAM,MAAM,EAAE;AAC3C,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,8BAA8B,MAAM,IAAI,SAAS;AAC7D,UAAQ,IAAI,oCAAoC;AAChD,UAAQ,IAAI,kCAAkC;AAChD;AAEA,eAAe,WAAW,MAA6B;AACrD,QAAM,QAAQ,MAAM,gBAAgB,IAAI;AACxC,MAAI,CAAC,OAAO;AACV,eAAW,uCAAuC,IAAI,IAAI;AAG1D,UAAMA,YAAW,sBAAsB,IAAI;AAC3C,QAAI,WAAWA,SAAQ,GAAG;AACxB,YAAM,GAAGA,WAAU,EAAE,OAAO,KAAK,CAAC;AAAA,IACpC;AACA,YAAQ,WAAW;AACnB;AAAA,EACF;AAGA,QAAM,MAAM,MAAM;AAClB,MAAI;AACF,YAAQ,KAAK,KAAK,SAAS;AAC3B,iBAAa,+BAA+B,IAAI,UAAU,GAAG,GAAG;AAAA,EAClE,QAAQ;AACN,eAAW,gCAAgC,GAAG,gBAAgB;AAC9D,UAAMA,YAAW,sBAAsB,IAAI;AAC3C,UAAM,GAAGA,WAAU,EAAE,OAAO,KAAK,CAAC;AAClC;AAAA,EACF;AAGA,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,UAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAC3C,QAAI,CAAC,eAAe,GAAG,GAAG;AACxB,mBAAa,iBAAiB;AAC9B;AAAA,IACF;AAAA,EACF;AAGA,MAAI;AACF,YAAQ,KAAK,KAAK,SAAS;AAC3B,iBAAa,wDAAmD,GAAG,IAAI;AAAA,EACzE,QAAQ;AAAA,EAER;AAGA,QAAM,WAAW,sBAAsB,IAAI;AAC3C,QAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAGlC,QAAM,WAAW,OAAO,IAAI;AAC5B,QAAM,aAAa,MAAM,kBAAkB,QAAQ;AACnD,MAAI,YAAY;AACd,UAAM,SAAS,QAAQ;AAAA,EACzB;AACF;AAEA,eAAe,YAAY,MAAc,SAAiC;AACxE,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,MAAI,SAAS;AACX,eAAW,eAAe,IAAI,6BAA6B,QAAQ,GAAG,IAAI;AAC1E,eAAW,2CAA2C;AACtD,YAAQ,WAAW;AACnB;AAAA,EACF;AAGA,QAAM,WAAW,sBAAsB,IAAI;AAC3C,MAAI,WAAW,QAAQ,GAAG;AACxB,UAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC;AAAA,EACpC;AAGA,QAAM,YAAY,KAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAC7D,QAAM,aAAa,KAAK,KAAK,WAAW,UAAU,sBAAsB;AACxE,QAAM,cAAc,KAAK,QAAQ,WAAW,IAAI;AAEhD,MAAI,SAAS;AACX,UAAM,gBAAgB,MAAM,gBAAgB;AAC5C,QAAI,CAAC,eAAe;AAClB,iBAAW,4CAA4C;AACvD,iBAAW,sCAAsC;AACjD,cAAQ,WAAW;AACnB;AAAA,IACF;AAEA,UAAM,WAAW,OAAO,IAAI;AAC5B,UAAM,SAAS,MAAM,kBAAkB,QAAQ;AAC/C,QAAI,QAAQ;AACV,YAAM,SAAS,QAAQ;AAAA,IACzB;AAGA,UAAM,eAAe,UAAU,QAAQ,CAAC,YAAY,IAAI,GAAG,WAAW;AAEtE,UAAM,SAAS,MAAM,iBAAiB;AACtC,iBAAa,eAAe,IAAI,iCAAiC,IAAI,EAAE;AACvE,YAAQ,IAAI,eAAe,OAAO,WAAW,IAAI,EAAE;AACnD,YAAQ,IAAI,8BAA8B,OAAO,WAAW,IAAI,SAAS;AACzE,YAAQ,IAAI,sCAAsC,OAAO,WAAW,IAAI,kBAAkB;AAC1F,YAAQ,IAAI,eAAe,iBAAiB,IAAI,CAAC,aAAa;AAC9D,YAAQ,IAAI,oCAAoC;AAChD,YAAQ,IAAI,oCAAoC;AAChD,YAAQ,IAAI,kCAAkC;AAAA,EAChD,OAAO;AAEL,UAAM,SAAS,iBAAiB,IAAI;AACpC,UAAM,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;AACvC,UAAM,QAAQ,SAAS,KAAK,KAAK,QAAQ,YAAY,GAAG,GAAG;AAC3D,UAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,YAAY,IAAI,GAAG;AAAA,MACxD,UAAU;AAAA,MACV,OAAO,CAAC,UAAU,OAAO,KAAK;AAAA,MAC9B,KAAK;AAAA,IACP,CAAC;AACD,UAAM,MAAM;AACZ,cAAU,KAAK;AAEf,UAAM,SAAS,MAAM,iBAAiB;AACtC,iBAAa,eAAe,IAAI,kBAAkB,MAAM,GAAG,GAAG;AAC9D,YAAQ,IAAI,eAAe,OAAO,WAAW,IAAI,EAAE;AACnD,YAAQ,IAAI,8BAA8B,OAAO,WAAW,IAAI,SAAS;AACzE,YAAQ,IAAI,sCAAsC,OAAO,WAAW,IAAI,kBAAkB;AAC1F,YAAQ,IAAI,eAAe,iBAAiB,IAAI,CAAC,aAAa;AAC9D,YAAQ,IAAI,oCAAoC;AAChD,YAAQ,IAAI,kCAAkC;AAAA,EAChD;AACF;AAEA,eAAe,aAAa,MAA6B;AACvD,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,MAAI,CAAC,SAAS;AACZ,eAAW,uCAAuC,IAAI,IAAI;AAC1D,eAAW,2BAA2B;AACtC,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,mBAAiB;AAC9D,QAAM,oBAAoB,IAAI;AAChC;AAEA,eAAe,cAAc,MAAc,MAA6B;AACtE,QAAM,UAAU,MAAM,gBAAgB,IAAI;AAC1C,MAAI,CAAC,SAAS;AACZ,eAAW,uCAAuC,IAAI,IAAI;AAC1D,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,YAAY,uBAAuB,IAAI;AAC7C,QAAM,UAAU;AAAA,IACd,IAAI,WAAW;AAAA,IACf,MAAM;AAAA,IACN;AAAA,IACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EACpC;AAEA,QAAM,WAAW,WAAW,GAAG,KAAK,UAAU,OAAO,CAAC;AAAA,GAAM,OAAO;AACnE,eAAa,+BAA+B,IAAI,IAAI;AACtD;AAEA,IAAO,oBAAQ,cAAc;AAAA,EAC3B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,SAAS;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,IACf;AAAA,EACF;AAAA,EACA,MAAM,IAAI,EAAE,KAAK,GAAG;AAClB,UAAM,OAAO,KAAK;AAElB,QAAI,KAAK,QAAQ;AACf,YAAM,aAAa,IAAI;AACvB;AAAA,IACF;AAEA,QAAI,KAAK,MAAM;AACb,YAAM,WAAW,IAAI;AACrB;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ;AACf,YAAM,aAAa,IAAI;AACvB;AAAA,IACF;AAEA,QAAI,KAAK,SAAS;AAChB,YAAM,cAAc,MAAM,KAAK,OAAO;AACtC;AAAA,IACF;AAGA,UAAM,iBAAiB,MAAM,gBAAgB,IAAI;AACjD,QAAI,CAAC,gBAAgB;AACnB,YAAM,YAAY,MAAM,CAAC,KAAK,MAAM;AAEpC,YAAM,IAAI,QAAQ,CAAC,MAAM,WAAW,GAAG,GAAK,CAAC;AAAA,IAC/C;AAGA,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,EAAE,oBAAoB,IAAI,MAAM,OAAO,mBAAiB;AAC9D,YAAM,oBAAoB,IAAI;AAAA,IAChC;AAAA,EACF;AACF,CAAC;","names":["lockPath"]}
|