@pcircle/memesh 4.4.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/README.de.md +32 -12
- package/README.es.md +13 -12
- package/README.fr.md +31 -11
- package/README.ja.md +13 -12
- package/README.ko.md +14 -13
- package/README.md +41 -16
- package/README.pt.md +30 -10
- package/README.th.md +16 -9
- package/README.vi.md +32 -12
- package/README.zh-CN.md +14 -13
- package/README.zh-TW.md +14 -13
- package/dashboard/dist/index.html +10 -10
- package/dist/cli/view-live.js +1 -1
- package/dist/cli/view.d.ts.map +1 -1
- package/dist/cli/view.js +2 -2
- package/dist/cli/view.js.map +1 -1
- package/dist/core/analytics.d.ts +7 -3
- package/dist/core/analytics.d.ts.map +1 -1
- package/dist/core/analytics.js +8 -8
- package/dist/core/analytics.js.map +1 -1
- package/dist/core/auto-tagger.d.ts.map +1 -1
- package/dist/core/auto-tagger.js.map +1 -1
- package/dist/core/config.d.ts +5 -3
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +30 -14
- package/dist/core/config.js.map +1 -1
- package/dist/core/demo.d.ts +2 -2
- package/dist/core/demo.d.ts.map +1 -1
- package/dist/core/demo.js.map +1 -1
- package/dist/core/digest-validator.d.ts.map +1 -1
- package/dist/core/digest-validator.js +3 -1
- package/dist/core/digest-validator.js.map +1 -1
- package/dist/core/doctor.d.ts +3 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +255 -101
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/dreamer.d.ts +35 -7
- package/dist/core/dreamer.d.ts.map +1 -1
- package/dist/core/dreamer.js +394 -41
- package/dist/core/dreamer.js.map +1 -1
- package/dist/core/embedder.d.ts +3 -5
- package/dist/core/embedder.d.ts.map +1 -1
- package/dist/core/embedder.js +26 -95
- package/dist/core/embedder.js.map +1 -1
- package/dist/core/extractor.d.ts.map +1 -1
- package/dist/core/extractor.js +2 -1
- package/dist/core/extractor.js.map +1 -1
- package/dist/core/failure-analyzer.d.ts.map +1 -1
- package/dist/core/failure-analyzer.js +2 -1
- package/dist/core/failure-analyzer.js.map +1 -1
- package/dist/core/graph.d.ts +4 -4
- package/dist/core/graph.d.ts.map +1 -1
- package/dist/core/graph.js.map +1 -1
- package/dist/core/install-hooks.d.ts +1 -0
- package/dist/core/install-hooks.d.ts.map +1 -1
- package/dist/core/install-hooks.js +0 -0
- package/dist/core/install-hooks.js.map +1 -1
- package/dist/core/kg-backfill.d.ts +4 -4
- package/dist/core/kg-backfill.d.ts.map +1 -1
- package/dist/core/kg-backfill.js +1 -1
- package/dist/core/kg-backfill.js.map +1 -1
- package/dist/core/lesson-engine.d.ts +1 -0
- package/dist/core/lesson-engine.d.ts.map +1 -1
- package/dist/core/lesson-engine.js +1 -0
- package/dist/core/lesson-engine.js.map +1 -1
- package/dist/core/lifecycle.d.ts +4 -4
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +1 -1
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/llm-client.d.ts.map +1 -1
- package/dist/core/llm-client.js +3 -6
- package/dist/core/llm-client.js.map +1 -1
- package/dist/core/llm-telemetry.d.ts +4 -4
- package/dist/core/llm-telemetry.d.ts.map +1 -1
- package/dist/core/llm-telemetry.js +1 -1
- package/dist/core/llm-telemetry.js.map +1 -1
- package/dist/core/llm-validator.d.ts +1 -0
- package/dist/core/llm-validator.d.ts.map +1 -1
- package/dist/core/llm-validator.js +33 -10
- package/dist/core/llm-validator.js.map +1 -1
- package/dist/core/memory-tool.d.ts.map +1 -1
- package/dist/core/memory-tool.js +4 -0
- package/dist/core/memory-tool.js.map +1 -1
- package/dist/core/operations.d.ts.map +1 -1
- package/dist/core/operations.js +23 -8
- package/dist/core/operations.js.map +1 -1
- package/dist/core/output-language.d.ts +6 -0
- package/dist/core/output-language.d.ts.map +1 -0
- package/dist/core/output-language.js +25 -0
- package/dist/core/output-language.js.map +1 -0
- package/dist/core/paths.d.ts +3 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +67 -1
- package/dist/core/paths.js.map +1 -1
- package/dist/core/patterns.d.ts +2 -3
- package/dist/core/patterns.d.ts.map +1 -1
- package/dist/core/patterns.js +1 -5
- package/dist/core/patterns.js.map +1 -1
- package/dist/core/project-tags.d.ts +3 -3
- package/dist/core/project-tags.d.ts.map +1 -1
- package/dist/core/project-tags.js.map +1 -1
- package/dist/core/projects.d.ts +2 -2
- package/dist/core/projects.d.ts.map +1 -1
- package/dist/core/projects.js.map +1 -1
- package/dist/core/schema-export.d.ts.map +1 -1
- package/dist/core/schema-export.js +0 -34
- package/dist/core/schema-export.js.map +1 -1
- package/dist/core/serializer.d.ts.map +1 -1
- package/dist/core/serializer.js +45 -4
- package/dist/core/serializer.js.map +1 -1
- package/dist/core/stats.d.ts +2 -2
- package/dist/core/stats.d.ts.map +1 -1
- package/dist/core/stats.js.map +1 -1
- package/dist/core/transcript-extractor.d.ts +88 -0
- package/dist/core/transcript-extractor.d.ts.map +1 -0
- package/dist/core/transcript-extractor.js +417 -0
- package/dist/core/transcript-extractor.js.map +1 -0
- package/dist/core/transcript-source.d.ts +21 -0
- package/dist/core/transcript-source.d.ts.map +1 -0
- package/dist/core/transcript-source.js +142 -0
- package/dist/core/transcript-source.js.map +1 -0
- package/dist/core/types.d.ts +17 -7
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -1
- package/dist/db.d.ts +5 -5
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +165 -17
- package/dist/db.js.map +1 -1
- package/dist/knowledge-graph.d.ts +3 -2
- package/dist/knowledge-graph.d.ts.map +1 -1
- package/dist/knowledge-graph.js +19 -10
- package/dist/knowledge-graph.js.map +1 -1
- package/dist/mcp/server.js +2 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/skills-manifest.json +28 -33
- package/dist/storage/conflicts.d.ts +3 -3
- package/dist/storage/conflicts.d.ts.map +1 -1
- package/dist/storage/conflicts.js.map +1 -1
- package/dist/storage/fts-index.d.ts +4 -4
- package/dist/storage/fts-index.d.ts.map +1 -1
- package/dist/storage/fts-index.js.map +1 -1
- package/dist/storage/sqlite.d.ts +20 -0
- package/dist/storage/sqlite.d.ts.map +1 -0
- package/dist/storage/sqlite.js +64 -0
- package/dist/storage/sqlite.js.map +1 -0
- package/dist/storage/vector-index.d.ts +3 -0
- package/dist/storage/vector-index.d.ts.map +1 -0
- package/dist/storage/vector-index.js +7 -0
- package/dist/storage/vector-index.js.map +1 -0
- package/dist/transports/cli/cli.d.ts.map +1 -1
- package/dist/transports/cli/cli.js +278 -91
- package/dist/transports/cli/cli.js.map +1 -1
- package/dist/transports/http/retired-routes.d.ts.map +1 -1
- package/dist/transports/http/retired-routes.js +1 -0
- package/dist/transports/http/retired-routes.js.map +1 -1
- package/dist/transports/http/server.d.ts +7 -0
- package/dist/transports/http/server.d.ts.map +1 -1
- package/dist/transports/http/server.js +165 -79
- package/dist/transports/http/server.js.map +1 -1
- package/dist/transports/mcp/handlers.d.ts +4 -96
- package/dist/transports/mcp/handlers.d.ts.map +1 -1
- package/dist/transports/mcp/handlers.js +26 -59
- package/dist/transports/mcp/handlers.js.map +1 -1
- package/dist/transports/schemas.d.ts +10 -30
- package/dist/transports/schemas.d.ts.map +1 -1
- package/dist/transports/schemas.js +5 -29
- package/dist/transports/schemas.js.map +1 -1
- package/hooks/hooks.json +0 -10
- package/package.json +6 -19
- package/scripts/hooks/_generated/core-paths.js +67 -1
- package/scripts/hooks/_generated/sqlite.js +71 -0
- package/scripts/hooks/_shared.js +286 -195
- package/scripts/hooks/post-commit.js +52 -10
- package/scripts/hooks/pre-compact.js +10 -7
- package/scripts/hooks/pre-edit-recall.js +4 -8
- package/scripts/hooks/session-start.js +95 -47
- package/scripts/hooks/session-summary.js +120 -52
- package/scripts/hooks/user-prompt-intent.js +3 -2
- package/skills/memesh/SKILL.md +3 -2
- package/dist/core/skill-usage-log.d.ts +0 -11
- package/dist/core/skill-usage-log.d.ts.map +0 -1
- package/dist/core/skill-usage-log.js +0 -125
- package/dist/core/skill-usage-log.js.map +0 -1
- package/dist/core/verifier.d.ts +0 -40
- package/dist/core/verifier.d.ts.map +0 -1
- package/dist/core/verifier.js +0 -206
- package/dist/core/verifier.js.map +0 -1
- package/dist/mcp/launcher.d.ts +0 -3
- package/dist/mcp/launcher.d.ts.map +0 -1
- package/dist/mcp/launcher.js +0 -37
- package/dist/mcp/launcher.js.map +0 -1
- package/scripts/hooks/pre-bash-orchestration-nudge.js +0 -155
- package/scripts/postinstall-rebuild.mjs +0 -41
- package/skills/agentic-orchestration/SKILL.md +0 -399
|
@@ -6,10 +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
|
-
import {
|
|
10
|
+
import { MAX_LANGUAGE_LENGTH, languageValueError } from '../../core/output-language.js';
|
|
11
|
+
import { getDbPath, redactSecrets, redactUserPaths } from '../../core/paths.js';
|
|
12
12
|
import { flushPendingEmbeddings, canRefillVectorIndex } from '../../core/embedder.js';
|
|
13
|
+
import { NAMESPACES } from '../../core/types.js';
|
|
13
14
|
async function withDatabase(fn) {
|
|
14
15
|
openDatabase();
|
|
15
16
|
try {
|
|
@@ -19,6 +20,12 @@ async function withDatabase(fn) {
|
|
|
19
20
|
closeDatabase();
|
|
20
21
|
}
|
|
21
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
|
+
}
|
|
22
29
|
const packageJsonPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../package.json');
|
|
23
30
|
const packageRoot = path.dirname(packageJsonPath);
|
|
24
31
|
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
@@ -37,9 +44,12 @@ program
|
|
|
37
44
|
.option('--type <type>', 'Entity type')
|
|
38
45
|
.option('--obs <observations...>', 'Observations (space-separated)')
|
|
39
46
|
.option('--tags <tags...>', 'Tags (space-separated)')
|
|
40
|
-
.option('--namespace <namespace>', 'Namespace: personal, team, or global (default
|
|
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')
|
|
41
50
|
.option('--json', 'Output as JSON')
|
|
42
51
|
.action(async (text, opts) => {
|
|
52
|
+
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
43
53
|
if (text && !opts.name && !opts.type) {
|
|
44
54
|
const slug = String(text)
|
|
45
55
|
.toLowerCase()
|
|
@@ -67,6 +77,10 @@ program
|
|
|
67
77
|
' memesh remember "Use OAuth 2.0 with PKCE"');
|
|
68
78
|
process.exit(1);
|
|
69
79
|
}
|
|
80
|
+
const relations = [
|
|
81
|
+
...(opts.supersedes ?? []).map(to => ({ to, type: 'supersedes' })),
|
|
82
|
+
...(opts.contradicts ?? []).map(to => ({ to, type: 'contradicts' })),
|
|
83
|
+
];
|
|
70
84
|
await withDatabase(async () => {
|
|
71
85
|
const result = remember({
|
|
72
86
|
name: opts.name,
|
|
@@ -74,13 +88,31 @@ program
|
|
|
74
88
|
observations: opts.obs,
|
|
75
89
|
tags: opts.tags,
|
|
76
90
|
namespace: opts.namespace,
|
|
91
|
+
relations: relations.length > 0 ? relations : undefined,
|
|
92
|
+
sourceHost: 'cli',
|
|
77
93
|
});
|
|
78
94
|
if (opts.json) {
|
|
79
95
|
console.log(JSON.stringify(result));
|
|
80
96
|
}
|
|
81
97
|
else {
|
|
82
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}`);
|
|
83
113
|
}
|
|
114
|
+
if (result.relationErrors?.length)
|
|
115
|
+
process.exitCode = 1;
|
|
84
116
|
await flushPendingEmbeddings();
|
|
85
117
|
});
|
|
86
118
|
});
|
|
@@ -95,6 +127,7 @@ program
|
|
|
95
127
|
.option('--cross-project', 'Search across all project tags (ignores --tag filter)')
|
|
96
128
|
.option('--json', 'Output as JSON')
|
|
97
129
|
.action(async (query, opts) => {
|
|
130
|
+
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
98
131
|
await withDatabase(async () => {
|
|
99
132
|
const { entities, conflicts } = await recallWithConflicts({
|
|
100
133
|
query: query || undefined,
|
|
@@ -172,8 +205,14 @@ program
|
|
|
172
205
|
else if (result.observation_removed) {
|
|
173
206
|
console.log(`✂️ Removed observation (${result.remaining_observations} remaining)`);
|
|
174
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
|
+
}
|
|
175
213
|
else {
|
|
176
214
|
console.log(`Entity "${opts.name}" not found`);
|
|
215
|
+
process.exitCode = 1;
|
|
177
216
|
}
|
|
178
217
|
});
|
|
179
218
|
});
|
|
@@ -218,6 +257,31 @@ program
|
|
|
218
257
|
console.error('so it is not a like-for-like replacement for compressing one named entity.');
|
|
219
258
|
process.exitCode = 1;
|
|
220
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
|
+
});
|
|
221
285
|
program
|
|
222
286
|
.command('export')
|
|
223
287
|
.description('Export memories as JSON. Defaults to stdout (pipe-friendly); use `-o <file>` to write directly.')
|
|
@@ -226,6 +290,7 @@ program
|
|
|
226
290
|
.option('--limit <n>', 'Max entities to export', '1000')
|
|
227
291
|
.option('-o, --out <file>', 'Write JSON to <file> instead of stdout. Parent directory must exist.')
|
|
228
292
|
.action(async (opts) => {
|
|
293
|
+
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
229
294
|
await withDatabase(() => {
|
|
230
295
|
const result = exportMemories({
|
|
231
296
|
tag: opts.tag,
|
|
@@ -234,6 +299,12 @@ program
|
|
|
234
299
|
});
|
|
235
300
|
const json = JSON.stringify(result, null, 2);
|
|
236
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
|
+
}
|
|
237
308
|
fs.writeFileSync(opts.out, json + '\n');
|
|
238
309
|
process.stderr.write(`✅ Exported ${result.entity_count} entities to ${opts.out}\n`);
|
|
239
310
|
}
|
|
@@ -249,6 +320,8 @@ program
|
|
|
249
320
|
.option('--namespace <ns>', 'Override namespace for all imported entities')
|
|
250
321
|
.option('--merge <strategy>', 'Merge strategy: skip | overwrite | append', 'skip')
|
|
251
322
|
.action(async (file, opts) => {
|
|
323
|
+
requireOneOf(opts.merge, ['skip', 'overwrite', 'append'], '--merge');
|
|
324
|
+
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
252
325
|
await withDatabase(() => {
|
|
253
326
|
let raw;
|
|
254
327
|
try {
|
|
@@ -280,11 +353,18 @@ program
|
|
|
280
353
|
console.error(` Try: memesh export > my-export.json && memesh import my-export.json`);
|
|
281
354
|
process.exit(1);
|
|
282
355
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
+
}
|
|
288
368
|
console.log(`Imported: ${result.imported}, Skipped: ${result.skipped}, Appended: ${result.appended}`);
|
|
289
369
|
if (result.errors.length > 0) {
|
|
290
370
|
console.error(`Errors:\n ${result.errors.join('\n ')}`);
|
|
@@ -302,6 +382,7 @@ program
|
|
|
302
382
|
.option('--severity <level>', 'Severity: critical|major|minor', 'minor')
|
|
303
383
|
.option('--json', 'Output as JSON')
|
|
304
384
|
.action(async (opts) => {
|
|
385
|
+
requireOneOf(opts.severity, ['critical', 'major', 'minor'], '--severity');
|
|
305
386
|
await withDatabase(() => {
|
|
306
387
|
const result = learn({
|
|
307
388
|
error: opts.error,
|
|
@@ -309,6 +390,7 @@ program
|
|
|
309
390
|
root_cause: opts.rootCause,
|
|
310
391
|
prevention: opts.prevention,
|
|
311
392
|
severity: opts.severity,
|
|
393
|
+
sourceHost: 'cli',
|
|
312
394
|
});
|
|
313
395
|
if (opts.json) {
|
|
314
396
|
console.log(JSON.stringify(result));
|
|
@@ -318,50 +400,6 @@ program
|
|
|
318
400
|
}
|
|
319
401
|
});
|
|
320
402
|
});
|
|
321
|
-
program
|
|
322
|
-
.command('verify <workdir>')
|
|
323
|
-
.description('Record a verification report for agent work in <workdir>. ' +
|
|
324
|
-
'Exit codes: 0 pass, 1 fail, 2 unverified (nothing was checked).')
|
|
325
|
-
.requiredOption('--agent-id <id>', 'Identifier for the agent being verified')
|
|
326
|
-
.option('--base <ref>', 'Git ref to diff against (default: merge-base with origin/main)')
|
|
327
|
-
.option('--expected-files <n>', 'Number of files the agent claimed to change', (v) => parseInt(v, 10))
|
|
328
|
-
.option('--report <path>', 'Path to a JSON file with pre-computed report (typecheck/tests/lint/build)')
|
|
329
|
-
.option('--json', 'Output as JSON')
|
|
330
|
-
.action(async (workdir, opts) => {
|
|
331
|
-
await withDatabase(() => {
|
|
332
|
-
let externalReport;
|
|
333
|
-
let result;
|
|
334
|
-
try {
|
|
335
|
-
if (opts.report) {
|
|
336
|
-
const raw = fs.readFileSync(opts.report, 'utf8');
|
|
337
|
-
externalReport = JSON.parse(raw);
|
|
338
|
-
}
|
|
339
|
-
result = verifyAgentWork({
|
|
340
|
-
agent_id: opts.agentId,
|
|
341
|
-
workdir: path.resolve(workdir),
|
|
342
|
-
base: opts.base,
|
|
343
|
-
claim: opts.expectedFiles != null ? { expected_files: opts.expectedFiles } : undefined,
|
|
344
|
-
report: externalReport,
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
catch (err) {
|
|
348
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
349
|
-
console.error('Nothing was checked (exit 2 = unverified).');
|
|
350
|
-
process.exit(2);
|
|
351
|
-
}
|
|
352
|
-
if (opts.json) {
|
|
353
|
-
console.log(JSON.stringify(result, null, 2));
|
|
354
|
-
}
|
|
355
|
-
else {
|
|
356
|
-
console.log(`${result.verdict.toUpperCase()} agent=${opts.agentId} entity=${result.entity_name}`);
|
|
357
|
-
console.log(` reality: ${result.reality_check.summary}`);
|
|
358
|
-
if (result.verdict === 'unverified') {
|
|
359
|
-
console.log(' nothing was checked — pass --expected-files <n> and/or --report <file> to verify something.');
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
process.exit(result.verdict === 'pass' ? 0 : result.verdict === 'fail' ? 1 : 2);
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
403
|
const configCmd = program.command('config').description('Manage configuration');
|
|
366
404
|
configCmd
|
|
367
405
|
.command('list')
|
|
@@ -391,13 +429,20 @@ const ALLOWED_KEYS = new Set([
|
|
|
391
429
|
'embedder.model',
|
|
392
430
|
'autoUpdate',
|
|
393
431
|
'sessionLimit',
|
|
394
|
-
'enableAgenticOrchestration',
|
|
395
432
|
'autoCapture',
|
|
396
433
|
'llmFallbacks',
|
|
434
|
+
'language',
|
|
397
435
|
]);
|
|
398
436
|
const KEY_VALIDATORS = {
|
|
399
437
|
'llm.provider': (v) => ['anthropic', 'openai', 'ollama'].includes(v) ? null : `must be one of: anthropic, openai, ollama`,
|
|
400
|
-
'
|
|
438
|
+
'language': (v) => {
|
|
439
|
+
if (v.trim().length === 0)
|
|
440
|
+
return 'must not be blank — use `memesh config unset language` to clear it';
|
|
441
|
+
if (v.length > MAX_LANGUAGE_LENGTH)
|
|
442
|
+
return `must be ${MAX_LANGUAGE_LENGTH} characters or fewer (a language name or locale code)`;
|
|
443
|
+
return languageValueError(v);
|
|
444
|
+
},
|
|
445
|
+
'embedder.provider': (v) => ['openai', 'ollama'].includes(v) ? null : `must be one of: openai, ollama`,
|
|
401
446
|
'autoUpdate': (v) => ['off', 'patch', 'minor', 'major'].includes(v) ? null : `must be one of: off, patch, minor, major`,
|
|
402
447
|
'llmFallbacks': (v) => {
|
|
403
448
|
let parsed;
|
|
@@ -507,7 +552,7 @@ configCmd
|
|
|
507
552
|
coerced = parseInt(value, 10);
|
|
508
553
|
if (canonical === 'llmFallbacks')
|
|
509
554
|
coerced = JSON.parse(value);
|
|
510
|
-
if (canonical === '
|
|
555
|
+
if (canonical === 'autoCapture') {
|
|
511
556
|
coerced = value === 'true' || value === '1';
|
|
512
557
|
}
|
|
513
558
|
const config = readConfig();
|
|
@@ -515,6 +560,10 @@ configCmd
|
|
|
515
560
|
writeConfig(config);
|
|
516
561
|
const displayValue = canonical.toLowerCase().includes('key') ? maskApiKey(String(value)) : String(value);
|
|
517
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
|
+
}
|
|
518
567
|
});
|
|
519
568
|
configCmd
|
|
520
569
|
.command('unset')
|
|
@@ -583,10 +632,16 @@ program
|
|
|
583
632
|
.description('Start the HTTP API server and web dashboard')
|
|
584
633
|
.option('--port <port>', 'Port number', '3737')
|
|
585
634
|
.option('--host <host>', 'Host to bind', '127.0.0.1')
|
|
586
|
-
.option('--allow-remote', '
|
|
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.')
|
|
587
636
|
.action(async (opts) => {
|
|
588
637
|
const { startServer } = await import('../http/server.js');
|
|
589
|
-
|
|
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
|
+
}
|
|
590
645
|
});
|
|
591
646
|
program
|
|
592
647
|
.command('update')
|
|
@@ -632,6 +687,12 @@ program
|
|
|
632
687
|
.option('--prune <days>', 'Delete rows older than N days BEFORE rendering (closes v4.2.0 retention gap)', (v) => parseInt(v, 10))
|
|
633
688
|
.option('--json', 'Output as JSON')
|
|
634
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
|
+
}
|
|
635
696
|
await withDatabase(async () => {
|
|
636
697
|
const { summariseTelemetry, pruneTelemetry } = await import('../../core/llm-telemetry.js');
|
|
637
698
|
let pruneResult = null;
|
|
@@ -881,7 +942,107 @@ dreamCmd
|
|
|
881
942
|
.option('--max-llm-calls <n>', 'Hard cap on LLM calls (default 100)', (v) => parseInt(v, 10))
|
|
882
943
|
.option('--window-days <n>', 'Look-back window in days (default 56 = 8 weeks)', (v) => parseInt(v, 10))
|
|
883
944
|
.option('--validate', 'Run a second LLM pass to cross-check each digest against its sources (doubles LLM calls per proposal; surfaces under flow=digest_validator in `memesh telemetry`)')
|
|
945
|
+
.option('--from-transcripts', 'EXPERIMENTAL: mine Claude Code session transcripts for this project (decisions/lessons/facts hidden in the conversation) and STAGE them as proposals for `dream accept`, instead of clustering existing entities. Scoped to the current project only — --project does not apply here. With --dry-run, lists sessions and conversation-turn counts without calling an LLM.')
|
|
946
|
+
.option('--if-due', 'For a scheduler (cron/launchd): only mine if `transcriptMining` is enabled in config AND at least --min-interval-hours have passed since this project was last mined; otherwise exit 0 doing nothing. Lets one frequently-firing entry self-throttle. Only meaningful with --from-transcripts.')
|
|
947
|
+
.option('--min-interval-hours <n>', 'With --if-due: minimum hours between mined runs for this project (default 24).', (v) => parseInt(v, 10))
|
|
884
948
|
.action(async (opts) => {
|
|
949
|
+
if (opts.fromTranscripts) {
|
|
950
|
+
const windowDays = typeof opts.windowDays === 'number' && !Number.isNaN(opts.windowDays) ? opts.windowDays : 3;
|
|
951
|
+
if (opts.dryRun) {
|
|
952
|
+
const { scanTranscripts } = await import('../../core/transcript-source.js');
|
|
953
|
+
const { countConversationTurns } = await import('../../core/transcript-extractor.js');
|
|
954
|
+
const sessions = scanTranscripts({ windowDays });
|
|
955
|
+
console.log(`[dry-run] transcript sessions for this project in the last ${windowDays} day(s): ${sessions.length}`);
|
|
956
|
+
let totalTurns = 0;
|
|
957
|
+
for (const s of sessions) {
|
|
958
|
+
const turns = countConversationTurns(s.path);
|
|
959
|
+
totalTurns += turns;
|
|
960
|
+
console.log(` ${s.sessionId} ${turns} conversation turns ${s.lineCount} lines ${(s.sizeBytes / 1024).toFixed(0)}KB ${s.modifiedAt}`);
|
|
961
|
+
}
|
|
962
|
+
console.log(` total: ${totalTurns} conversation turns across ${sessions.length} session(s)`);
|
|
963
|
+
console.log('');
|
|
964
|
+
console.log('Run without --dry-run to extract high-value memories and stage them as proposals.');
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
if (opts.ifDue) {
|
|
968
|
+
const { isTranscriptMiningEnabled } = await import('../../core/config.js');
|
|
969
|
+
if (!isTranscriptMiningEnabled(readConfig())) {
|
|
970
|
+
console.log('Scheduled transcript mining is off (opt-in). Enable it with `memesh config set transcriptMining true`; this scheduled run will then start mining when due.');
|
|
971
|
+
return;
|
|
972
|
+
}
|
|
973
|
+
const { getProjectName } = await import('../../core/paths.js');
|
|
974
|
+
const { lastTranscriptMineAt, transcriptMiningDue } = await import('../../core/transcript-source.js');
|
|
975
|
+
const projectKey = getProjectName(process.cwd());
|
|
976
|
+
const intervalH = typeof opts.minIntervalHours === 'number' && !Number.isNaN(opts.minIntervalHours) ? opts.minIntervalHours : 24;
|
|
977
|
+
const last = lastTranscriptMineAt(projectKey);
|
|
978
|
+
if (!transcriptMiningDue(Date.now(), last, intervalH)) {
|
|
979
|
+
const agoH = last === null ? null : (Date.now() - last) / 3600_000;
|
|
980
|
+
console.log(`Not due yet: this project was mined ${agoH === null ? 'recently' : `${agoH.toFixed(1)}h ago`}; interval is ${intervalH}h. Nothing to do.`);
|
|
981
|
+
return;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
if (opts.project) {
|
|
985
|
+
console.log('note: --project does not scope --from-transcripts — the transcript source is always the current project. Ignoring --project.');
|
|
986
|
+
}
|
|
987
|
+
await withDatabase(async () => {
|
|
988
|
+
const { runTranscriptSource } = await import('../../core/transcript-extractor.js');
|
|
989
|
+
const { getDatabase } = await import('../../db.js');
|
|
990
|
+
const cfg = readConfig();
|
|
991
|
+
const llm = detectCapabilities().llm;
|
|
992
|
+
if (!llm) {
|
|
993
|
+
console.error('No LLM configured. Run `memesh config set llm.provider <anthropic|openai|ollama>` first (or set ANTHROPIC_API_KEY / OPENAI_API_KEY).');
|
|
994
|
+
console.error('LLM is required for `--from-transcripts` because extracting durable memory from prose is a semantic decision, not a rule.');
|
|
995
|
+
process.exit(1);
|
|
996
|
+
}
|
|
997
|
+
const result = await runTranscriptSource(getDatabase(), llm, {
|
|
998
|
+
windowDays,
|
|
999
|
+
maxLlmCalls: opts.maxLlmCalls,
|
|
1000
|
+
fallbacks: cfg.llmFallbacks,
|
|
1001
|
+
});
|
|
1002
|
+
const { getProjectName } = await import('../../core/paths.js');
|
|
1003
|
+
const { recordTranscriptMine } = await import('../../core/transcript-source.js');
|
|
1004
|
+
recordTranscriptMine(getProjectName(process.cwd()), Date.now());
|
|
1005
|
+
console.log(`Transcript mining complete in ${result.durationMs}ms`);
|
|
1006
|
+
console.log(` sessions scanned: ${result.sessionsScanned}`);
|
|
1007
|
+
console.log(` LLM calls: ${result.llmCalls}`);
|
|
1008
|
+
console.log(` candidates extracted: ${result.candidatesExtracted}`);
|
|
1009
|
+
console.log(` proposals created: ${result.proposalsCreated}`);
|
|
1010
|
+
if (result.duplicatesSkipped > 0)
|
|
1011
|
+
console.log(` duplicates skipped: ${result.duplicatesSkipped} (already a pending proposal)`);
|
|
1012
|
+
if (result.nearDuplicatesSkipped > 0) {
|
|
1013
|
+
console.log(` near-duplicates skipped: ${result.nearDuplicatesSkipped} candidate(s) skipped as near-duplicates of existing memories`);
|
|
1014
|
+
for (const d of result.nearDuplicates) {
|
|
1015
|
+
console.log(` - "${d.candidateName}" ~= existing "${d.matchedEntityName}" (distance ${d.distance.toFixed(3)})`);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
if (result.secretsDropped > 0)
|
|
1019
|
+
console.log(` secret-bearing candidates dropped: ${result.secretsDropped}`);
|
|
1020
|
+
if (result.llmFailures > 0)
|
|
1021
|
+
console.log(` LLM call failures: ${result.llmFailures} (sessions not mined — retry when the provider is reachable)`);
|
|
1022
|
+
if (result.parseFailures > 0)
|
|
1023
|
+
console.log(` unparsable replies: ${result.parseFailures} (chunk reply not valid JSON — likely truncated; those candidates were lost, retry)`);
|
|
1024
|
+
if (result.truncatedTurns > 0) {
|
|
1025
|
+
console.log(` size-cap truncation: ${result.truncatedTurns} conversation turn(s) beyond the cap were NOT analysed`);
|
|
1026
|
+
for (const t of result.truncatedSessions) {
|
|
1027
|
+
console.log(` - session ${t.sessionId}: ${t.truncatedTurns} tail turn(s) not analysed`);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
if (result.skipped.length > 0) {
|
|
1031
|
+
const reasonCounts = new Map();
|
|
1032
|
+
for (const s of result.skipped)
|
|
1033
|
+
reasonCounts.set(s.reason, (reasonCounts.get(s.reason) ?? 0) + 1);
|
|
1034
|
+
console.log(` skipped: ${result.skipped.length}`);
|
|
1035
|
+
for (const [reason, n] of reasonCounts)
|
|
1036
|
+
console.log(` - ${reason}${n > 1 ? ` (×${n})` : ''}`);
|
|
1037
|
+
}
|
|
1038
|
+
if (result.proposalsCreated > 0) {
|
|
1039
|
+
console.log('');
|
|
1040
|
+
console.log('Review with: memesh dream list');
|
|
1041
|
+
console.log('Accept: memesh dream accept <id>');
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
885
1046
|
await withDatabase(async () => {
|
|
886
1047
|
const { runDreamer } = await import('../../core/dreamer.js');
|
|
887
1048
|
const { getDatabase } = await import('../../db.js');
|
|
@@ -902,6 +1063,11 @@ dreamCmd
|
|
|
902
1063
|
});
|
|
903
1064
|
console.log(`${opts.dryRun ? '[dry-run] ' : ''}Dream pass complete in ${result.durationMs}ms`);
|
|
904
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}`);
|
|
905
1071
|
console.log(` LLM calls: ${result.llmCalls}`);
|
|
906
1072
|
console.log(` proposals created: ${result.proposalsCreated}`);
|
|
907
1073
|
if (result.skipped.length > 0) {
|
|
@@ -985,12 +1151,48 @@ dreamCmd
|
|
|
985
1151
|
console.log(`${proposals.length} ${opts.status} proposal(s):`);
|
|
986
1152
|
console.log('');
|
|
987
1153
|
for (const p of proposals) {
|
|
988
|
-
|
|
989
|
-
console.log(`
|
|
1154
|
+
const srcLabel = p.source_kind === 'transcript' ? ' (transcript)' : '';
|
|
1155
|
+
console.log(` #${p.id} [${p.project}/${p.cluster_key}]${srcLabel} ${p.source_count} source(s) → "${p.digest_name}"`);
|
|
1156
|
+
if (p.digest_observations_preview !== null) {
|
|
1157
|
+
console.log(` ${p.digest_observations_preview}`);
|
|
1158
|
+
}
|
|
990
1159
|
console.log(` created: ${p.created_at}`);
|
|
991
1160
|
console.log('');
|
|
992
1161
|
}
|
|
993
|
-
console.log(`Apply: memesh dream accept <id> | Reject: memesh dream reject <id>`);
|
|
1162
|
+
console.log(`Inspect: memesh dream show <id> | Apply: memesh dream accept <id> | Reject: memesh dream reject <id>`);
|
|
1163
|
+
});
|
|
1164
|
+
});
|
|
1165
|
+
dreamCmd
|
|
1166
|
+
.command('show <id>')
|
|
1167
|
+
.description('Show a proposal in full — name, type, ALL observations, tags, source — so you can review the whole thing before accepting')
|
|
1168
|
+
.option('--json', 'Output JSON')
|
|
1169
|
+
.action(async (id, opts) => {
|
|
1170
|
+
await withDatabase(async () => {
|
|
1171
|
+
const { getProposalDetail } = await import('../../core/dreamer.js');
|
|
1172
|
+
const { getDatabase } = await import('../../db.js');
|
|
1173
|
+
const detail = getProposalDetail(getDatabase(), parseInt(id, 10));
|
|
1174
|
+
if (!detail) {
|
|
1175
|
+
console.error(`proposal #${id} not found`);
|
|
1176
|
+
console.error('See ids with: memesh dream list');
|
|
1177
|
+
process.exit(1);
|
|
1178
|
+
}
|
|
1179
|
+
if (opts.json) {
|
|
1180
|
+
console.log(JSON.stringify(detail, null, 2));
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
console.log(`Proposal #${detail.id} [${detail.project}/${detail.cluster_key}] source: ${detail.source_kind} status: ${detail.status}`);
|
|
1184
|
+
console.log(`created: ${detail.created_at}`);
|
|
1185
|
+
console.log('');
|
|
1186
|
+
console.log(`name: ${detail.digest.name}`);
|
|
1187
|
+
console.log(`type: ${detail.digest.type}`);
|
|
1188
|
+
console.log(`observations (${detail.digest.observations.length}):`);
|
|
1189
|
+
for (const o of detail.digest.observations)
|
|
1190
|
+
console.log(` - ${o}`);
|
|
1191
|
+
if (detail.digest.tags.length > 0)
|
|
1192
|
+
console.log(`tags: ${detail.digest.tags.join(', ')}`);
|
|
1193
|
+
console.log(`source: ${JSON.stringify(detail.source)}`);
|
|
1194
|
+
console.log('');
|
|
1195
|
+
console.log(`Accept: memesh dream accept ${detail.id} | Reject: memesh dream reject ${detail.id}`);
|
|
994
1196
|
});
|
|
995
1197
|
});
|
|
996
1198
|
dreamCmd
|
|
@@ -1011,6 +1213,7 @@ dreamCmd
|
|
|
1011
1213
|
console.error('See pending ids with: memesh dream list');
|
|
1012
1214
|
process.exit(1);
|
|
1013
1215
|
}
|
|
1216
|
+
await flushPendingEmbeddings();
|
|
1014
1217
|
console.log(`Applied proposal #${result.proposalId}`);
|
|
1015
1218
|
console.log(` digest entity: ${result.digestEntityName}`);
|
|
1016
1219
|
console.log(` sources archived: ${result.sourcesArchived}`);
|
|
@@ -1063,6 +1266,9 @@ program
|
|
|
1063
1266
|
}
|
|
1064
1267
|
console.log(`${opts.dryRun ? '[dry-run] ' : ''}Settings: ${result.settingsPath}`);
|
|
1065
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
|
+
}
|
|
1066
1272
|
if (result.backupPath)
|
|
1067
1273
|
console.log(`Backup: ${result.backupPath}`);
|
|
1068
1274
|
if (result.conflicts.length > 0) {
|
|
@@ -1143,11 +1349,19 @@ program
|
|
|
1143
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._`;
|
|
1144
1350
|
}
|
|
1145
1351
|
}
|
|
1352
|
+
body = redactUserPaths(redactSecrets(body));
|
|
1146
1353
|
const url = `https://github.com/PCIRCLE-AI/memesh-llm-memory/issues/new?title=${encodeURIComponent(`[${typeLabel}] `)}&body=${encodeURIComponent(body)}&labels=${encodeURIComponent(labels)}`;
|
|
1147
1354
|
if (opts.open === false) {
|
|
1148
1355
|
console.log(url);
|
|
1149
1356
|
return;
|
|
1150
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
|
+
}
|
|
1151
1365
|
const { spawn } = await import('child_process');
|
|
1152
1366
|
const cmd = process.platform === 'darwin' ? 'open'
|
|
1153
1367
|
: process.platform === 'win32' ? 'cmd'
|
|
@@ -1173,6 +1387,7 @@ program
|
|
|
1173
1387
|
'stored embedding first. Needed only when switching embedding providers.')
|
|
1174
1388
|
.option('--json', 'Output as JSON')
|
|
1175
1389
|
.action(async (opts) => {
|
|
1390
|
+
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
1176
1391
|
try {
|
|
1177
1392
|
if (opts.fts) {
|
|
1178
1393
|
if (opts.vectors) {
|
|
@@ -1203,9 +1418,8 @@ program
|
|
|
1203
1418
|
console.error('❌ Could not produce a test embedding at this database\'s vector width, so\n' +
|
|
1204
1419
|
' the index was left untouched. Rebuilding it deletes every stored\n' +
|
|
1205
1420
|
' embedding, and nothing here could regenerate them.\n' +
|
|
1206
|
-
' Check that your OpenAI API key is valid
|
|
1207
|
-
'
|
|
1208
|
-
' again. `memesh doctor` reports which provider is configured.');
|
|
1421
|
+
' Check that Ollama is running (or that your OpenAI API key is valid) —\n' +
|
|
1422
|
+
' then run this again. `memesh doctor` reports which provider is configured.');
|
|
1209
1423
|
process.exit(1);
|
|
1210
1424
|
}
|
|
1211
1425
|
}
|
|
@@ -1258,33 +1472,6 @@ program
|
|
|
1258
1472
|
throw err;
|
|
1259
1473
|
}
|
|
1260
1474
|
});
|
|
1261
|
-
program
|
|
1262
|
-
.command('patterns')
|
|
1263
|
-
.description('Show local skill-usage telemetry (agentic-orchestration banner injections, verify_agent_work invocations). Local-only — never uploaded.')
|
|
1264
|
-
.option('--json', 'Output as JSON')
|
|
1265
|
-
.action(async (opts) => {
|
|
1266
|
-
const { summariseSkillUsage } = await import('../../core/skill-usage-log.js');
|
|
1267
|
-
const summary = summariseSkillUsage();
|
|
1268
|
-
if (opts.json) {
|
|
1269
|
-
console.log(JSON.stringify(summary, null, 2));
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
console.log(`Skill usage log: ${summary.log_path}`);
|
|
1273
|
-
console.log(` total events: ${summary.total_events}`);
|
|
1274
|
-
console.log(` log size: ${summary.log_bytes} bytes`);
|
|
1275
|
-
if (summary.first_event)
|
|
1276
|
-
console.log(` first event: ${summary.first_event}`);
|
|
1277
|
-
if (summary.last_event)
|
|
1278
|
-
console.log(` last event: ${summary.last_event}`);
|
|
1279
|
-
if (summary.total_events === 0) {
|
|
1280
|
-
console.log(' (no events recorded yet — open a Claude Code session with memesh installed, or run a verification, to start collecting)');
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
console.log(' events by name:');
|
|
1284
|
-
for (const [name, count] of Object.entries(summary.events_by_name).sort((a, b) => b[1] - a[1])) {
|
|
1285
|
-
console.log(` ${count.toString().padStart(6)} ${name}`);
|
|
1286
|
-
}
|
|
1287
|
-
});
|
|
1288
1475
|
program
|
|
1289
1476
|
.command('status')
|
|
1290
1477
|
.description('Show MeMesh status and capabilities')
|
|
@@ -1299,7 +1486,7 @@ program
|
|
|
1299
1486
|
console.log(`MeMesh v${pkg.version}`);
|
|
1300
1487
|
console.log(`Search level: ${caps.searchLevel} (${caps.searchLevel === 1 ? 'Smart Mode' : 'Core'})`);
|
|
1301
1488
|
console.log(`Embeddings: ${caps.embeddings}`);
|
|
1302
|
-
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'}`);
|
|
1303
1490
|
console.log(`Install method: ${installSupport.label}`);
|
|
1304
1491
|
for (const line of formatUpdateCheckStatus(update)) {
|
|
1305
1492
|
console.log(`\n${line}`);
|