@neotx/cli 0.1.0-alpha.24 → 0.1.0-alpha.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/child-5X5IHAKS.js +92 -0
  2. package/dist/child-5X5IHAKS.js.map +1 -0
  3. package/dist/child-mode-IB3XSUHD.js +8 -0
  4. package/dist/child-mode-IB3XSUHD.js.map +1 -0
  5. package/dist/chunk-4TQ3Q6IE.js +43 -0
  6. package/dist/chunk-4TQ3Q6IE.js.map +1 -0
  7. package/dist/chunk-6PSXZ3UV.js +46 -0
  8. package/dist/chunk-6PSXZ3UV.js.map +1 -0
  9. package/dist/chunk-V5SN5F73.js +54 -0
  10. package/dist/chunk-V5SN5F73.js.map +1 -0
  11. package/dist/daemon/child-supervisor-worker.js +136 -0
  12. package/dist/daemon/child-supervisor-worker.js.map +1 -0
  13. package/dist/daemon/supervisor-worker.js +9 -1
  14. package/dist/daemon/supervisor-worker.js.map +1 -1
  15. package/dist/daemon/worker.js +16 -3
  16. package/dist/daemon/worker.js.map +1 -1
  17. package/dist/directive-7WM2Q2UW.js +259 -0
  18. package/dist/directive-7WM2Q2UW.js.map +1 -0
  19. package/dist/do-F5XW2ELZ.js +83 -0
  20. package/dist/do-F5XW2ELZ.js.map +1 -0
  21. package/dist/index.js +8 -5
  22. package/dist/index.js.map +1 -1
  23. package/dist/{log-PTHLI7ZN.js → log-ZLIAIBZQ.js} +64 -9
  24. package/dist/log-ZLIAIBZQ.js.map +1 -0
  25. package/dist/{memory-SDZ57W2S.js → memory-CW6E65SQ.js} +112 -62
  26. package/dist/memory-CW6E65SQ.js.map +1 -0
  27. package/dist/{run-MWHIQUSY.js → run-NV762V5B.js} +56 -22
  28. package/dist/run-NV762V5B.js.map +1 -0
  29. package/dist/{supervise-XMZRNODO.js → supervise-BWIKWNHH.js} +68 -41
  30. package/dist/supervise-BWIKWNHH.js.map +1 -0
  31. package/dist/{supervisor-3RUX5SPH.js → supervisor-N4D5EWCC.js} +1 -1
  32. package/dist/tui-LSW7VVK6.js +1319 -0
  33. package/dist/tui-LSW7VVK6.js.map +1 -0
  34. package/package.json +4 -4
  35. package/dist/log-PTHLI7ZN.js.map +0 -1
  36. package/dist/memory-SDZ57W2S.js.map +0 -1
  37. package/dist/run-MWHIQUSY.js.map +0 -1
  38. package/dist/supervise-XMZRNODO.js.map +0 -1
  39. package/dist/tui-67VJ5VBA.js +0 -842
  40. package/dist/tui-67VJ5VBA.js.map +0 -1
  41. /package/dist/{supervisor-3RUX5SPH.js.map → supervisor-N4D5EWCC.js.map} +0 -0
@@ -6,9 +6,15 @@ import {
6
6
 
7
7
  // src/commands/memory.ts
8
8
  import path from "path";
9
- import { getSupervisorDir, LocalEmbedder, MemoryStore } from "@neotx/core";
9
+ import { getSupervisorDir, MemoryStore } from "@neotx/core";
10
10
  import { defineCommand } from "citty";
11
- var VALID_TYPES = ["fact", "procedure", "episode", "focus", "feedback", "task"];
11
+ var VALID_TYPES = ["knowledge", "warning", "focus"];
12
+ var VALID_SUBTYPES = ["fact", "procedure"];
13
+ var LEGACY_TYPE_MAP = {
14
+ fact: { type: "knowledge", subtype: "fact" },
15
+ procedure: { type: "knowledge", subtype: "procedure" },
16
+ feedback: { type: "warning" }
17
+ };
12
18
  function parseDuration(input) {
13
19
  const match = input.match(/^(\d+)(h|m)$/);
14
20
  if (!match) return void 0;
@@ -20,25 +26,21 @@ function parseDuration(input) {
20
26
  function truncate(text, max) {
21
27
  return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
22
28
  }
23
- function createEmbedder() {
24
- try {
25
- return new LocalEmbedder();
26
- } catch (err) {
27
- console.debug(
28
- `[memory] Failed to create embedder: ${err instanceof Error ? err.message : String(err)}`
29
- );
30
- return null;
31
- }
32
- }
33
- function openStore(name, withEmbeddings = false) {
29
+ function openStore(name) {
34
30
  const dir = getSupervisorDir(name);
35
- const embedder = withEmbeddings ? createEmbedder() : null;
36
- return new MemoryStore(path.join(dir, "memory.sqlite"), embedder);
31
+ return new MemoryStore(path.join(dir, "memory.sqlite"));
37
32
  }
38
- function formatResultsTable(results) {
33
+ function formatResultsTable(results, full = false) {
34
+ const maxContent = full ? 500 : 60;
39
35
  printTable(
40
36
  ["ID", "TYPE", "SCOPE", "CONTENT", "ACCESSES"],
41
- results.map((m) => [m.id, m.type, m.scope, truncate(m.content, 60), String(m.accessCount)])
37
+ results.map((m) => [
38
+ m.id,
39
+ m.type,
40
+ m.scope,
41
+ truncate(m.content, maxContent),
42
+ String(m.accessCount)
43
+ ])
42
44
  );
43
45
  }
44
46
  async function handleWrite(args) {
@@ -47,9 +49,24 @@ async function handleWrite(args) {
47
49
  process.exitCode = 1;
48
50
  return;
49
51
  }
50
- const type = args.type ?? "fact";
51
- if (!VALID_TYPES.includes(type)) {
52
- printError(`Invalid type "${type}". Must be one of: ${VALID_TYPES.join(", ")}`);
52
+ const inputType = args.type ?? "knowledge";
53
+ const legacyMapping = LEGACY_TYPE_MAP[inputType];
54
+ let type;
55
+ let subtype;
56
+ if (legacyMapping) {
57
+ type = legacyMapping.type;
58
+ subtype = args.subtype ?? legacyMapping.subtype;
59
+ } else if (VALID_TYPES.includes(inputType)) {
60
+ type = inputType;
61
+ subtype = args.subtype ?? (type === "knowledge" ? "fact" : void 0);
62
+ } else {
63
+ const allValid = [...VALID_TYPES, ...Object.keys(LEGACY_TYPE_MAP)];
64
+ printError(`Invalid type "${inputType}". Must be one of: ${allValid.join(", ")}`);
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+ if (type === "knowledge" && subtype && !VALID_SUBTYPES.includes(subtype)) {
69
+ printError(`Invalid subtype "${subtype}". Must be one of: ${VALID_SUBTYPES.join(", ")}`);
53
70
  process.exitCode = 1;
54
71
  return;
55
72
  }
@@ -62,7 +79,7 @@ async function handleWrite(args) {
62
79
  return;
63
80
  }
64
81
  }
65
- const store = openStore(args.name, true);
82
+ const store = openStore(args.name);
66
83
  try {
67
84
  const tags = args.tags ? args.tags.split(",").map((t) => t.trim()) : [];
68
85
  const id = await store.write({
@@ -72,9 +89,8 @@ async function handleWrite(args) {
72
89
  source: args.source,
73
90
  tags,
74
91
  expiresAt,
75
- severity: args.severity,
76
- category: args.category,
77
- outcome: args.outcome
92
+ ...type === "knowledge" && subtype && { subtype },
93
+ ...type === "warning" && args.category && { category: args.category }
78
94
  });
79
95
  printSuccess(`Memory written: ${id}`);
80
96
  } finally {
@@ -95,10 +111,9 @@ function handleForget(args) {
95
111
  store.close();
96
112
  }
97
113
  }
98
- var VALID_OUTCOMES = ["pending", "in_progress", "done", "blocked", "abandoned"];
99
114
  function handleUpdate(args) {
100
115
  if (!args.value) {
101
- printError('Usage: neo memory update <id> ["new content"] [--outcome <status>]');
116
+ printError("Usage: neo memory update <id> <new content>");
102
117
  process.exitCode = 1;
103
118
  return;
104
119
  }
@@ -106,33 +121,21 @@ function handleUpdate(args) {
106
121
  const updateIdx = argv.indexOf("update");
107
122
  const idArg = argv[updateIdx + 1];
108
123
  const contentArg = argv[updateIdx + 2];
109
- if (args.outcome && !VALID_OUTCOMES.includes(args.outcome)) {
110
- printError(`Invalid outcome "${args.outcome}". Must be one of: ${VALID_OUTCOMES.join(", ")}`);
111
- process.exitCode = 1;
112
- return;
113
- }
114
124
  const isContentArgAFlag = contentArg?.startsWith("--");
115
125
  const hasContent = contentArg && !isContentArgAFlag;
116
- if (!hasContent && !args.outcome) {
117
- printError('Usage: neo memory update <id> ["new content"] [--outcome <status>]');
126
+ if (!hasContent) {
127
+ printError("Usage: neo memory update <id> <new content>");
118
128
  process.exitCode = 1;
119
129
  return;
120
130
  }
121
131
  if (!idArg) {
122
- printError('Usage: neo memory update <id> ["new content"] [--outcome <status>]');
132
+ printError("Usage: neo memory update <id> <new content>");
123
133
  process.exitCode = 1;
124
134
  return;
125
135
  }
126
136
  const store = openStore(args.name);
127
137
  try {
128
- if (args.outcome) {
129
- store.updateFields(idArg, {
130
- ...hasContent && { content: contentArg },
131
- outcome: args.outcome
132
- });
133
- } else {
134
- store.update(idArg, contentArg);
135
- }
138
+ store.update(idArg, contentArg);
136
139
  printSuccess(`Memory updated: ${idArg}`);
137
140
  } finally {
138
141
  store.close();
@@ -144,7 +147,7 @@ async function handleSearch(args) {
144
147
  process.exitCode = 1;
145
148
  return;
146
149
  }
147
- const store = openStore(args.name, true);
150
+ const store = openStore(args.name);
148
151
  try {
149
152
  const results = await store.search(args.value, {
150
153
  ...args.scope !== "global" && { scope: args.scope },
@@ -154,7 +157,18 @@ async function handleSearch(args) {
154
157
  console.log("No memories found.");
155
158
  return;
156
159
  }
157
- formatResultsTable(results);
160
+ const maxContent = args.full ? 500 : 60;
161
+ printTable(
162
+ ["ID", "TYPE", "SCOPE", "SCORE", "CONTENT", "ACCESSES"],
163
+ results.map((m) => [
164
+ m.id,
165
+ m.type,
166
+ m.scope,
167
+ `${(m.score * 100).toFixed(0)}%`,
168
+ truncate(m.content, maxContent),
169
+ String(m.accessCount)
170
+ ])
171
+ );
158
172
  } finally {
159
173
  store.close();
160
174
  }
@@ -170,7 +184,26 @@ function handleList(args) {
170
184
  console.log("No memories found.");
171
185
  return;
172
186
  }
173
- formatResultsTable(results);
187
+ formatResultsTable(results, args.full);
188
+ } finally {
189
+ store.close();
190
+ }
191
+ }
192
+ function handleRecent(args) {
193
+ const limit = args.limit ? Number(args.limit) : 10;
194
+ const store = openStore(args.name);
195
+ try {
196
+ const results = store.query({
197
+ ...args.scope !== "global" && { scope: args.scope },
198
+ ...args.type && { types: [args.type] },
199
+ sortBy: "createdAt",
200
+ limit
201
+ });
202
+ if (results.length === 0) {
203
+ console.log("No memories found.");
204
+ return;
205
+ }
206
+ formatResultsTable(results, args.full);
174
207
  } finally {
175
208
  store.close();
176
209
  }
@@ -193,6 +226,15 @@ function handleStats(args) {
193
226
  ["SCOPE", "COUNT"],
194
227
  Object.entries(s.byScope).map(([sc, c]) => [sc, String(c)])
195
228
  );
229
+ console.log();
230
+ }
231
+ const topAccessed = store.topAccessed(5);
232
+ if (topAccessed.length > 0) {
233
+ console.log("Top 5 most-accessed memories:\n");
234
+ printTable(
235
+ ["ID", "TYPE", "ACCESSES", "CONTENT"],
236
+ topAccessed.map((m) => [m.id, m.type, String(m.accessCount), truncate(m.content, 50)])
237
+ );
196
238
  }
197
239
  } finally {
198
240
  store.close();
@@ -206,7 +248,7 @@ var memory_default = defineCommand({
206
248
  args: {
207
249
  action: {
208
250
  type: "positional",
209
- description: "Action: write, forget, update, search, list, stats",
251
+ description: "Action: write, forget, update, search, list, stats, recent",
210
252
  required: true
211
253
  },
212
254
  value: {
@@ -216,7 +258,11 @@ var memory_default = defineCommand({
216
258
  },
217
259
  type: {
218
260
  type: "string",
219
- description: "Memory type: fact, procedure, episode, focus, feedback, task"
261
+ description: "Memory type: knowledge, warning, focus"
262
+ },
263
+ subtype: {
264
+ type: "string",
265
+ description: "Knowledge subtype: fact, procedure (only for knowledge type)"
220
266
  },
221
267
  scope: {
222
268
  type: "string",
@@ -232,26 +278,27 @@ var memory_default = defineCommand({
232
278
  type: "string",
233
279
  description: "TTL for focus entries (e.g. 2h, 30m)"
234
280
  },
235
- outcome: {
236
- type: "string",
237
- description: "Task outcome: pending, in_progress, done, blocked, abandoned"
238
- },
239
- severity: {
240
- type: "string",
241
- description: "Priority: critical, high, medium, low"
242
- },
243
281
  category: {
244
282
  type: "string",
245
- description: "Context reference (e.g. 'neo runs abc123' or 'cat notes/plan.md')"
283
+ description: "Warning category (e.g. input_validation, testing)"
246
284
  },
247
285
  tags: {
248
286
  type: "string",
249
- description: "Comma-separated tags (e.g. 'initiative:auth,depends:mem_abc')"
287
+ description: "Comma-separated tags"
250
288
  },
251
289
  name: {
252
290
  type: "string",
253
291
  description: "Supervisor name",
254
292
  default: "supervisor"
293
+ },
294
+ full: {
295
+ type: "boolean",
296
+ description: "Show full content without truncation",
297
+ default: false
298
+ },
299
+ limit: {
300
+ type: "string",
301
+ description: "Limit number of results (for recent command)"
255
302
  }
256
303
  },
257
304
  async run({ args }) {
@@ -259,14 +306,15 @@ var memory_default = defineCommand({
259
306
  const parsed = {
260
307
  value: args.value,
261
308
  type: args.type,
309
+ subtype: args.subtype,
262
310
  scope: args.scope,
263
311
  source: args.source,
264
312
  expires: args.expires,
265
313
  name: args.name,
266
- outcome: args.outcome,
267
- severity: args.severity,
268
314
  category: args.category,
269
- tags: args.tags
315
+ tags: args.tags,
316
+ full: args.full,
317
+ limit: args.limit
270
318
  };
271
319
  switch (action) {
272
320
  case "write":
@@ -281,9 +329,11 @@ var memory_default = defineCommand({
281
329
  return handleList(parsed);
282
330
  case "stats":
283
331
  return handleStats(parsed);
332
+ case "recent":
333
+ return handleRecent(parsed);
284
334
  default:
285
335
  printError(
286
- `Unknown action "${action}". Must be one of: write, forget, update, search, list, stats`
336
+ `Unknown action "${action}". Must be one of: write, forget, update, search, list, stats, recent`
287
337
  );
288
338
  process.exitCode = 1;
289
339
  }
@@ -292,4 +342,4 @@ var memory_default = defineCommand({
292
342
  export {
293
343
  memory_default as default
294
344
  };
295
- //# sourceMappingURL=memory-SDZ57W2S.js.map
345
+ //# sourceMappingURL=memory-CW6E65SQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/memory.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { KnowledgeSubtype, MemoryEntry, MemoryType } from \"@neotx/core\";\nimport { getSupervisorDir, MemoryStore } from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printSuccess, printTable } from \"../output.js\";\n\nconst VALID_TYPES = [\"knowledge\", \"warning\", \"focus\"] as const;\nconst VALID_SUBTYPES = [\"fact\", \"procedure\"] as const;\n\n// Legacy type aliases for backward compatibility\n// Agents/docs may use: --type fact, --type procedure, --type feedback\nconst LEGACY_TYPE_MAP: Record<string, { type: MemoryType; subtype?: KnowledgeSubtype }> = {\n fact: { type: \"knowledge\", subtype: \"fact\" },\n procedure: { type: \"knowledge\", subtype: \"procedure\" },\n feedback: { type: \"warning\" },\n};\n\ninterface ParsedArgs {\n value: string | undefined;\n type: string | undefined;\n subtype: string | undefined;\n scope: string;\n source: string;\n expires: string | undefined;\n name: string;\n category: string | undefined;\n tags: string | undefined;\n full: boolean;\n limit: string | undefined;\n}\n\nfunction parseDuration(input: string): string | undefined {\n const match = input.match(/^(\\d+)(h|m)$/);\n if (!match) return undefined;\n\n const value = Number(match[1]);\n const unit = match[2];\n const ms = unit === \"h\" ? value * 60 * 60 * 1000 : value * 60 * 1000;\n return new Date(Date.now() + ms).toISOString();\n}\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\nfunction openStore(name: string): MemoryStore {\n const dir = getSupervisorDir(name);\n return new MemoryStore(path.join(dir, \"memory.sqlite\"));\n}\n\nfunction formatResultsTable(results: MemoryEntry[], full = false): void {\n const maxContent = full ? 500 : 60;\n printTable(\n [\"ID\", \"TYPE\", \"SCOPE\", \"CONTENT\", \"ACCESSES\"],\n results.map((m) => [\n m.id,\n m.type,\n m.scope,\n truncate(m.content, maxContent),\n String(m.accessCount),\n ]),\n );\n}\n\nasync function handleWrite(args: ParsedArgs): Promise<void> {\n if (!args.value) {\n printError(\"Usage: neo memory write <content> --type <type> [--scope <scope>]\");\n process.exitCode = 1;\n return;\n }\n\n const inputType = args.type ?? \"knowledge\";\n\n // Map legacy types (fact, procedure, feedback) to new schema\n const legacyMapping = LEGACY_TYPE_MAP[inputType];\n let type: MemoryType;\n let subtype: KnowledgeSubtype | undefined;\n\n if (legacyMapping) {\n type = legacyMapping.type;\n subtype = (args.subtype as KnowledgeSubtype | undefined) ?? legacyMapping.subtype;\n } else if (VALID_TYPES.includes(inputType as MemoryType)) {\n type = inputType as MemoryType;\n subtype =\n (args.subtype as KnowledgeSubtype | undefined) ?? (type === \"knowledge\" ? \"fact\" : undefined);\n } else {\n const allValid = [...VALID_TYPES, ...Object.keys(LEGACY_TYPE_MAP)];\n printError(`Invalid type \"${inputType}\". Must be one of: ${allValid.join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n // Validate subtype for knowledge type\n if (type === \"knowledge\" && subtype && !VALID_SUBTYPES.includes(subtype)) {\n printError(`Invalid subtype \"${subtype}\". Must be one of: ${VALID_SUBTYPES.join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n let expiresAt: string | undefined;\n if (args.expires) {\n expiresAt = parseDuration(args.expires);\n if (!expiresAt) {\n printError('Invalid --expires format. Use e.g. \"2h\" or \"30m\".');\n process.exitCode = 1;\n return;\n }\n }\n\n const store = openStore(args.name);\n try {\n const tags = args.tags ? args.tags.split(\",\").map((t) => t.trim()) : [];\n const id = await store.write({\n type: type as MemoryType,\n scope: args.scope,\n content: args.value,\n source: args.source,\n tags,\n expiresAt,\n ...(type === \"knowledge\" && subtype && { subtype: subtype as KnowledgeSubtype }),\n ...(type === \"warning\" && args.category && { category: args.category }),\n });\n printSuccess(`Memory written: ${id}`);\n } finally {\n store.close();\n }\n}\n\nfunction handleForget(args: ParsedArgs): void {\n if (!args.value) {\n printError(\"Usage: neo memory forget <id>\");\n process.exitCode = 1;\n return;\n }\n\n const store = openStore(args.name);\n try {\n store.forget(args.value);\n printSuccess(`Memory forgotten: ${args.value}`);\n } finally {\n store.close();\n }\n}\n\nfunction handleUpdate(args: ParsedArgs): void {\n if (!args.value) {\n printError(\"Usage: neo memory update <id> <new content>\");\n process.exitCode = 1;\n return;\n }\n\n // The ID is in value, but we need content too.\n // citty only supports 2 positional args — content comes after ID.\n const argv = process.argv;\n const updateIdx = argv.indexOf(\"update\");\n const idArg = argv[updateIdx + 1];\n const contentArg = argv[updateIdx + 2];\n\n // Determine if contentArg is actually content or a flag\n const isContentArgAFlag = contentArg?.startsWith(\"--\");\n const hasContent = contentArg && !isContentArgAFlag;\n\n // Need content\n if (!hasContent) {\n printError(\"Usage: neo memory update <id> <new content>\");\n process.exitCode = 1;\n return;\n }\n\n // ID is required at this point — validated by args.value check above\n if (!idArg) {\n printError(\"Usage: neo memory update <id> <new content>\");\n process.exitCode = 1;\n return;\n }\n\n const store = openStore(args.name);\n try {\n store.update(idArg, contentArg as string);\n printSuccess(`Memory updated: ${idArg}`);\n } finally {\n store.close();\n }\n}\n\nasync function handleSearch(args: ParsedArgs): Promise<void> {\n if (!args.value) {\n printError(\"Usage: neo memory search <query>\");\n process.exitCode = 1;\n return;\n }\n\n const store = openStore(args.name);\n try {\n const results = await store.search(args.value, {\n ...(args.scope !== \"global\" && { scope: args.scope }),\n ...(args.type && { types: [args.type as MemoryType] }),\n });\n\n if (results.length === 0) {\n console.log(\"No memories found.\");\n return;\n }\n\n // Display with relevance score\n const maxContent = args.full ? 500 : 60;\n printTable(\n [\"ID\", \"TYPE\", \"SCOPE\", \"SCORE\", \"CONTENT\", \"ACCESSES\"],\n results.map((m) => [\n m.id,\n m.type,\n m.scope,\n `${(m.score * 100).toFixed(0)}%`,\n truncate(m.content, maxContent),\n String(m.accessCount),\n ]),\n );\n } finally {\n store.close();\n }\n}\n\nfunction handleList(args: ParsedArgs): void {\n const store = openStore(args.name);\n try {\n const results = store.query({\n ...(args.scope !== \"global\" && { scope: args.scope }),\n ...(args.type && { types: [args.type as MemoryType] }),\n });\n\n if (results.length === 0) {\n console.log(\"No memories found.\");\n return;\n }\n\n formatResultsTable(results, args.full);\n } finally {\n store.close();\n }\n}\n\nfunction handleRecent(args: ParsedArgs): void {\n const limit = args.limit ? Number(args.limit) : 10;\n\n const store = openStore(args.name);\n try {\n const results = store.query({\n ...(args.scope !== \"global\" && { scope: args.scope }),\n ...(args.type && { types: [args.type as MemoryType] }),\n sortBy: \"createdAt\",\n limit,\n });\n\n if (results.length === 0) {\n console.log(\"No memories found.\");\n return;\n }\n\n formatResultsTable(results, args.full);\n } finally {\n store.close();\n }\n}\n\nfunction handleStats(args: ParsedArgs): void {\n const store = openStore(args.name);\n try {\n const s = store.stats();\n console.log(`Total memories: ${s.total}\\n`);\n\n if (Object.keys(s.byType).length > 0) {\n printTable(\n [\"TYPE\", \"COUNT\"],\n Object.entries(s.byType).map(([t, c]) => [t, String(c)]),\n );\n console.log();\n }\n\n if (Object.keys(s.byScope).length > 0) {\n printTable(\n [\"SCOPE\", \"COUNT\"],\n Object.entries(s.byScope).map(([sc, c]) => [sc, String(c)]),\n );\n console.log();\n }\n\n // Show top 5 most-accessed memories\n const topAccessed = store.topAccessed(5);\n if (topAccessed.length > 0) {\n console.log(\"Top 5 most-accessed memories:\\n\");\n printTable(\n [\"ID\", \"TYPE\", \"ACCESSES\", \"CONTENT\"],\n topAccessed.map((m) => [m.id, m.type, String(m.accessCount), truncate(m.content, 50)]),\n );\n }\n } finally {\n store.close();\n }\n}\n\nexport default defineCommand({\n meta: {\n name: \"memory\",\n description: \"Manage the supervisor memory store\",\n },\n args: {\n action: {\n type: \"positional\",\n description: \"Action: write, forget, update, search, list, stats, recent\",\n required: true,\n },\n value: {\n type: \"positional\",\n description: \"Content or ID depending on action\",\n required: false,\n },\n type: {\n type: \"string\",\n description: \"Memory type: knowledge, warning, focus\",\n },\n subtype: {\n type: \"string\",\n description: \"Knowledge subtype: fact, procedure (only for knowledge type)\",\n },\n scope: {\n type: \"string\",\n description: \"Scope: global or repo path\",\n default: \"global\",\n },\n source: {\n type: \"string\",\n description: \"Source: developer, reviewer, supervisor, user\",\n default: \"user\",\n },\n expires: {\n type: \"string\",\n description: \"TTL for focus entries (e.g. 2h, 30m)\",\n },\n category: {\n type: \"string\",\n description: \"Warning category (e.g. input_validation, testing)\",\n },\n tags: {\n type: \"string\",\n description: \"Comma-separated tags\",\n },\n name: {\n type: \"string\",\n description: \"Supervisor name\",\n default: \"supervisor\",\n },\n full: {\n type: \"boolean\",\n description: \"Show full content without truncation\",\n default: false,\n },\n limit: {\n type: \"string\",\n description: \"Limit number of results (for recent command)\",\n },\n },\n async run({ args }) {\n const action = args.action as string;\n const parsed: ParsedArgs = {\n value: args.value as string | undefined,\n type: args.type as string | undefined,\n subtype: args.subtype as string | undefined,\n scope: args.scope as string,\n source: args.source as string,\n expires: args.expires as string | undefined,\n name: args.name as string,\n category: args.category as string | undefined,\n tags: args.tags as string | undefined,\n full: args.full as boolean,\n limit: args.limit as string | undefined,\n };\n\n switch (action) {\n case \"write\":\n return handleWrite(parsed);\n case \"forget\":\n return handleForget(parsed);\n case \"update\":\n return handleUpdate(parsed);\n case \"search\":\n return handleSearch(parsed);\n case \"list\":\n return handleList(parsed);\n case \"stats\":\n return handleStats(parsed);\n case \"recent\":\n return handleRecent(parsed);\n default:\n printError(\n `Unknown action \"${action}\". Must be one of: write, forget, update, search, list, stats, recent`,\n );\n process.exitCode = 1;\n }\n },\n});\n"],"mappings":"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","names":[]}
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  resolveAgentsDir
3
3
  } from "./chunk-F622JUDY.js";
4
+ import {
5
+ spawnWithConfirmation
6
+ } from "./chunk-6PSXZ3UV.js";
4
7
  import {
5
8
  printError,
6
9
  printJson,
@@ -8,7 +11,6 @@ import {
8
11
  } from "./chunk-YQIWMDXL.js";
9
12
 
10
13
  // src/commands/run.ts
11
- import { spawn } from "child_process";
12
14
  import { randomUUID } from "crypto";
13
15
  import { existsSync } from "fs";
14
16
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -18,6 +20,7 @@ import {
18
20
  AgentRegistry,
19
21
  getRepoRunsDir,
20
22
  getRunDispatchPath,
23
+ getWorkerStartedPath,
21
24
  loadGlobalConfig,
22
25
  Orchestrator,
23
26
  toRepoSlug
@@ -72,6 +75,18 @@ function printResult(result, agentName) {
72
75
  console.log(typeof output === "string" ? output : JSON.stringify(output, null, 2));
73
76
  }
74
77
  }
78
+ var WORKER_STARTUP_TIMEOUT_MS = 5e3;
79
+ var WORKER_STARTUP_POLL_MS = 100;
80
+ async function waitForWorkerStartup(startedPath, timeoutMs) {
81
+ const deadline = Date.now() + timeoutMs;
82
+ while (Date.now() < deadline) {
83
+ if (existsSync(startedPath)) {
84
+ return true;
85
+ }
86
+ await new Promise((resolve) => setTimeout(resolve, WORKER_STARTUP_POLL_MS));
87
+ }
88
+ return false;
89
+ }
75
90
  async function runDetached(params) {
76
91
  const runId = randomUUID();
77
92
  const repoSlug = toRepoSlug({ path: params.repo });
@@ -89,11 +104,8 @@ async function runDetached(params) {
89
104
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
90
105
  metadata: params.metadata
91
106
  };
92
- await writeFile(
93
- path.join(runsDir, `${runId}.json`),
94
- JSON.stringify(persistedRun, null, 2),
95
- "utf-8"
96
- );
107
+ const runFilePath = path.join(runsDir, `${runId}.json`);
108
+ await writeFile(runFilePath, JSON.stringify(persistedRun, null, 2), "utf-8");
97
109
  const dispatchPath = getRunDispatchPath(repoSlug, runId);
98
110
  await writeFile(
99
111
  dispatchPath,
@@ -110,30 +122,52 @@ async function runDetached(params) {
110
122
  "utf-8"
111
123
  );
112
124
  const workerPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "daemon", "worker.js");
113
- const child = spawn(process.execPath, [workerPath, runId, repoSlug], {
114
- detached: true,
115
- stdio: "ignore",
116
- env: process.env
117
- });
118
- child.unref();
119
- if (child.pid) {
120
- const runFilePath = path.join(runsDir, `${runId}.json`);
125
+ const spawnResult = await spawnWithConfirmation(process.execPath, [workerPath, runId, repoSlug]);
126
+ if ("error" in spawnResult) {
127
+ try {
128
+ const raw = await readFile(runFilePath, "utf-8");
129
+ const run = JSON.parse(raw);
130
+ run.status = "failed";
131
+ run.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
132
+ await writeFile(runFilePath, JSON.stringify(run, null, 2), "utf-8");
133
+ } catch {
134
+ }
135
+ printError(`Failed to spawn worker: ${spawnResult.error}`);
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+ const startedPath = getWorkerStartedPath(repoSlug, runId);
140
+ const workerStarted = await waitForWorkerStartup(startedPath, WORKER_STARTUP_TIMEOUT_MS);
141
+ if (!workerStarted) {
121
142
  try {
122
143
  const raw = await readFile(runFilePath, "utf-8");
123
144
  const run = JSON.parse(raw);
124
- run.pid = child.pid;
145
+ run.status = "failed";
146
+ run.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
125
147
  await writeFile(runFilePath, JSON.stringify(run, null, 2), "utf-8");
126
- } catch (err) {
127
- console.debug(
128
- `[run] Failed to update run file with PID: ${err instanceof Error ? err.message : String(err)}`
129
- );
148
+ } catch {
130
149
  }
150
+ printError(
151
+ `Worker failed to start within ${WORKER_STARTUP_TIMEOUT_MS / 1e3}s. The process may have crashed before initialization.`
152
+ );
153
+ process.exitCode = 1;
154
+ return;
155
+ }
156
+ try {
157
+ const raw = await readFile(runFilePath, "utf-8");
158
+ const run = JSON.parse(raw);
159
+ run.pid = spawnResult.pid;
160
+ await writeFile(runFilePath, JSON.stringify(run, null, 2), "utf-8");
161
+ } catch (err) {
162
+ console.debug(
163
+ `[run] Failed to update run file with PID: ${err instanceof Error ? err.message : String(err)}`
164
+ );
131
165
  }
132
166
  if (params.jsonOutput) {
133
- printJson({ runId, status: "detached", pid: child.pid });
167
+ printJson({ runId, status: "detached", pid: spawnResult.pid });
134
168
  } else {
135
169
  printSuccess(`Detached run started: ${runId}`);
136
- console.log(` PID: ${String(child.pid)}`);
170
+ console.log(` PID: ${String(spawnResult.pid)}`);
137
171
  console.log(` Logs: neo logs -f ${runId}`);
138
172
  }
139
173
  }
@@ -259,4 +293,4 @@ var run_default = defineCommand({
259
293
  export {
260
294
  run_default as default
261
295
  };
262
- //# sourceMappingURL=run-MWHIQUSY.js.map
296
+ //# sourceMappingURL=run-NV762V5B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/run.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NeoEvent, PersistedRun } from \"@neotx/core\";\nimport {\n AgentRegistry,\n getRepoRunsDir,\n getRunDispatchPath,\n getWorkerStartedPath,\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\";\nimport { spawnWithConfirmation } from \"../spawn-utils.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 (err) {\n // Expected error: invalid JSON provided by user\n throw new Error(\n `Invalid --meta JSON: ${meta}. Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n}\n\nfunction printResult(result: import(\"@neotx/core\").TaskResult, agentName: string): void {\n console.log(\"\");\n console.log(`Run: ${result.runId}`);\n console.log(`Agent: ${agentName}`);\n console.log(`Status: ${result.status}`);\n console.log(`Cost: $${result.costUsd.toFixed(4)}`);\n console.log(`Duration: ${(result.durationMs / 1000).toFixed(1)}s`);\n if (result.branch) {\n console.log(`Branch: ${result.branch}`);\n }\n if (result.prUrl) {\n console.log(`PR: ${result.prUrl}`);\n }\n\n const stepResult = Object.values(result.steps)[0];\n const output = stepResult?.output ?? result.summary;\n if (output) {\n console.log(\"\");\n console.log(typeof output === \"string\" ? output : JSON.stringify(output, null, 2));\n }\n}\n\ninterface DetachParams {\n agentName: string;\n repo: string;\n prompt: string;\n branch: string | undefined;\n priority: string;\n metadata: Record<string, unknown> | undefined;\n bundledAgentsDir: string;\n customAgentsDir: string | undefined;\n jsonOutput: boolean;\n}\n\n/**\n * Time in milliseconds to wait for worker startup confirmation.\n * The worker writes a .started file immediately after spawning.\n * If this file doesn't appear within the timeout, the worker likely crashed.\n */\nconst WORKER_STARTUP_TIMEOUT_MS = 5000;\n\n/**\n * Polling interval for checking if the worker has started.\n */\nconst WORKER_STARTUP_POLL_MS = 100;\n\n/**\n * Wait for the worker to write its startup confirmation file.\n * Returns true if the worker started successfully, false if it timed out.\n */\nasync function waitForWorkerStartup(startedPath: string, timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (existsSync(startedPath)) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, WORKER_STARTUP_POLL_MS));\n }\n return false;\n}\n\nasync function runDetached(params: DetachParams): Promise<void> {\n const runId = randomUUID();\n const repoSlug = toRepoSlug({ path: params.repo });\n const runsDir = getRepoRunsDir(repoSlug);\n await mkdir(runsDir, { recursive: true });\n\n const persistedRun: PersistedRun = {\n version: 1,\n runId,\n agent: params.agentName,\n repo: params.repo,\n prompt: params.prompt,\n status: \"running\",\n steps: {},\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n metadata: params.metadata,\n };\n const runFilePath = path.join(runsDir, `${runId}.json`);\n await writeFile(runFilePath, JSON.stringify(persistedRun, null, 2), \"utf-8\");\n\n const dispatchPath = getRunDispatchPath(repoSlug, runId);\n await writeFile(\n dispatchPath,\n JSON.stringify({\n agentName: params.agentName,\n repo: params.repo,\n prompt: params.prompt,\n branch: params.branch,\n priority: params.priority,\n metadata: params.metadata,\n bundledAgentsDir: params.bundledAgentsDir,\n customAgentsDir: params.customAgentsDir,\n }),\n \"utf-8\",\n );\n\n const workerPath = path.join(path.dirname(fileURLToPath(import.meta.url)), \"daemon\", \"worker.js\");\n\n // Wait for spawn confirmation before persisting PID\n // This prevents ghost runs where spawn fails silently\n const spawnResult = await spawnWithConfirmation(process.execPath, [workerPath, runId, repoSlug]);\n\n if (\"error\" in spawnResult) {\n // Mark run as failed if spawn failed\n try {\n const raw = await readFile(runFilePath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n run.status = \"failed\";\n run.updatedAt = new Date().toISOString();\n await writeFile(runFilePath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch {\n // Best effort - run file update failed\n }\n\n printError(`Failed to spawn worker: ${spawnResult.error}`);\n process.exitCode = 1;\n return;\n }\n\n // Wait for worker to confirm startup by writing .started file\n // This catches early crashes between spawn() and actual worker initialization\n const startedPath = getWorkerStartedPath(repoSlug, runId);\n const workerStarted = await waitForWorkerStartup(startedPath, WORKER_STARTUP_TIMEOUT_MS);\n\n if (!workerStarted) {\n // Worker failed to start - mark run as failed\n try {\n const raw = await readFile(runFilePath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n run.status = \"failed\";\n run.updatedAt = new Date().toISOString();\n await writeFile(runFilePath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch {\n // Best effort - run file update failed\n }\n\n printError(\n `Worker failed to start within ${WORKER_STARTUP_TIMEOUT_MS / 1000}s. The process may have crashed before initialization.`,\n );\n process.exitCode = 1;\n return;\n }\n\n // Write PID to persisted run AFTER spawn confirmation\n // This ensures PID in run.json corresponds to an actually running process\n try {\n const raw = await readFile(runFilePath, \"utf-8\");\n const run = JSON.parse(raw) as PersistedRun;\n run.pid = spawnResult.pid;\n await writeFile(runFilePath, JSON.stringify(run, null, 2), \"utf-8\");\n } catch (err) {\n // Non-critical — worker will write PID on startup anyway\n console.debug(\n `[run] Failed to update run file with PID: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n\n if (params.jsonOutput) {\n printJson({ runId, status: \"detached\", pid: spawnResult.pid });\n } else {\n printSuccess(`Detached run started: ${runId}`);\n console.log(` PID: ${String(spawnResult.pid)}`);\n console.log(` Logs: neo logs -f ${runId}`);\n }\n}\n\nexport default defineCommand({\n meta: {\n name: \"run\",\n description: \"Dispatch an agent to execute a task in an isolated clone\",\n },\n args: {\n agent: {\n type: \"positional\",\n description: \"Agent name to run (e.g. developer, architect, reviewer-quality)\",\n required: true,\n },\n repo: {\n type: \"string\",\n description: \"Target repository path\",\n default: \".\",\n },\n prompt: {\n type: \"string\",\n description: \"Task description for the agent\",\n required: true,\n },\n branch: {\n type: \"string\",\n description: \"Branch name for the session clone (required for writable agents)\",\n },\n priority: {\n type: \"string\",\n description: \"Priority level: critical, high, medium, low\",\n },\n meta: {\n type: \"string\",\n description: \"Metadata as JSON string (for traceability: ticketId, stage, etc.)\",\n },\n output: {\n type: \"string\",\n description: \"Output format: json\",\n },\n detach: {\n type: \"boolean\",\n alias: \"d\",\n description: \"Run in background and return immediately with the run ID\",\n default: true,\n },\n sync: {\n type: \"boolean\",\n alias: \"s\",\n description: \"Run in foreground (blocking) instead of detached\",\n default: false,\n },\n \"git-strategy\": {\n type: \"string\",\n description: \"Git strategy: pr (create PR), branch (push only, default)\",\n },\n },\n async run({ args }) {\n const jsonOutput = args.output === \"json\";\n\n // Zero-config: only need global config (auto-creates ~/.neo/config.yml if absent)\n const config = await loadGlobalConfig();\n const repo = path.resolve(args.repo);\n\n // Load agent registry (bundled + project-local agents)\n const bundledAgentsDir = resolveAgentsDir();\n const customAgentsDir = path.resolve(\".neo/agents\");\n const agentRegistry = new AgentRegistry(\n bundledAgentsDir,\n existsSync(customAgentsDir) ? customAgentsDir : undefined,\n );\n await agentRegistry.load();\n\n // Validate agent exists\n const agent = agentRegistry.get(args.agent);\n if (!agent) {\n const available = agentRegistry\n .list()\n .map((a) => a.name)\n .join(\", \");\n printError(`Agent \"${args.agent}\" not found. Available: ${available}`);\n process.exitCode = 1;\n return;\n }\n\n if (args.detach && !args.sync) {\n await runDetached({\n agentName: args.agent,\n repo,\n prompt: args.prompt,\n branch: args.branch,\n priority: args.priority ?? \"medium\",\n metadata: parseMetadata(args.meta),\n bundledAgentsDir,\n customAgentsDir: existsSync(customAgentsDir) ? customAgentsDir : undefined,\n jsonOutput,\n });\n return;\n }\n\n // ─── Foreground mode (default) ──────────────────────\n const orchestrator = new Orchestrator(config, { skipOrphanRecovery: true });\n orchestrator.registerAgent(agent);\n\n if (!jsonOutput) {\n orchestrator.on(\"*\", printProgress);\n }\n\n try {\n await orchestrator.start();\n\n const gitStrategy = args[\"git-strategy\"] as \"pr\" | \"branch\" | undefined;\n const result = await orchestrator.dispatch({\n agent: args.agent,\n repo,\n prompt: args.prompt,\n ...(args.branch ? { branch: args.branch } : {}),\n priority: (args.priority as \"critical\" | \"high\" | \"medium\" | \"low\") ?? \"medium\",\n metadata: parseMetadata(args.meta),\n ...(gitStrategy ? { gitStrategy } : {}),\n });\n\n if (jsonOutput) {\n printJson(result);\n } else {\n printResult(result, args.agent);\n }\n\n await orchestrator.shutdown();\n if (result.status !== \"success\") {\n process.exitCode = 1;\n }\n } catch (error) {\n await orchestrator.shutdown();\n printError(error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n },\n});\n"],"mappings":"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","names":[]}