@pcircle/memesh 4.6.1 → 4.7.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/README.de.md +22 -11
- package/README.md +22 -11
- package/README.zh-TW.md +21 -11
- package/dashboard/dist/index.html +6 -6
- package/dist/core/analytics.d.ts.map +1 -1
- package/dist/core/analytics.js +1 -1
- package/dist/core/analytics.js.map +1 -1
- package/dist/core/citation-rule.d.ts +24 -0
- package/dist/core/citation-rule.d.ts.map +1 -0
- package/dist/core/citation-rule.js +71 -0
- package/dist/core/citation-rule.js.map +1 -0
- package/dist/core/conflict-candidates.d.ts.map +1 -1
- package/dist/core/conflict-candidates.js +4 -12
- package/dist/core/conflict-candidates.js.map +1 -1
- package/dist/core/conflict-judge.d.ts +11 -0
- package/dist/core/conflict-judge.d.ts.map +1 -1
- package/dist/core/conflict-judge.js +1 -1
- package/dist/core/conflict-judge.js.map +1 -1
- package/dist/core/demo.d.ts.map +1 -1
- package/dist/core/demo.js +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 -3
- package/dist/core/digest-validator.js.map +1 -1
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +100 -16
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/dreamer.d.ts.map +1 -1
- package/dist/core/dreamer.js +10 -6
- package/dist/core/dreamer.js.map +1 -1
- package/dist/core/install-channel.d.ts +2 -1
- package/dist/core/install-channel.d.ts.map +1 -1
- package/dist/core/install-channel.js +11 -3
- package/dist/core/install-channel.js.map +1 -1
- package/dist/core/install-hooks.d.ts +6 -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.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.map +1 -1
- package/dist/core/lesson-engine.js +3 -3
- package/dist/core/lesson-engine.js.map +1 -1
- package/dist/core/lifecycle.js +2 -2
- package/dist/core/llm-client.d.ts.map +1 -1
- package/dist/core/llm-client.js +7 -3
- package/dist/core/llm-client.js.map +1 -1
- package/dist/core/llm-telemetry.d.ts.map +1 -1
- package/dist/core/llm-telemetry.js +5 -2
- package/dist/core/llm-telemetry.js.map +1 -1
- package/dist/core/operations.d.ts +2 -0
- package/dist/core/operations.d.ts.map +1 -1
- package/dist/core/operations.js +2 -2
- package/dist/core/operations.js.map +1 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +3 -2
- package/dist/core/paths.js.map +1 -1
- package/dist/core/patterns.d.ts +0 -5
- package/dist/core/patterns.d.ts.map +1 -1
- package/dist/core/patterns.js +1 -43
- package/dist/core/patterns.js.map +1 -1
- package/dist/core/schema-export.js +1 -1
- package/dist/core/schema-export.js.map +1 -1
- package/dist/core/serializer.d.ts.map +1 -1
- package/dist/core/serializer.js +47 -9
- package/dist/core/serializer.js.map +1 -1
- package/dist/core/signal-scorer.d.ts +0 -1
- package/dist/core/signal-scorer.d.ts.map +1 -1
- package/dist/core/signal-scorer.js +12 -8
- package/dist/core/signal-scorer.js.map +1 -1
- package/dist/core/transcript-extractor.d.ts +2 -0
- package/dist/core/transcript-extractor.d.ts.map +1 -1
- package/dist/core/transcript-extractor.js +10 -5
- package/dist/core/transcript-extractor.js.map +1 -1
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/updater.d.ts.map +1 -1
- package/dist/core/updater.js +1 -1
- package/dist/core/updater.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +1 -1
- package/dist/db.js.map +1 -1
- package/dist/knowledge-graph.d.ts +3 -1
- package/dist/knowledge-graph.d.ts.map +1 -1
- package/dist/knowledge-graph.js +44 -28
- package/dist/knowledge-graph.js.map +1 -1
- package/dist/skills-manifest.json +20 -15
- package/dist/storage/schema.d.ts.map +1 -1
- package/dist/storage/schema.js +18 -22
- package/dist/storage/schema.js.map +1 -1
- package/dist/storage/vector-index.d.ts.map +1 -1
- package/dist/storage/vector-index.js +10 -4
- package/dist/storage/vector-index.js.map +1 -1
- package/dist/transports/cli/cli.js +105 -45
- package/dist/transports/cli/cli.js.map +1 -1
- package/dist/transports/http/server.d.ts.map +1 -1
- package/dist/transports/http/server.js +56 -1
- package/dist/transports/http/server.js.map +1 -1
- package/dist/transports/mcp/handlers.d.ts +2 -2
- package/dist/transports/mcp/handlers.d.ts.map +1 -1
- package/dist/transports/mcp/handlers.js +15 -15
- package/dist/transports/mcp/handlers.js.map +1 -1
- package/dist/transports/schemas.d.ts +0 -1
- package/dist/transports/schemas.d.ts.map +1 -1
- package/dist/transports/schemas.js +2 -2
- package/dist/transports/schemas.js.map +1 -1
- package/hooks/hooks.json +4 -2
- package/llms-install.md +28 -0
- package/package.json +3 -2
- package/scripts/hooks/_generated/citation-rule.js +78 -0
- package/scripts/hooks/_generated/core-paths.js +3 -2
- package/scripts/hooks/_generated/schema.js +18 -22
- package/scripts/hooks/_shared.js +73 -4
- package/scripts/hooks/pre-compact.js +14 -7
- package/scripts/hooks/session-start.js +61 -2
- package/scripts/hooks/session-summary.js +41 -4
- package/scripts/upgrade-plugin.sh +9 -1
|
@@ -17,14 +17,56 @@ import { installHooks } from '../../core/install-hooks.js';
|
|
|
17
17
|
import { getTaskState, setTaskState } from '../../core/task-state-store.js';
|
|
18
18
|
import { TASK_STATE_FIELDS, taskStateLines } from '../../core/task-state.js';
|
|
19
19
|
async function withDatabase(fn) {
|
|
20
|
-
|
|
20
|
+
try {
|
|
21
|
+
openDatabase();
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
25
|
+
console.error(`Error: memesh cannot open its database.`);
|
|
26
|
+
console.error(` ${message}`);
|
|
27
|
+
console.error(` Run \`memesh doctor\` — it names the file, the likely cause and the way back.`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
21
30
|
try {
|
|
22
31
|
return await fn();
|
|
23
32
|
}
|
|
24
33
|
finally {
|
|
34
|
+
await flushPendingEmbeddings();
|
|
25
35
|
closeDatabase();
|
|
26
36
|
}
|
|
27
37
|
}
|
|
38
|
+
function unitFraction(flag) {
|
|
39
|
+
return (value) => {
|
|
40
|
+
const parsed = Number(value);
|
|
41
|
+
if (!Number.isFinite(parsed) || parsed < 0 || parsed > 1) {
|
|
42
|
+
console.error(`Error: ${flag} needs a number between 0 and 1, not "${value}".`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
return parsed;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function nonEmpty(flag) {
|
|
49
|
+
return (value) => {
|
|
50
|
+
if (value.trim() === '') {
|
|
51
|
+
console.error(`Error: ${flag} needs some text. An empty value is not a selector.`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function proposalId(raw) {
|
|
58
|
+
return wholeNumber('<id>')(raw);
|
|
59
|
+
}
|
|
60
|
+
function wholeNumber(flag, min = 1) {
|
|
61
|
+
return (value) => {
|
|
62
|
+
const parsed = Number(value);
|
|
63
|
+
if (!Number.isInteger(parsed) || parsed < min) {
|
|
64
|
+
console.error(`Error: ${flag} needs a whole number of ${min} or more, not "${value}".`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
return parsed;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
28
70
|
function requireOneOf(value, allowed, flag) {
|
|
29
71
|
if (value === undefined || allowed.includes(value))
|
|
30
72
|
return;
|
|
@@ -143,7 +185,6 @@ program
|
|
|
143
185
|
}
|
|
144
186
|
if (result.relationErrors?.length)
|
|
145
187
|
process.exitCode = 1;
|
|
146
|
-
await flushPendingEmbeddings();
|
|
147
188
|
});
|
|
148
189
|
});
|
|
149
190
|
program
|
|
@@ -151,7 +192,7 @@ program
|
|
|
151
192
|
.description('Search stored knowledge')
|
|
152
193
|
.argument('[query]', 'Search query')
|
|
153
194
|
.option('--tag <tag>', 'Filter by tag')
|
|
154
|
-
.option('--limit <n>', 'Max results', '
|
|
195
|
+
.option('--limit <n>', 'Max results', wholeNumber('--limit'), 20)
|
|
155
196
|
.option('--include-archived', 'Include archived entities')
|
|
156
197
|
.option('--namespace <namespace>', 'Filter by namespace: personal, team, or global')
|
|
157
198
|
.option('--cross-project', 'Search across all project tags (ignores --tag filter)')
|
|
@@ -162,7 +203,7 @@ program
|
|
|
162
203
|
const { entities, conflicts, retrieval } = await recallWithConflicts({
|
|
163
204
|
query: query || undefined,
|
|
164
205
|
tag: opts.tag,
|
|
165
|
-
limit:
|
|
206
|
+
limit: opts.limit,
|
|
166
207
|
include_archived: opts.includeArchived,
|
|
167
208
|
namespace: opts.namespace,
|
|
168
209
|
cross_project: opts.crossProject,
|
|
@@ -216,7 +257,7 @@ program
|
|
|
216
257
|
.command('forget')
|
|
217
258
|
.description('Archive an entity or remove an observation (soft-delete, recoverable)')
|
|
218
259
|
.requiredOption('--name <name>', 'Entity name')
|
|
219
|
-
.option('--observation <text>', 'Remove specific observation only')
|
|
260
|
+
.option('--observation <text>', 'Remove specific observation only', nonEmpty('--observation'))
|
|
220
261
|
.option('--json', 'Output as JSON')
|
|
221
262
|
.option('--confirm', '[deprecated, no-op] forget is a soft archive — no confirmation needed')
|
|
222
263
|
.action(async (opts) => {
|
|
@@ -234,7 +275,7 @@ program
|
|
|
234
275
|
else if (result.observation_removed) {
|
|
235
276
|
console.log(`✂️ Removed observation (${result.remaining_observations} remaining)`);
|
|
236
277
|
}
|
|
237
|
-
else if (opts.observation && result.entity_found) {
|
|
278
|
+
else if (opts.observation !== undefined && result.entity_found) {
|
|
238
279
|
console.log(`Entity "${opts.name}" has no observation matching that text (${result.remaining_observations} observation(s) present).`);
|
|
239
280
|
console.log(`See them with: memesh recall "${opts.name}" --json`);
|
|
240
281
|
process.exitCode = 1;
|
|
@@ -316,7 +357,7 @@ program
|
|
|
316
357
|
.description('Export memories as JSON. Defaults to stdout (pipe-friendly); use `-o <file>` to write directly.')
|
|
317
358
|
.option('--tag <tag>', 'Export only entities with this tag')
|
|
318
359
|
.option('--namespace <ns>', 'Export only from this namespace (personal, team, global)')
|
|
319
|
-
.option('--limit <n>', 'Max entities to export', '
|
|
360
|
+
.option('--limit <n>', 'Max entities to export', wholeNumber('--limit'), 1000)
|
|
320
361
|
.option('-o, --out <file>', 'Write JSON to <file> instead of stdout. Parent directory must exist.')
|
|
321
362
|
.action(async (opts) => {
|
|
322
363
|
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
@@ -324,7 +365,7 @@ program
|
|
|
324
365
|
const result = exportMemories({
|
|
325
366
|
tag: opts.tag,
|
|
326
367
|
namespace: opts.namespace,
|
|
327
|
-
limit:
|
|
368
|
+
limit: opts.limit,
|
|
328
369
|
});
|
|
329
370
|
const json = JSON.stringify(result, null, 2);
|
|
330
371
|
if (opts.out) {
|
|
@@ -340,6 +381,10 @@ program
|
|
|
340
381
|
else {
|
|
341
382
|
console.log(json);
|
|
342
383
|
}
|
|
384
|
+
if (result.truncated) {
|
|
385
|
+
process.stderr.write(`⚠️ This is NOT the whole graph — ${result.entity_count} entities is the --limit, and there are more.\n`
|
|
386
|
+
+ ` For a full backup, raise it: memesh export --limit 100000${opts.out ? ` -o ${opts.out}` : ''}\n`);
|
|
387
|
+
}
|
|
343
388
|
});
|
|
344
389
|
});
|
|
345
390
|
program
|
|
@@ -395,6 +440,11 @@ program
|
|
|
395
440
|
process.exit(1);
|
|
396
441
|
}
|
|
397
442
|
console.log(`Imported: ${result.imported}, Skipped: ${result.skipped}, Appended: ${result.appended}`);
|
|
443
|
+
if (result.skipped_relations.length > 0) {
|
|
444
|
+
console.error(`Note: ${result.skipped_relations.length} relation(s) not restored — the target is not in this bundle:\n `
|
|
445
|
+
+ `${result.skipped_relations.join('\n ')}`);
|
|
446
|
+
console.error(` Export those entities too (widen --limit, or drop --tag/--namespace) to keep the links.`);
|
|
447
|
+
}
|
|
398
448
|
if (result.errors.length > 0) {
|
|
399
449
|
console.error(`Errors:\n ${result.errors.join('\n ')}`);
|
|
400
450
|
process.exitCode = 1;
|
|
@@ -464,21 +514,15 @@ program
|
|
|
464
514
|
.command('why')
|
|
465
515
|
.description('Explain a file: commits memesh remembers touching it, their sessions, and related memories')
|
|
466
516
|
.argument('<file>', 'File path (relative to the current directory or absolute)')
|
|
467
|
-
.option('--line <n>', 'Attribute one line via git blame instead of file history')
|
|
468
|
-
.option('--limit <n>', 'Max commits to inspect', '
|
|
517
|
+
.option('--line <n>', 'Attribute one line via git blame instead of file history', wholeNumber('--line'))
|
|
518
|
+
.option('--limit <n>', 'Max commits to inspect', wholeNumber('--limit'), 10)
|
|
469
519
|
.option('--json', 'Output as JSON')
|
|
470
520
|
.action(async (file, opts) => {
|
|
471
521
|
await withDatabase(async () => {
|
|
472
522
|
const { resolveFileCommits, explainCommits } = await import('../../core/why.js');
|
|
473
523
|
const cwd = process.cwd();
|
|
474
|
-
const limit =
|
|
475
|
-
const line = opts.line
|
|
476
|
-
for (const [flag, value] of [['--limit', limit], ['--line', line]]) {
|
|
477
|
-
if (value !== undefined && (!Number.isInteger(value) || value < 1)) {
|
|
478
|
-
console.error(`Error: ${flag} needs a whole number of 1 or more.`);
|
|
479
|
-
process.exit(1);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
524
|
+
const limit = opts.limit;
|
|
525
|
+
const line = opts.line;
|
|
482
526
|
const resolved = resolveFileCommits(cwd, file, { line, limit });
|
|
483
527
|
const result = explainCommits(getDatabase(), {
|
|
484
528
|
file,
|
|
@@ -631,7 +675,7 @@ program
|
|
|
631
675
|
.option('--done <text>', 'What was just finished')
|
|
632
676
|
.option('--json', 'Output as JSON')
|
|
633
677
|
.action(async (opts) => {
|
|
634
|
-
await withDatabase(() => {
|
|
678
|
+
await withDatabase(async () => {
|
|
635
679
|
const patch = {};
|
|
636
680
|
for (const field of TASK_STATE_FIELDS) {
|
|
637
681
|
if (opts[field] !== undefined)
|
|
@@ -813,8 +857,9 @@ configCmd
|
|
|
813
857
|
}
|
|
814
858
|
}
|
|
815
859
|
let coerced = value;
|
|
816
|
-
if (canonical === 'sessionLimit')
|
|
817
|
-
coerced =
|
|
860
|
+
if (canonical === 'sessionLimit') {
|
|
861
|
+
coerced = wholeNumber('sessionLimit')(value);
|
|
862
|
+
}
|
|
818
863
|
if (canonical === 'llmFallbacks')
|
|
819
864
|
coerced = JSON.parse(value);
|
|
820
865
|
if (canonical === 'autoCapture') {
|
|
@@ -898,13 +943,13 @@ program
|
|
|
898
943
|
program
|
|
899
944
|
.command('serve')
|
|
900
945
|
.description('Start the HTTP API server and web dashboard')
|
|
901
|
-
.option('--port <port>', 'Port number', '
|
|
946
|
+
.option('--port <port>', 'Port number', wholeNumber('--port', 0), 3737)
|
|
902
947
|
.option('--host <host>', 'Host to bind', '127.0.0.1')
|
|
903
948
|
.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.')
|
|
904
949
|
.action(async (opts) => {
|
|
905
950
|
const { startServer } = await import('../http/server.js');
|
|
906
951
|
try {
|
|
907
|
-
startServer(opts.host,
|
|
952
|
+
startServer(opts.host, opts.port, { allowRemote: opts.allowRemote, autoUpdateCheck: true });
|
|
908
953
|
}
|
|
909
954
|
catch (err) {
|
|
910
955
|
console.error(`MeMesh: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -998,16 +1043,10 @@ program
|
|
|
998
1043
|
program
|
|
999
1044
|
.command('telemetry')
|
|
1000
1045
|
.description('Show LLM call telemetry (per-flow scorecard for the last N days)')
|
|
1001
|
-
.option('--window <days>', 'Look-back window in days (default 30)', (
|
|
1002
|
-
.option('--prune <days>', 'Delete rows older than N days BEFORE rendering (closes v4.2.0 retention gap)', (
|
|
1046
|
+
.option('--window <days>', 'Look-back window in days (default 30)', wholeNumber('--window'), 30)
|
|
1047
|
+
.option('--prune <days>', 'Delete rows older than N days BEFORE rendering (closes v4.2.0 retention gap)', wholeNumber('--prune', 0))
|
|
1003
1048
|
.option('--json', 'Output as JSON')
|
|
1004
1049
|
.action(async (opts) => {
|
|
1005
|
-
for (const [flag, value] of [['--window', opts.window], ['--prune', opts.prune]]) {
|
|
1006
|
-
if (value !== undefined && !Number.isFinite(value)) {
|
|
1007
|
-
console.error(`Error: ${flag} needs a number of days.`);
|
|
1008
|
-
process.exit(1);
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
1050
|
await withDatabase(async () => {
|
|
1012
1051
|
const { summariseTelemetry, pruneTelemetry } = await import('../../core/llm-telemetry.js');
|
|
1013
1052
|
let pruneResult = null;
|
|
@@ -1074,12 +1113,12 @@ kgCmd
|
|
|
1074
1113
|
.description('Propose / apply heuristic relations to connect orphan entities (no LLM)')
|
|
1075
1114
|
.option('--project <name>', 'Restrict to one project')
|
|
1076
1115
|
.option('--dry-run', 'Show proposals without writing (default off — use to preview)')
|
|
1077
|
-
.option('--max-per-source <n>', 'Max edges per orphan (default 3)', (
|
|
1078
|
-
.option('--min-shared-tags <n>', 'Min shared topical tags to gate co-occurrence rule (default 2)', (
|
|
1116
|
+
.option('--max-per-source <n>', 'Max edges per orphan (default 3)', wholeNumber('--max-per-source'), 3)
|
|
1117
|
+
.option('--min-shared-tags <n>', 'Min shared topical tags to gate co-occurrence rule (default 2)', wholeNumber('--min-shared-tags'), 2)
|
|
1079
1118
|
.option('--include-archived', 'Also process archived entities')
|
|
1080
1119
|
.option('--session-cooccurrence', 'Rule 3: link high-signal orphans co-created in the same session')
|
|
1081
1120
|
.option('--name-tokens', 'Rule 4: link orphans sharing ≥3 name content tokens (or Jaccard ≥ 0.50)')
|
|
1082
|
-
.option('--min-jaccard <n>', 'Jaccard threshold for name similarity (default 0.50)',
|
|
1121
|
+
.option('--min-jaccard <n>', 'Jaccard threshold for name similarity (default 0.50)', unitFraction('--min-jaccard'))
|
|
1083
1122
|
.option('--all-rules', 'Enable all heuristic rules (Rules 1–5)')
|
|
1084
1123
|
.option('--no-evidence-links', 'Disable Rule 5: evidence → work-item links via shared session id (on by default — these edges feed the graph\'s evidence badges)')
|
|
1085
1124
|
.option('--reset-idempotency', 'Clear the persistent "already-attempted" orphan cache before running (use after schema changes or to reconsider every orphan)')
|
|
@@ -1324,12 +1363,12 @@ dreamCmd
|
|
|
1324
1363
|
.description('Run a dream pass — propose digests for clusters of compactable entities')
|
|
1325
1364
|
.option('--project <name>', 'Restrict to one project')
|
|
1326
1365
|
.option('--dry-run', 'Compute proposals without writing to dream_proposals')
|
|
1327
|
-
.option('--max-llm-calls <n>', 'Hard cap on LLM calls (default 100)', (
|
|
1328
|
-
.option('--window-days <n>', 'Look-back window in days (default 56 = 8 weeks)', (
|
|
1366
|
+
.option('--max-llm-calls <n>', 'Hard cap on LLM calls (default 100)', wholeNumber('--max-llm-calls'))
|
|
1367
|
+
.option('--window-days <n>', 'Look-back window in days (default 56 = 8 weeks)', wholeNumber('--window-days'))
|
|
1329
1368
|
.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`)')
|
|
1330
1369
|
.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.')
|
|
1331
1370
|
.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.')
|
|
1332
|
-
.option('--min-interval-hours <n>', 'With --if-due: minimum hours between mined runs for this project (default 24).', (
|
|
1371
|
+
.option('--min-interval-hours <n>', 'With --if-due: minimum hours between mined runs for this project (default 24).', wholeNumber('--min-interval-hours'))
|
|
1333
1372
|
.action(async (opts) => {
|
|
1334
1373
|
if (opts.fromTranscripts) {
|
|
1335
1374
|
const windowDays = typeof opts.windowDays === 'number' && !Number.isNaN(opts.windowDays) ? opts.windowDays : 3;
|
|
@@ -1406,6 +1445,10 @@ dreamCmd
|
|
|
1406
1445
|
console.log(` LLM call failures: ${result.llmFailures} (sessions not mined — retry when the provider is reachable)`);
|
|
1407
1446
|
if (result.parseFailures > 0)
|
|
1408
1447
|
console.log(` unparsable replies: ${result.parseFailures} (chunk reply not valid JSON — likely truncated; those candidates were lost, retry)`);
|
|
1448
|
+
if (result.cappedTurns > 0) {
|
|
1449
|
+
console.log(` per-turn cap: ${result.cappedTurns} turn(s) were analysed only in part `
|
|
1450
|
+
+ `(the first 4,000 characters); the rest of each was not sent`);
|
|
1451
|
+
}
|
|
1409
1452
|
if (result.truncatedTurns > 0) {
|
|
1410
1453
|
console.log(` size-cap truncation: ${result.truncatedTurns} conversation turn(s) beyond the cap were NOT analysed`);
|
|
1411
1454
|
for (const t of result.truncatedSessions) {
|
|
@@ -1477,9 +1520,9 @@ dreamCmd
|
|
|
1477
1520
|
.description('Run pattern detector — surface emerging patterns/conventions/repeated mistakes per project (Phase 3)')
|
|
1478
1521
|
.option('--project <name>', 'Restrict to one project (default: all projects)')
|
|
1479
1522
|
.option('--dry-run', 'Compute proposals without writing to dream_proposals')
|
|
1480
|
-
.option('--max-llm-calls <n>', 'Hard cap on LLM calls (default 10)', (
|
|
1481
|
-
.option('--window-days <n>', 'Look-back window in days (default 30)', (
|
|
1482
|
-
.option('--min-signal <n>', 'Minimum signal_score to include in scan (default 0.3)', (
|
|
1523
|
+
.option('--max-llm-calls <n>', 'Hard cap on LLM calls (default 10)', wholeNumber('--max-llm-calls'))
|
|
1524
|
+
.option('--window-days <n>', 'Look-back window in days (default 30)', wholeNumber('--window-days'))
|
|
1525
|
+
.option('--min-signal <n>', 'Minimum signal_score to include in scan (default 0.3)', unitFraction('--min-signal'))
|
|
1483
1526
|
.action(async (opts) => {
|
|
1484
1527
|
await withDatabase(async () => {
|
|
1485
1528
|
const { runPatternDetector } = await import('../../core/dreamer.js');
|
|
@@ -1551,7 +1594,7 @@ dreamCmd
|
|
|
1551
1594
|
dreamCmd
|
|
1552
1595
|
.command('conflicts')
|
|
1553
1596
|
.description('Judge semantically-close memory pairs for contradiction / supersession / duplication (LLM) and stage relation proposals for review')
|
|
1554
|
-
.option('--max-pairs <n>', 'Judge at most N of the tightest candidate pairs this run (default 20)', (
|
|
1597
|
+
.option('--max-pairs <n>', 'Judge at most N of the tightest candidate pairs this run (default 20)', wholeNumber('--max-pairs'))
|
|
1555
1598
|
.option('--dry-run', 'Show how many candidates are queued without calling an LLM or writing anything')
|
|
1556
1599
|
.action(async (opts) => {
|
|
1557
1600
|
await withDatabase(async () => {
|
|
@@ -1599,7 +1642,7 @@ dreamCmd
|
|
|
1599
1642
|
await withDatabase(async () => {
|
|
1600
1643
|
const { getProposalDetail } = await import('../../core/dreamer.js');
|
|
1601
1644
|
const { getDatabase } = await import('../../db.js');
|
|
1602
|
-
const detail = getProposalDetail(getDatabase(),
|
|
1645
|
+
const detail = getProposalDetail(getDatabase(), proposalId(id));
|
|
1603
1646
|
if (!detail) {
|
|
1604
1647
|
console.error(`proposal #${id} not found`);
|
|
1605
1648
|
console.error('See ids with: memesh dream list');
|
|
@@ -1660,14 +1703,13 @@ dreamCmd
|
|
|
1660
1703
|
const kg = new KnowledgeGraph(getDatabase());
|
|
1661
1704
|
let result;
|
|
1662
1705
|
try {
|
|
1663
|
-
result = applyProposal(getDatabase(),
|
|
1706
|
+
result = applyProposal(getDatabase(), proposalId(id), kg);
|
|
1664
1707
|
}
|
|
1665
1708
|
catch (err) {
|
|
1666
1709
|
console.error(err instanceof Error ? err.message : String(err));
|
|
1667
1710
|
console.error('See pending ids with: memesh dream list');
|
|
1668
1711
|
process.exit(1);
|
|
1669
1712
|
}
|
|
1670
|
-
await flushPendingEmbeddings();
|
|
1671
1713
|
console.log(`Applied proposal #${result.proposalId}`);
|
|
1672
1714
|
console.log(` digest entity: ${result.digestEntityName}`);
|
|
1673
1715
|
console.log(` sources archived: ${result.sourcesArchived}`);
|
|
@@ -1682,7 +1724,7 @@ dreamCmd
|
|
|
1682
1724
|
const { rejectProposal } = await import('../../core/dreamer.js');
|
|
1683
1725
|
const { getDatabase } = await import('../../db.js');
|
|
1684
1726
|
try {
|
|
1685
|
-
rejectProposal(getDatabase(),
|
|
1727
|
+
rejectProposal(getDatabase(), proposalId(id), opts.reason);
|
|
1686
1728
|
}
|
|
1687
1729
|
catch (err) {
|
|
1688
1730
|
console.error(err instanceof Error ? err.message : String(err));
|
|
@@ -1716,6 +1758,15 @@ program
|
|
|
1716
1758
|
console.log('Hooks are active. Verify with: memesh doctor');
|
|
1717
1759
|
console.log('');
|
|
1718
1760
|
console.log('If you really want a second copy in ~/.claude/settings.json on top of the plugin, re-run with --force-over-plugin. (Not recommended — every session-start / Stop / PreToolUse event will fire memesh\'s hooks twice.)');
|
|
1761
|
+
if (result.citationRule.action === 'foreign-file') {
|
|
1762
|
+
console.log('');
|
|
1763
|
+
console.log(`WARNING: the citation contract was NOT installed — a file memesh did not write already exists at ${result.citationRule.path}.`);
|
|
1764
|
+
console.log(' memesh will not overwrite it. Move or rename that file and re-run, or add the contract to it by hand.');
|
|
1765
|
+
console.log(' Until then, memesh cannot tell whether the memories it injects are ever used.');
|
|
1766
|
+
}
|
|
1767
|
+
else if (result.citationRule.action !== 'unchanged') {
|
|
1768
|
+
console.log(`Citation contract ${result.citationRule.action}: ${result.citationRule.path}`);
|
|
1769
|
+
}
|
|
1719
1770
|
return;
|
|
1720
1771
|
}
|
|
1721
1772
|
console.log(`${opts.dryRun ? '[dry-run] ' : ''}Settings: ${result.settingsPath}`);
|
|
@@ -1725,6 +1776,15 @@ program
|
|
|
1725
1776
|
}
|
|
1726
1777
|
if (result.backupPath)
|
|
1727
1778
|
console.log(`Backup: ${result.backupPath}`);
|
|
1779
|
+
if (result.citationRule.action === 'foreign-file') {
|
|
1780
|
+
console.log('');
|
|
1781
|
+
console.log(`WARNING: the citation contract was NOT installed — a file memesh did not write already exists at ${result.citationRule.path}.`);
|
|
1782
|
+
console.log(' memesh will not overwrite it. Move or rename that file and re-run, or add the contract to it by hand.');
|
|
1783
|
+
console.log(' Until then, memesh cannot tell whether the memories it injects are ever used.');
|
|
1784
|
+
}
|
|
1785
|
+
else if (result.citationRule.action !== 'unchanged') {
|
|
1786
|
+
console.log(`Citation contract ${result.citationRule.action}: ${result.citationRule.path}`);
|
|
1787
|
+
}
|
|
1728
1788
|
if (result.conflicts.length > 0) {
|
|
1729
1789
|
console.log('');
|
|
1730
1790
|
console.log('Note: memesh hooks now coexist with the following pre-existing entries:');
|