@pcircle/memesh 4.5.0 → 4.5.1

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 (176) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.mcp.json +1 -1
  4. package/README.de.md +2 -5
  5. package/README.es.md +5 -8
  6. package/README.fr.md +3 -6
  7. package/README.ja.md +5 -8
  8. package/README.ko.md +5 -8
  9. package/README.md +28 -10
  10. package/README.pt.md +3 -6
  11. package/README.th.md +3 -6
  12. package/README.vi.md +3 -6
  13. package/README.zh-CN.md +5 -8
  14. package/README.zh-TW.md +5 -8
  15. package/dashboard/dist/index.html +9 -9
  16. package/dist/cli/view.d.ts.map +1 -1
  17. package/dist/cli/view.js +2 -2
  18. package/dist/cli/view.js.map +1 -1
  19. package/dist/core/analytics.d.ts +3 -3
  20. package/dist/core/analytics.d.ts.map +1 -1
  21. package/dist/core/analytics.js.map +1 -1
  22. package/dist/core/config.d.ts +0 -1
  23. package/dist/core/config.d.ts.map +1 -1
  24. package/dist/core/config.js +2 -1
  25. package/dist/core/config.js.map +1 -1
  26. package/dist/core/demo.d.ts +2 -2
  27. package/dist/core/demo.d.ts.map +1 -1
  28. package/dist/core/demo.js.map +1 -1
  29. package/dist/core/doctor.d.ts +1 -0
  30. package/dist/core/doctor.d.ts.map +1 -1
  31. package/dist/core/doctor.js +191 -47
  32. package/dist/core/doctor.js.map +1 -1
  33. package/dist/core/dreamer.d.ts +15 -7
  34. package/dist/core/dreamer.d.ts.map +1 -1
  35. package/dist/core/dreamer.js +310 -35
  36. package/dist/core/dreamer.js.map +1 -1
  37. package/dist/core/embedder.d.ts +2 -1
  38. package/dist/core/embedder.d.ts.map +1 -1
  39. package/dist/core/embedder.js +22 -1
  40. package/dist/core/embedder.js.map +1 -1
  41. package/dist/core/extractor.d.ts.map +1 -1
  42. package/dist/core/extractor.js +2 -1
  43. package/dist/core/extractor.js.map +1 -1
  44. package/dist/core/graph.d.ts +4 -4
  45. package/dist/core/graph.d.ts.map +1 -1
  46. package/dist/core/graph.js.map +1 -1
  47. package/dist/core/install-hooks.d.ts +1 -0
  48. package/dist/core/install-hooks.d.ts.map +1 -1
  49. package/dist/core/install-hooks.js +0 -0
  50. package/dist/core/install-hooks.js.map +1 -1
  51. package/dist/core/kg-backfill.d.ts +4 -4
  52. package/dist/core/kg-backfill.d.ts.map +1 -1
  53. package/dist/core/kg-backfill.js +1 -1
  54. package/dist/core/kg-backfill.js.map +1 -1
  55. package/dist/core/lesson-engine.d.ts +1 -0
  56. package/dist/core/lesson-engine.d.ts.map +1 -1
  57. package/dist/core/lesson-engine.js +1 -0
  58. package/dist/core/lesson-engine.js.map +1 -1
  59. package/dist/core/lifecycle.d.ts +4 -4
  60. package/dist/core/lifecycle.d.ts.map +1 -1
  61. package/dist/core/lifecycle.js +1 -1
  62. package/dist/core/lifecycle.js.map +1 -1
  63. package/dist/core/llm-client.d.ts.map +1 -1
  64. package/dist/core/llm-client.js +3 -6
  65. package/dist/core/llm-client.js.map +1 -1
  66. package/dist/core/llm-telemetry.d.ts +4 -4
  67. package/dist/core/llm-telemetry.d.ts.map +1 -1
  68. package/dist/core/llm-telemetry.js +1 -1
  69. package/dist/core/llm-telemetry.js.map +1 -1
  70. package/dist/core/memory-tool.d.ts.map +1 -1
  71. package/dist/core/memory-tool.js +4 -0
  72. package/dist/core/memory-tool.js.map +1 -1
  73. package/dist/core/operations.d.ts.map +1 -1
  74. package/dist/core/operations.js +22 -7
  75. package/dist/core/operations.js.map +1 -1
  76. package/dist/core/paths.d.ts +3 -0
  77. package/dist/core/paths.d.ts.map +1 -1
  78. package/dist/core/paths.js +67 -1
  79. package/dist/core/paths.js.map +1 -1
  80. package/dist/core/patterns.d.ts +2 -2
  81. package/dist/core/patterns.d.ts.map +1 -1
  82. package/dist/core/patterns.js.map +1 -1
  83. package/dist/core/project-tags.d.ts +3 -3
  84. package/dist/core/project-tags.d.ts.map +1 -1
  85. package/dist/core/project-tags.js.map +1 -1
  86. package/dist/core/projects.d.ts +2 -2
  87. package/dist/core/projects.d.ts.map +1 -1
  88. package/dist/core/projects.js.map +1 -1
  89. package/dist/core/schema-export.d.ts.map +1 -1
  90. package/dist/core/schema-export.js +0 -34
  91. package/dist/core/schema-export.js.map +1 -1
  92. package/dist/core/serializer.d.ts.map +1 -1
  93. package/dist/core/serializer.js +45 -4
  94. package/dist/core/serializer.js.map +1 -1
  95. package/dist/core/stats.d.ts +2 -2
  96. package/dist/core/stats.d.ts.map +1 -1
  97. package/dist/core/stats.js.map +1 -1
  98. package/dist/core/transcript-extractor.d.ts +5 -6
  99. package/dist/core/transcript-extractor.d.ts.map +1 -1
  100. package/dist/core/transcript-extractor.js +4 -24
  101. package/dist/core/transcript-extractor.js.map +1 -1
  102. package/dist/core/transcript-source.d.ts.map +1 -1
  103. package/dist/core/transcript-source.js.map +1 -1
  104. package/dist/core/types.d.ts +17 -7
  105. package/dist/core/types.d.ts.map +1 -1
  106. package/dist/core/types.js +2 -0
  107. package/dist/core/types.js.map +1 -1
  108. package/dist/db.d.ts +5 -5
  109. package/dist/db.d.ts.map +1 -1
  110. package/dist/db.js +155 -17
  111. package/dist/db.js.map +1 -1
  112. package/dist/knowledge-graph.d.ts +3 -2
  113. package/dist/knowledge-graph.d.ts.map +1 -1
  114. package/dist/knowledge-graph.js +19 -10
  115. package/dist/knowledge-graph.js.map +1 -1
  116. package/dist/mcp/server.js +2 -1
  117. package/dist/mcp/server.js.map +1 -1
  118. package/dist/skills-manifest.json +28 -33
  119. package/dist/storage/conflicts.d.ts +3 -3
  120. package/dist/storage/conflicts.d.ts.map +1 -1
  121. package/dist/storage/conflicts.js.map +1 -1
  122. package/dist/storage/fts-index.d.ts +4 -4
  123. package/dist/storage/fts-index.d.ts.map +1 -1
  124. package/dist/storage/fts-index.js.map +1 -1
  125. package/dist/storage/sqlite.d.ts +20 -0
  126. package/dist/storage/sqlite.d.ts.map +1 -0
  127. package/dist/storage/sqlite.js +64 -0
  128. package/dist/storage/sqlite.js.map +1 -0
  129. package/dist/storage/vector-index.d.ts +3 -0
  130. package/dist/storage/vector-index.d.ts.map +1 -0
  131. package/dist/storage/vector-index.js +7 -0
  132. package/dist/storage/vector-index.js.map +1 -0
  133. package/dist/transports/cli/cli.d.ts.map +1 -1
  134. package/dist/transports/cli/cli.js +126 -84
  135. package/dist/transports/cli/cli.js.map +1 -1
  136. package/dist/transports/http/retired-routes.d.ts.map +1 -1
  137. package/dist/transports/http/retired-routes.js +1 -0
  138. package/dist/transports/http/retired-routes.js.map +1 -1
  139. package/dist/transports/http/server.d.ts.map +1 -1
  140. package/dist/transports/http/server.js +48 -29
  141. package/dist/transports/http/server.js.map +1 -1
  142. package/dist/transports/mcp/handlers.d.ts +4 -96
  143. package/dist/transports/mcp/handlers.d.ts.map +1 -1
  144. package/dist/transports/mcp/handlers.js +24 -58
  145. package/dist/transports/mcp/handlers.js.map +1 -1
  146. package/dist/transports/schemas.d.ts +10 -30
  147. package/dist/transports/schemas.d.ts.map +1 -1
  148. package/dist/transports/schemas.js +5 -29
  149. package/dist/transports/schemas.js.map +1 -1
  150. package/hooks/hooks.json +0 -10
  151. package/package.json +6 -10
  152. package/scripts/hooks/_generated/core-paths.js +67 -1
  153. package/scripts/hooks/_generated/sqlite.js +71 -0
  154. package/scripts/hooks/_shared.js +286 -195
  155. package/scripts/hooks/post-commit.js +52 -10
  156. package/scripts/hooks/pre-compact.js +10 -7
  157. package/scripts/hooks/pre-edit-recall.js +4 -8
  158. package/scripts/hooks/session-start.js +95 -47
  159. package/scripts/hooks/session-summary.js +120 -52
  160. package/scripts/hooks/user-prompt-intent.js +3 -2
  161. package/skills/memesh/SKILL.md +1 -2
  162. package/dist/core/skill-usage-log.d.ts +0 -11
  163. package/dist/core/skill-usage-log.d.ts.map +0 -1
  164. package/dist/core/skill-usage-log.js +0 -125
  165. package/dist/core/skill-usage-log.js.map +0 -1
  166. package/dist/core/verifier.d.ts +0 -40
  167. package/dist/core/verifier.d.ts.map +0 -1
  168. package/dist/core/verifier.js +0 -206
  169. package/dist/core/verifier.js.map +0 -1
  170. package/dist/mcp/launcher.d.ts +0 -3
  171. package/dist/mcp/launcher.d.ts.map +0 -1
  172. package/dist/mcp/launcher.js +0 -37
  173. package/dist/mcp/launcher.js.map +0 -1
  174. package/scripts/hooks/pre-bash-orchestration-nudge.js +0 -155
  175. package/scripts/postinstall-rebuild.mjs +0 -41
  176. package/skills/agentic-orchestration/SKILL.md +0 -399
@@ -6,11 +6,11 @@ import path from 'path';
6
6
  import { fileURLToPath } from 'url';
7
7
  import { openDatabase, closeDatabase, getDatabase, reindexFts, allowVectorIndexRebuild } from '../../db.js';
8
8
  import { remember, recallWithConflicts, forget, exportMemories, importMemories, learn, reindex, setPinned } from '../../core/operations.js';
9
- import { verifyAgentWork } from '../../core/verifier.js';
10
9
  import { readConfig, writeConfig, maskApiKey, detectCapabilities } from '../../core/config.js';
11
10
  import { MAX_LANGUAGE_LENGTH, languageValueError } from '../../core/output-language.js';
12
- import { getDbPath } from '../../core/paths.js';
11
+ import { getDbPath, redactSecrets, redactUserPaths } from '../../core/paths.js';
13
12
  import { flushPendingEmbeddings, canRefillVectorIndex } from '../../core/embedder.js';
13
+ import { NAMESPACES } from '../../core/types.js';
14
14
  async function withDatabase(fn) {
15
15
  openDatabase();
16
16
  try {
@@ -20,6 +20,12 @@ async function withDatabase(fn) {
20
20
  closeDatabase();
21
21
  }
22
22
  }
23
+ function requireOneOf(value, allowed, flag) {
24
+ if (value === undefined || allowed.includes(value))
25
+ return;
26
+ console.error(`Error: ${flag} "${value}" is not valid. Use one of: ${allowed.join(', ')}.`);
27
+ process.exit(1);
28
+ }
23
29
  const packageJsonPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../package.json');
24
30
  const packageRoot = path.dirname(packageJsonPath);
25
31
  const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
@@ -38,9 +44,12 @@ program
38
44
  .option('--type <type>', 'Entity type')
39
45
  .option('--obs <observations...>', 'Observations (space-separated)')
40
46
  .option('--tags <tags...>', 'Tags (space-separated)')
41
- .option('--namespace <namespace>', 'Namespace: personal, team, or global (default: personal)')
47
+ .option('--namespace <namespace>', 'Namespace: personal, team, or global. On a NEW memory this places it (default personal); on one that already exists it MOVES it out of the scope it is in — omit the flag to leave it alone.')
48
+ .option('--supersedes <name...>', 'This memory replaces the named one — ARCHIVES it immediately (recoverable; nothing is deleted)')
49
+ .option('--contradicts <name...>', 'This memory cannot both be true with the named one — both surface as a conflict on every recall')
42
50
  .option('--json', 'Output as JSON')
43
51
  .action(async (text, opts) => {
52
+ requireOneOf(opts.namespace, NAMESPACES, '--namespace');
44
53
  if (text && !opts.name && !opts.type) {
45
54
  const slug = String(text)
46
55
  .toLowerCase()
@@ -68,6 +77,10 @@ program
68
77
  ' memesh remember "Use OAuth 2.0 with PKCE"');
69
78
  process.exit(1);
70
79
  }
80
+ const relations = [
81
+ ...(opts.supersedes ?? []).map(to => ({ to, type: 'supersedes' })),
82
+ ...(opts.contradicts ?? []).map(to => ({ to, type: 'contradicts' })),
83
+ ];
71
84
  await withDatabase(async () => {
72
85
  const result = remember({
73
86
  name: opts.name,
@@ -75,13 +88,31 @@ program
75
88
  observations: opts.obs,
76
89
  tags: opts.tags,
77
90
  namespace: opts.namespace,
91
+ relations: relations.length > 0 ? relations : undefined,
92
+ sourceHost: 'cli',
78
93
  });
79
94
  if (opts.json) {
80
95
  console.log(JSON.stringify(result));
81
96
  }
82
97
  else {
83
98
  console.log(`✅ Stored "${result.name}" (${result.observations} observations, ${result.tags} tags)`);
99
+ if (result.movedFromNamespace) {
100
+ console.log(` moved: ${result.movedFromNamespace} → ${opts.namespace} (was in ${result.movedFromNamespace}; re-run with --namespace ${result.movedFromNamespace} to put it back)`);
101
+ }
102
+ if (result.superseded?.length) {
103
+ console.log(` archived as superseded: ${result.superseded.join(', ')}`);
104
+ }
105
+ const contradicted = (result.relationsCreated ?? [])
106
+ .filter(r => r.type === 'contradicts')
107
+ .map(r => r.to);
108
+ if (contradicted.length > 0) {
109
+ console.log(` conflicts stated: ${contradicted.join(', ')}`);
110
+ }
111
+ for (const err of result.relationErrors ?? [])
112
+ console.error(` ⚠️ ${err}`);
84
113
  }
114
+ if (result.relationErrors?.length)
115
+ process.exitCode = 1;
85
116
  await flushPendingEmbeddings();
86
117
  });
87
118
  });
@@ -96,6 +127,7 @@ program
96
127
  .option('--cross-project', 'Search across all project tags (ignores --tag filter)')
97
128
  .option('--json', 'Output as JSON')
98
129
  .action(async (query, opts) => {
130
+ requireOneOf(opts.namespace, NAMESPACES, '--namespace');
99
131
  await withDatabase(async () => {
100
132
  const { entities, conflicts } = await recallWithConflicts({
101
133
  query: query || undefined,
@@ -173,8 +205,14 @@ program
173
205
  else if (result.observation_removed) {
174
206
  console.log(`✂️ Removed observation (${result.remaining_observations} remaining)`);
175
207
  }
208
+ else if (opts.observation && result.entity_found) {
209
+ console.log(`Entity "${opts.name}" has no observation matching that text (${result.remaining_observations} observation(s) present).`);
210
+ console.log(`See them with: memesh recall "${opts.name}" --json`);
211
+ process.exitCode = 1;
212
+ }
176
213
  else {
177
214
  console.log(`Entity "${opts.name}" not found`);
215
+ process.exitCode = 1;
178
216
  }
179
217
  });
180
218
  });
@@ -219,6 +257,31 @@ program
219
257
  console.error('so it is not a like-for-like replacement for compressing one named entity.');
220
258
  process.exitCode = 1;
221
259
  });
260
+ program
261
+ .command('verify')
262
+ .description('(retired) Removed with the agentic-orchestration experiment — see the message this prints')
263
+ .allowUnknownOption()
264
+ .action(() => {
265
+ console.error('`memesh verify` has been retired, along with the agentic-orchestration experiment.');
266
+ console.error('');
267
+ console.error('It recorded a verification report for background-agent work. The protocol it');
268
+ console.error('served was removed without ever leaving opt-in. Run your own verification');
269
+ console.error('(typecheck / tests / lint) and store conclusions with `memesh remember` if you');
270
+ console.error('want them remembered. Existing verification_record entities are untouched.');
271
+ process.exitCode = 1;
272
+ });
273
+ program
274
+ .command('patterns')
275
+ .description('(retired) Removed with the agentic-orchestration experiment — see the message this prints')
276
+ .allowUnknownOption()
277
+ .action(() => {
278
+ console.error('`memesh patterns` has been retired, along with the agentic-orchestration experiment.');
279
+ console.error('');
280
+ console.error('It displayed the experiment\'s local skill-usage telemetry, which is no longer');
281
+ console.error('written. A leftover ~/.memesh/skill-usage.jsonl is inert and safe to delete.');
282
+ console.error('For work-pattern insights, use the `user_patterns` MCP tool or GET /v1/patterns.');
283
+ process.exitCode = 1;
284
+ });
222
285
  program
223
286
  .command('export')
224
287
  .description('Export memories as JSON. Defaults to stdout (pipe-friendly); use `-o <file>` to write directly.')
@@ -227,6 +290,7 @@ program
227
290
  .option('--limit <n>', 'Max entities to export', '1000')
228
291
  .option('-o, --out <file>', 'Write JSON to <file> instead of stdout. Parent directory must exist.')
229
292
  .action(async (opts) => {
293
+ requireOneOf(opts.namespace, NAMESPACES, '--namespace');
230
294
  await withDatabase(() => {
231
295
  const result = exportMemories({
232
296
  tag: opts.tag,
@@ -235,6 +299,12 @@ program
235
299
  });
236
300
  const json = JSON.stringify(result, null, 2);
237
301
  if (opts.out) {
302
+ const outDir = path.dirname(path.resolve(opts.out));
303
+ if (!fs.existsSync(outDir)) {
304
+ console.error(`Error: cannot write ${opts.out} — the directory ${outDir} does not exist.`);
305
+ console.error(` Create it first (mkdir -p "${outDir}"), or drop -o to write to stdout.`);
306
+ process.exit(1);
307
+ }
238
308
  fs.writeFileSync(opts.out, json + '\n');
239
309
  process.stderr.write(`✅ Exported ${result.entity_count} entities to ${opts.out}\n`);
240
310
  }
@@ -250,6 +320,8 @@ program
250
320
  .option('--namespace <ns>', 'Override namespace for all imported entities')
251
321
  .option('--merge <strategy>', 'Merge strategy: skip | overwrite | append', 'skip')
252
322
  .action(async (file, opts) => {
323
+ requireOneOf(opts.merge, ['skip', 'overwrite', 'append'], '--merge');
324
+ requireOneOf(opts.namespace, NAMESPACES, '--namespace');
253
325
  await withDatabase(() => {
254
326
  let raw;
255
327
  try {
@@ -281,11 +353,18 @@ program
281
353
  console.error(` Try: memesh export > my-export.json && memesh import my-export.json`);
282
354
  process.exit(1);
283
355
  }
284
- const result = importMemories({
285
- data: data,
286
- namespace: opts.namespace,
287
- merge_strategy: opts.merge,
288
- });
356
+ let result;
357
+ try {
358
+ result = importMemories({
359
+ data: data,
360
+ namespace: opts.namespace,
361
+ merge_strategy: opts.merge,
362
+ });
363
+ }
364
+ catch (err) {
365
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
366
+ process.exit(1);
367
+ }
289
368
  console.log(`Imported: ${result.imported}, Skipped: ${result.skipped}, Appended: ${result.appended}`);
290
369
  if (result.errors.length > 0) {
291
370
  console.error(`Errors:\n ${result.errors.join('\n ')}`);
@@ -303,6 +382,7 @@ program
303
382
  .option('--severity <level>', 'Severity: critical|major|minor', 'minor')
304
383
  .option('--json', 'Output as JSON')
305
384
  .action(async (opts) => {
385
+ requireOneOf(opts.severity, ['critical', 'major', 'minor'], '--severity');
306
386
  await withDatabase(() => {
307
387
  const result = learn({
308
388
  error: opts.error,
@@ -310,6 +390,7 @@ program
310
390
  root_cause: opts.rootCause,
311
391
  prevention: opts.prevention,
312
392
  severity: opts.severity,
393
+ sourceHost: 'cli',
313
394
  });
314
395
  if (opts.json) {
315
396
  console.log(JSON.stringify(result));
@@ -319,50 +400,6 @@ program
319
400
  }
320
401
  });
321
402
  });
322
- program
323
- .command('verify <workdir>')
324
- .description('Record a verification report for agent work in <workdir>. ' +
325
- 'Exit codes: 0 pass, 1 fail, 2 unverified (nothing was checked).')
326
- .requiredOption('--agent-id <id>', 'Identifier for the agent being verified')
327
- .option('--base <ref>', 'Git ref to diff against (default: merge-base with origin/main)')
328
- .option('--expected-files <n>', 'Number of files the agent claimed to change', (v) => parseInt(v, 10))
329
- .option('--report <path>', 'Path to a JSON file with pre-computed report (typecheck/tests/lint/build)')
330
- .option('--json', 'Output as JSON')
331
- .action(async (workdir, opts) => {
332
- await withDatabase(() => {
333
- let externalReport;
334
- let result;
335
- try {
336
- if (opts.report) {
337
- const raw = fs.readFileSync(opts.report, 'utf8');
338
- externalReport = JSON.parse(raw);
339
- }
340
- result = verifyAgentWork({
341
- agent_id: opts.agentId,
342
- workdir: path.resolve(workdir),
343
- base: opts.base,
344
- claim: opts.expectedFiles != null ? { expected_files: opts.expectedFiles } : undefined,
345
- report: externalReport,
346
- });
347
- }
348
- catch (err) {
349
- console.error(err instanceof Error ? err.message : String(err));
350
- console.error('Nothing was checked (exit 2 = unverified).');
351
- process.exit(2);
352
- }
353
- if (opts.json) {
354
- console.log(JSON.stringify(result, null, 2));
355
- }
356
- else {
357
- console.log(`${result.verdict.toUpperCase()} agent=${opts.agentId} entity=${result.entity_name}`);
358
- console.log(` reality: ${result.reality_check.summary}`);
359
- if (result.verdict === 'unverified') {
360
- console.log(' nothing was checked — pass --expected-files <n> and/or --report <file> to verify something.');
361
- }
362
- }
363
- process.exit(result.verdict === 'pass' ? 0 : result.verdict === 'fail' ? 1 : 2);
364
- });
365
- });
366
403
  const configCmd = program.command('config').description('Manage configuration');
367
404
  configCmd
368
405
  .command('list')
@@ -392,7 +429,6 @@ const ALLOWED_KEYS = new Set([
392
429
  'embedder.model',
393
430
  'autoUpdate',
394
431
  'sessionLimit',
395
- 'enableAgenticOrchestration',
396
432
  'autoCapture',
397
433
  'llmFallbacks',
398
434
  'language',
@@ -516,7 +552,7 @@ configCmd
516
552
  coerced = parseInt(value, 10);
517
553
  if (canonical === 'llmFallbacks')
518
554
  coerced = JSON.parse(value);
519
- if (canonical === 'enableAgenticOrchestration' || canonical === 'autoCapture') {
555
+ if (canonical === 'autoCapture') {
520
556
  coerced = value === 'true' || value === '1';
521
557
  }
522
558
  const config = readConfig();
@@ -524,6 +560,10 @@ configCmd
524
560
  writeConfig(config);
525
561
  const displayValue = canonical.toLowerCase().includes('key') ? maskApiKey(String(value)) : String(value);
526
562
  console.log(`✅ Set ${canonical} = ${displayValue}`);
563
+ if (canonical === 'llm.apiKey' && !config.llm?.provider) {
564
+ console.log('⚠️ No llm.provider is set, so this key is not used yet and LLM features stay off.');
565
+ console.log(' Set one with: memesh config set llm.provider <anthropic|openai|ollama>');
566
+ }
527
567
  });
528
568
  configCmd
529
569
  .command('unset')
@@ -592,10 +632,16 @@ program
592
632
  .description('Start the HTTP API server and web dashboard')
593
633
  .option('--port <port>', 'Port number', '3737')
594
634
  .option('--host <host>', 'Host to bind', '127.0.0.1')
595
- .option('--allow-remote', 'Allow binding to non-loopback hosts. A bearer token is generated and REQUIRED for every /v1 request the startup output shows where it lives and how to rotate it.')
635
+ .option('--allow-remote', 'Permit binding to a non-loopback host. Pair it with --host; on a non-loopback bind a bearer token is generated and REQUIRED for every /v1 request, and the startup output says where it lives. On the default loopback host this flag changes nothing.')
596
636
  .action(async (opts) => {
597
637
  const { startServer } = await import('../http/server.js');
598
- startServer(opts.host, parseInt(opts.port, 10), { allowRemote: opts.allowRemote, autoUpdateCheck: true });
638
+ try {
639
+ startServer(opts.host, parseInt(opts.port, 10), { allowRemote: opts.allowRemote, autoUpdateCheck: true });
640
+ }
641
+ catch (err) {
642
+ console.error(`MeMesh: ${err instanceof Error ? err.message : String(err)}`);
643
+ process.exit(1);
644
+ }
599
645
  });
600
646
  program
601
647
  .command('update')
@@ -641,6 +687,12 @@ program
641
687
  .option('--prune <days>', 'Delete rows older than N days BEFORE rendering (closes v4.2.0 retention gap)', (v) => parseInt(v, 10))
642
688
  .option('--json', 'Output as JSON')
643
689
  .action(async (opts) => {
690
+ for (const [flag, value] of [['--window', opts.window], ['--prune', opts.prune]]) {
691
+ if (value !== undefined && !Number.isFinite(value)) {
692
+ console.error(`Error: ${flag} needs a number of days.`);
693
+ process.exit(1);
694
+ }
695
+ }
644
696
  await withDatabase(async () => {
645
697
  const { summariseTelemetry, pruneTelemetry } = await import('../../core/llm-telemetry.js');
646
698
  let pruneResult = null;
@@ -1011,6 +1063,11 @@ dreamCmd
1011
1063
  });
1012
1064
  console.log(`${opts.dryRun ? '[dry-run] ' : ''}Dream pass complete in ${result.durationMs}ms`);
1013
1065
  console.log(` clusters scanned: ${result.clustersScanned}`);
1066
+ if (result.clusteringMode) {
1067
+ console.log(` grouped by: ${result.clusteringMode === 'semantic' ? 'meaning (embeddings)' : 'calendar week (no embeddings)'}`);
1068
+ }
1069
+ if (result.clusteringNote)
1070
+ console.log(` note: ${result.clusteringNote}`);
1014
1071
  console.log(` LLM calls: ${result.llmCalls}`);
1015
1072
  console.log(` proposals created: ${result.proposalsCreated}`);
1016
1073
  if (result.skipped.length > 0) {
@@ -1209,6 +1266,9 @@ program
1209
1266
  }
1210
1267
  console.log(`${opts.dryRun ? '[dry-run] ' : ''}Settings: ${result.settingsPath}`);
1211
1268
  console.log(`${opts.dryRun ? '[dry-run] Would add ' : 'Added '}${result.added} hook entr${result.added === 1 ? 'y' : 'ies'}, ${opts.dryRun ? 'would skip ' : 'skipped '}${result.skipped} already-installed.`);
1269
+ if (result.pruned > 0) {
1270
+ console.log(`${opts.dryRun ? '[dry-run] Would remove ' : 'Removed '}${result.pruned} retired memesh hook entr${result.pruned === 1 ? 'y' : 'ies'} no longer shipped by this version.`);
1271
+ }
1212
1272
  if (result.backupPath)
1213
1273
  console.log(`Backup: ${result.backupPath}`);
1214
1274
  if (result.conflicts.length > 0) {
@@ -1289,11 +1349,19 @@ program
1289
1349
  body += `\n\n---\n**System Info**\n- Version: \`${pkg.version}\`\n- Node: \`${process.version}\`\n- Platform: \`${process.platform} ${process.arch}\`\n_Diagnostics unavailable: doctor probe failed._`;
1290
1350
  }
1291
1351
  }
1352
+ body = redactUserPaths(redactSecrets(body));
1292
1353
  const url = `https://github.com/PCIRCLE-AI/memesh-llm-memory/issues/new?title=${encodeURIComponent(`[${typeLabel}] `)}&body=${encodeURIComponent(body)}&labels=${encodeURIComponent(labels)}`;
1293
1354
  if (opts.open === false) {
1294
1355
  console.log(url);
1295
1356
  return;
1296
1357
  }
1358
+ console.log('This will be pre-filled into a PUBLIC GitHub issue:');
1359
+ console.log('---');
1360
+ console.log(body);
1361
+ console.log('---');
1362
+ if (opts.diagnostics !== false) {
1363
+ console.log('Re-run with --no-diagnostics to leave out the install ID and the doctor report.');
1364
+ }
1297
1365
  const { spawn } = await import('child_process');
1298
1366
  const cmd = process.platform === 'darwin' ? 'open'
1299
1367
  : process.platform === 'win32' ? 'cmd'
@@ -1319,6 +1387,7 @@ program
1319
1387
  'stored embedding first. Needed only when switching embedding providers.')
1320
1388
  .option('--json', 'Output as JSON')
1321
1389
  .action(async (opts) => {
1390
+ requireOneOf(opts.namespace, NAMESPACES, '--namespace');
1322
1391
  try {
1323
1392
  if (opts.fts) {
1324
1393
  if (opts.vectors) {
@@ -1403,33 +1472,6 @@ program
1403
1472
  throw err;
1404
1473
  }
1405
1474
  });
1406
- program
1407
- .command('patterns')
1408
- .description('Show local skill-usage telemetry (agentic-orchestration banner injections, verify_agent_work invocations). Local-only — never uploaded.')
1409
- .option('--json', 'Output as JSON')
1410
- .action(async (opts) => {
1411
- const { summariseSkillUsage } = await import('../../core/skill-usage-log.js');
1412
- const summary = summariseSkillUsage();
1413
- if (opts.json) {
1414
- console.log(JSON.stringify(summary, null, 2));
1415
- return;
1416
- }
1417
- console.log(`Skill usage log: ${summary.log_path}`);
1418
- console.log(` total events: ${summary.total_events}`);
1419
- console.log(` log size: ${summary.log_bytes} bytes`);
1420
- if (summary.first_event)
1421
- console.log(` first event: ${summary.first_event}`);
1422
- if (summary.last_event)
1423
- console.log(` last event: ${summary.last_event}`);
1424
- if (summary.total_events === 0) {
1425
- console.log(' (no events recorded yet — open a Claude Code session with memesh installed, or run a verification, to start collecting)');
1426
- return;
1427
- }
1428
- console.log(' events by name:');
1429
- for (const [name, count] of Object.entries(summary.events_by_name).sort((a, b) => b[1] - a[1])) {
1430
- console.log(` ${count.toString().padStart(6)} ${name}`);
1431
- }
1432
- });
1433
1475
  program
1434
1476
  .command('status')
1435
1477
  .description('Show MeMesh status and capabilities')
@@ -1444,7 +1486,7 @@ program
1444
1486
  console.log(`MeMesh v${pkg.version}`);
1445
1487
  console.log(`Search level: ${caps.searchLevel} (${caps.searchLevel === 1 ? 'Smart Mode' : 'Core'})`);
1446
1488
  console.log(`Embeddings: ${caps.embeddings}`);
1447
- console.log(`LLM: ${caps.llm ? `${caps.llm.provider} (${caps.llm.model})` : 'not configured'}`);
1489
+ console.log(`LLM: ${caps.llm ? `${caps.llm.provider} (${caps.llm.model ?? 'default'})` : 'not configured'}`);
1448
1490
  console.log(`Install method: ${installSupport.label}`);
1449
1491
  for (const line of formatUpdateCheckStatus(update)) {
1450
1492
  console.log(`\n${line}`);