@neotx/cli 0.1.0-alpha.22 → 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 (46) 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/{decision-PNZ2S2TU.js → decision-T2526ITK.js} +35 -2
  18. package/dist/decision-T2526ITK.js.map +1 -0
  19. package/dist/directive-7WM2Q2UW.js +259 -0
  20. package/dist/directive-7WM2Q2UW.js.map +1 -0
  21. package/dist/do-F5XW2ELZ.js +83 -0
  22. package/dist/do-F5XW2ELZ.js.map +1 -0
  23. package/dist/health-SWQ6V4H5.js +72 -0
  24. package/dist/health-SWQ6V4H5.js.map +1 -0
  25. package/dist/index.js +10 -6
  26. package/dist/index.js.map +1 -1
  27. package/dist/{log-PTHLI7ZN.js → log-ZLIAIBZQ.js} +64 -9
  28. package/dist/log-ZLIAIBZQ.js.map +1 -0
  29. package/dist/{memory-SDZ57W2S.js → memory-CW6E65SQ.js} +112 -62
  30. package/dist/memory-CW6E65SQ.js.map +1 -0
  31. package/dist/{run-MWHIQUSY.js → run-NV762V5B.js} +56 -22
  32. package/dist/run-NV762V5B.js.map +1 -0
  33. package/dist/{supervise-XMZRNODO.js → supervise-BWIKWNHH.js} +68 -41
  34. package/dist/supervise-BWIKWNHH.js.map +1 -0
  35. package/dist/{supervisor-3RUX5SPH.js → supervisor-N4D5EWCC.js} +1 -1
  36. package/dist/tui-LSW7VVK6.js +1319 -0
  37. package/dist/tui-LSW7VVK6.js.map +1 -0
  38. package/package.json +4 -4
  39. package/dist/decision-PNZ2S2TU.js.map +0 -1
  40. package/dist/log-PTHLI7ZN.js.map +0 -1
  41. package/dist/memory-SDZ57W2S.js.map +0 -1
  42. package/dist/run-MWHIQUSY.js.map +0 -1
  43. package/dist/supervise-XMZRNODO.js.map +0 -1
  44. package/dist/tui-67VJ5VBA.js +0 -842
  45. package/dist/tui-67VJ5VBA.js.map +0 -1
  46. /package/dist/{supervisor-3RUX5SPH.js.map → supervisor-N4D5EWCC.js.map} +0 -0
@@ -1,14 +1,41 @@
1
1
  import {
2
2
  printError,
3
- printSuccess
3
+ printSuccess,
4
+ printTable
4
5
  } from "./chunk-YQIWMDXL.js";
5
6
 
6
7
  // src/commands/log.ts
7
8
  import { randomUUID } from "crypto";
8
9
  import { appendFile } from "fs/promises";
9
10
  import path from "path";
10
- import { appendLogBuffer, getSupervisorDir, MemoryStore } from "@neotx/core";
11
+ import {
12
+ appendLogBuffer,
13
+ getSupervisorDir,
14
+ MemoryStore,
15
+ readLogBuffer
16
+ } from "@neotx/core";
11
17
  import { defineCommand } from "citty";
18
+ function truncate(text, max) {
19
+ return text.length > max ? `${text.slice(0, max - 1)}...` : text;
20
+ }
21
+ async function handleListRecent(name, limit = 20) {
22
+ const dir = getSupervisorDir(name);
23
+ const entries = await readLogBuffer(dir);
24
+ const recent = entries.slice(-limit).reverse();
25
+ if (recent.length === 0) {
26
+ console.log("No log entries found.");
27
+ return;
28
+ }
29
+ printTable(
30
+ ["TIME", "TYPE", "AGENT", "MESSAGE"],
31
+ recent.map((e) => [
32
+ new Date(e.timestamp).toLocaleTimeString(),
33
+ e.type,
34
+ e.agent ?? "-",
35
+ truncate(e.message, 60)
36
+ ])
37
+ );
38
+ }
12
39
  var VALID_TYPES = [
13
40
  "progress",
14
41
  "action",
@@ -41,13 +68,13 @@ var log_default = defineCommand({
41
68
  args: {
42
69
  type: {
43
70
  type: "positional",
44
- description: "Report type: progress, action, decision, blocker, milestone, discovery",
45
- required: true
71
+ description: "Report type: progress, action, decision, blocker, milestone, discovery (or omit to list recent)",
72
+ required: false
46
73
  },
47
74
  message: {
48
75
  type: "positional",
49
- description: "Message to log",
50
- required: true
76
+ description: "Message to log (required when type is provided)",
77
+ required: false
51
78
  },
52
79
  name: {
53
80
  type: "string",
@@ -68,25 +95,44 @@ var log_default = defineCommand({
68
95
  type: "string",
69
96
  description: "Repository path"
70
97
  },
98
+ scope: {
99
+ type: "string",
100
+ description: "Repository scope for discovery entries (alias for --repo)"
101
+ },
71
102
  procedure: {
72
103
  type: "boolean",
73
104
  description: "Also write as a procedure memory entry",
74
105
  default: false
106
+ },
107
+ preview: {
108
+ type: "boolean",
109
+ description: "Preview the formatted inbox message before writing (for blocker type)",
110
+ default: false
75
111
  }
76
112
  },
113
+ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: CLI command handler with multiple type-specific branches; extracting would obscure flow
77
114
  async run({ args }) {
78
115
  const type = args.type;
116
+ if (!type) {
117
+ await handleListRecent(args.name);
118
+ return;
119
+ }
79
120
  if (!VALID_TYPES.includes(type)) {
80
121
  printError(`Invalid type "${type}". Must be one of: ${VALID_TYPES.join(", ")}`);
81
122
  process.exitCode = 1;
82
123
  return;
83
124
  }
125
+ if (!args.message) {
126
+ printError(`Usage: neo log ${type} <message>`);
127
+ process.exitCode = 1;
128
+ return;
129
+ }
84
130
  const dir = getSupervisorDir(args.name);
85
131
  const now = (/* @__PURE__ */ new Date()).toISOString();
86
132
  const id = randomUUID();
87
133
  const agent = process.env.NEO_AGENT_NAME ?? void 0;
88
134
  const runId = process.env.NEO_RUN_ID ?? void 0;
89
- const repo = args.repo ?? process.env.NEO_REPOSITORY ?? void 0;
135
+ const repo = args.repo ?? args.scope ?? process.env.NEO_REPOSITORY ?? void 0;
90
136
  let target = TARGET_MAP[type] ?? "digest";
91
137
  if (args.memory) target = "memory";
92
138
  if (args.knowledge) target = "knowledge";
@@ -112,7 +158,8 @@ var log_default = defineCommand({
112
158
  try {
113
159
  const store = new MemoryStore(path.join(dir, "memory.sqlite"));
114
160
  await store.write({
115
- type: args.procedure ? "procedure" : "fact",
161
+ type: "knowledge",
162
+ subtype: args.procedure ? "procedure" : "fact",
116
163
  scope: repo ?? "global",
117
164
  content: args.message,
118
165
  source: agent ?? "user",
@@ -129,6 +176,14 @@ var log_default = defineCommand({
129
176
  text: `[BLOCKER]${agent ? ` (${agent})` : ""} ${args.message}`,
130
177
  timestamp: now
131
178
  };
179
+ if (args.preview) {
180
+ console.log("\nPreview of inbox message:");
181
+ console.log("\u2500".repeat(60));
182
+ console.log(JSON.stringify(inboxMessage, null, 2));
183
+ console.log("\u2500".repeat(60));
184
+ console.log("\nUse without --preview to write to inbox.");
185
+ return;
186
+ }
132
187
  await appendFile(`${dir}/inbox.jsonl`, `${JSON.stringify(inboxMessage)}
133
188
  `, "utf-8");
134
189
  }
@@ -138,4 +193,4 @@ var log_default = defineCommand({
138
193
  export {
139
194
  log_default as default
140
195
  };
141
- //# sourceMappingURL=log-PTHLI7ZN.js.map
196
+ //# sourceMappingURL=log-ZLIAIBZQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/log.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { appendFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n appendLogBuffer,\n getSupervisorDir,\n type LogBufferEntry,\n MemoryStore,\n readLogBuffer,\n} from \"@neotx/core\";\nimport { defineCommand } from \"citty\";\nimport { printError, printSuccess, printTable } from \"../output.js\";\n\nfunction truncate(text: string, max: number): string {\n return text.length > max ? `${text.slice(0, max - 1)}...` : text;\n}\n\nasync function handleListRecent(name: string, limit = 20): Promise<void> {\n const dir = getSupervisorDir(name);\n\n const entries = await readLogBuffer(dir);\n const recent = entries.slice(-limit).reverse();\n\n if (recent.length === 0) {\n console.log(\"No log entries found.\");\n return;\n }\n\n printTable(\n [\"TIME\", \"TYPE\", \"AGENT\", \"MESSAGE\"],\n recent.map((e: LogBufferEntry) => [\n new Date(e.timestamp).toLocaleTimeString(),\n e.type,\n e.agent ?? \"-\",\n truncate(e.message, 60),\n ]),\n );\n}\n\nconst VALID_TYPES = [\n \"progress\",\n \"action\",\n \"decision\",\n \"blocker\",\n \"milestone\",\n \"discovery\",\n] as const;\ntype LogType = (typeof VALID_TYPES)[number];\n\n// Map log types to activity.jsonl entry types (preserve existing behavior)\nconst TYPE_MAP: Record<string, string> = {\n decision: \"decision\",\n action: \"action\",\n blocker: \"error\",\n progress: \"event\",\n milestone: \"event\",\n discovery: \"event\",\n};\n\n// Implicit routing: which target each type gets by default\nconst TARGET_MAP: Record<string, \"memory\" | \"knowledge\" | \"digest\"> = {\n progress: \"digest\",\n action: \"digest\",\n decision: \"memory\",\n milestone: \"memory\",\n blocker: \"memory\",\n discovery: \"knowledge\",\n};\n\nexport default defineCommand({\n meta: {\n name: \"log\",\n description: \"Log a structured progress report to the supervisor activity log\",\n },\n args: {\n type: {\n type: \"positional\",\n description:\n \"Report type: progress, action, decision, blocker, milestone, discovery (or omit to list recent)\",\n required: false,\n },\n message: {\n type: \"positional\",\n description: \"Message to log (required when type is provided)\",\n required: false,\n },\n name: {\n type: \"string\",\n description: \"Supervisor instance name\",\n default: \"supervisor\",\n },\n memory: {\n type: \"boolean\",\n description: \"Override routing: send to memory target\",\n default: false,\n },\n knowledge: {\n type: \"boolean\",\n description: \"Override routing: send to knowledge target\",\n default: false,\n },\n repo: {\n type: \"string\",\n description: \"Repository path\",\n },\n scope: {\n type: \"string\",\n description: \"Repository scope for discovery entries (alias for --repo)\",\n },\n procedure: {\n type: \"boolean\",\n description: \"Also write as a procedure memory entry\",\n default: false,\n },\n preview: {\n type: \"boolean\",\n description: \"Preview the formatted inbox message before writing (for blocker type)\",\n default: false,\n },\n },\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: CLI command handler with multiple type-specific branches; extracting would obscure flow\n async run({ args }) {\n const type = args.type as string | undefined;\n\n // No type = list recent logs\n if (!type) {\n await handleListRecent(args.name);\n return;\n }\n\n if (!VALID_TYPES.includes(type as LogType)) {\n printError(`Invalid type \"${type}\". Must be one of: ${VALID_TYPES.join(\", \")}`);\n process.exitCode = 1;\n return;\n }\n\n if (!args.message) {\n printError(`Usage: neo log ${type} <message>`);\n process.exitCode = 1;\n return;\n }\n\n const dir = getSupervisorDir(args.name);\n const now = new Date().toISOString();\n const id = randomUUID();\n\n // Resolve agent/run from env vars or flags\n const agent = process.env.NEO_AGENT_NAME ?? undefined;\n const runId = process.env.NEO_RUN_ID ?? undefined;\n const repo =\n (args.repo as string | undefined) ??\n (args.scope as string | undefined) ??\n process.env.NEO_REPOSITORY ??\n undefined;\n\n // Resolve target with flag overrides\n let target: \"memory\" | \"knowledge\" | \"digest\" = TARGET_MAP[type] ?? \"digest\";\n if (args.memory) target = \"memory\";\n if (args.knowledge) target = \"knowledge\";\n\n // 1. Always: append to activity.jsonl (existing behavior)\n const activityEntry = {\n id,\n type: TYPE_MAP[type] ?? \"event\",\n summary: args.message,\n timestamp: now,\n };\n await appendFile(`${dir}/activity.jsonl`, `${JSON.stringify(activityEntry)}\\n`, \"utf-8\");\n\n // 2. Always: append to log-buffer.jsonl via shared helper\n await appendLogBuffer(dir, {\n id,\n type: type as \"progress\" | \"action\" | \"decision\" | \"blocker\" | \"milestone\" | \"discovery\",\n message: args.message,\n agent,\n runId,\n repo,\n target,\n timestamp: now,\n });\n\n // 3. Write to memory store for knowledge entries (facts or procedures)\n if (target === \"knowledge\" || args.procedure) {\n try {\n const store = new MemoryStore(path.join(dir, \"memory.sqlite\"));\n await store.write({\n type: \"knowledge\",\n subtype: args.procedure ? \"procedure\" : \"fact\",\n scope: repo ?? \"global\",\n content: args.message,\n source: agent ?? \"user\",\n runId,\n });\n store.close();\n } catch {\n // Best-effort — don't crash CLI if store write fails\n }\n }\n\n // 4. If blocker: also append to inbox.jsonl (wake up heartbeat)\n if (type === \"blocker\") {\n const inboxMessage = {\n id: randomUUID(),\n from: \"agent\" as const,\n text: `[BLOCKER]${agent ? ` (${agent})` : \"\"} ${args.message}`,\n timestamp: now,\n };\n\n if (args.preview) {\n console.log(\"\\nPreview of inbox message:\");\n console.log(\"─\".repeat(60));\n console.log(JSON.stringify(inboxMessage, null, 2));\n console.log(\"─\".repeat(60));\n console.log(\"\\nUse without --preview to write to inbox.\");\n return;\n }\n\n await appendFile(`${dir}/inbox.jsonl`, `${JSON.stringify(inboxMessage)}\\n`, \"utf-8\");\n }\n\n printSuccess(`Logged: [${type}] ${args.message.slice(0, 100)}`);\n },\n});\n"],"mappings":"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","names":[]}
@@ -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