@pcircle/memesh 4.3.0 → 4.5.0
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 +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/README.de.md +35 -12
- package/README.es.md +13 -9
- package/README.fr.md +33 -10
- package/README.ja.md +13 -9
- package/README.ko.md +14 -10
- package/README.md +18 -11
- package/README.pt.md +32 -9
- package/README.th.md +18 -8
- package/README.vi.md +34 -11
- package/README.zh-CN.md +14 -10
- package/README.zh-TW.md +14 -10
- package/dashboard/dist/index.html +10 -10
- package/dist/cli/view-live.js +2 -2
- package/dist/cli/view.js +1 -1
- package/dist/core/analytics.d.ts +4 -0
- 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 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +28 -13
- package/dist/core/config.js.map +1 -1
- package/dist/core/demo.d.ts +1 -0
- package/dist/core/demo.d.ts.map +1 -1
- package/dist/core/demo.js +24 -0
- 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 +2 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +70 -60
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/dreamer.d.ts +21 -1
- package/dist/core/dreamer.d.ts.map +1 -1
- package/dist/core/dreamer.js +86 -8
- package/dist/core/dreamer.js.map +1 -1
- package/dist/core/embedder.d.ts +1 -4
- package/dist/core/embedder.d.ts.map +1 -1
- package/dist/core/embedder.js +5 -92
- package/dist/core/embedder.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/llm-client.d.ts.map +1 -1
- package/dist/core/llm-client.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/operations.d.ts.map +1 -1
- package/dist/core/operations.js +10 -3
- 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/patterns.d.ts +0 -1
- 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/transcript-extractor.d.ts +89 -0
- package/dist/core/transcript-extractor.d.ts.map +1 -0
- package/dist/core/transcript-extractor.js +437 -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 +4 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/verifier.js +1 -1
- package/dist/core/verifier.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +10 -0
- package/dist/db.js.map +1 -1
- package/dist/skills-manifest.json +11 -11
- package/dist/transports/cli/cli.d.ts.map +1 -1
- package/dist/transports/cli/cli.js +229 -65
- package/dist/transports/cli/cli.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 +145 -50
- package/dist/transports/http/server.js.map +1 -1
- package/dist/transports/mcp/handlers.d.ts +1 -1
- package/dist/transports/mcp/handlers.d.ts.map +1 -1
- package/dist/transports/mcp/handlers.js +3 -2
- package/dist/transports/mcp/handlers.js.map +1 -1
- package/dist/transports/schemas.d.ts.map +1 -1
- package/dist/transports/schemas.js.map +1 -1
- package/package.json +2 -11
- package/scripts/hooks/post-commit.js +8 -2
- package/scripts/hooks/pre-compact.js +9 -0
- package/scripts/hooks/session-start.js +1 -1
- package/skills/agentic-orchestration/SKILL.md +1 -1
- package/skills/memesh/SKILL.md +2 -0
|
@@ -8,6 +8,7 @@ import { openDatabase, closeDatabase, getDatabase, reindexFts, allowVectorIndexR
|
|
|
8
8
|
import { remember, recallWithConflicts, forget, exportMemories, importMemories, learn, reindex, setPinned } from '../../core/operations.js';
|
|
9
9
|
import { verifyAgentWork } from '../../core/verifier.js';
|
|
10
10
|
import { readConfig, writeConfig, maskApiKey, detectCapabilities } from '../../core/config.js';
|
|
11
|
+
import { MAX_LANGUAGE_LENGTH, languageValueError } from '../../core/output-language.js';
|
|
11
12
|
import { getDbPath } from '../../core/paths.js';
|
|
12
13
|
import { flushPendingEmbeddings, canRefillVectorIndex } from '../../core/embedder.js';
|
|
13
14
|
async function withDatabase(fn) {
|
|
@@ -52,6 +53,14 @@ program
|
|
|
52
53
|
opts.type = 'note';
|
|
53
54
|
if (!opts.obs || opts.obs.length === 0)
|
|
54
55
|
opts.obs = [String(text)];
|
|
56
|
+
else
|
|
57
|
+
opts.obs = [...opts.obs, String(text)];
|
|
58
|
+
}
|
|
59
|
+
else if (text) {
|
|
60
|
+
if (!opts.obs || opts.obs.length === 0)
|
|
61
|
+
opts.obs = [String(text)];
|
|
62
|
+
else
|
|
63
|
+
opts.obs = [...opts.obs, String(text)];
|
|
55
64
|
}
|
|
56
65
|
if (!opts.name || !opts.type) {
|
|
57
66
|
console.error('Error: provide --name and --type, OR pass quick-capture text as a positional arg.\n' +
|
|
@@ -108,11 +117,25 @@ program
|
|
|
108
117
|
console.log('No results found.');
|
|
109
118
|
}
|
|
110
119
|
else {
|
|
120
|
+
const allSemantic = query && entities.every((e) => e.match?.source === 'semantic');
|
|
121
|
+
if (allSemantic) {
|
|
122
|
+
console.log('No keyword matches. Closest memories by meaning — may be unrelated:');
|
|
123
|
+
}
|
|
111
124
|
for (const e of entities) {
|
|
112
125
|
const badge = e.archived ? ' [archived]' : '';
|
|
113
|
-
|
|
126
|
+
const semantic = e.match?.source === 'semantic'
|
|
127
|
+
? ` (~${Math.round((e.match.relevance ?? 0) * 100)}% semantic)`
|
|
128
|
+
: '';
|
|
129
|
+
console.log(` ${e.name}${badge} (${e.type})${semantic}`);
|
|
114
130
|
for (const obs of e.observations.slice(0, 3)) {
|
|
115
|
-
|
|
131
|
+
let shown = obs;
|
|
132
|
+
if (obs.length > 500) {
|
|
133
|
+
let head = obs.slice(0, 500);
|
|
134
|
+
if (/[\uD800-\uDBFF]$/.test(head))
|
|
135
|
+
head = head.slice(0, -1);
|
|
136
|
+
shown = `${head} … (+${obs.length - head.length} more chars)`;
|
|
137
|
+
}
|
|
138
|
+
console.log(` - ${shown}`);
|
|
116
139
|
}
|
|
117
140
|
if (e.observations.length > 3) {
|
|
118
141
|
console.log(` ... +${e.observations.length - 3} more`);
|
|
@@ -168,6 +191,8 @@ function registerPinCommand(name, description, pinned, onFound) {
|
|
|
168
191
|
console.log(JSON.stringify(result));
|
|
169
192
|
else
|
|
170
193
|
console.log(result.found ? onFound(opts.name) : `Entity "${opts.name}" not found`);
|
|
194
|
+
if (!result.found)
|
|
195
|
+
process.exitCode = 1;
|
|
171
196
|
});
|
|
172
197
|
});
|
|
173
198
|
}
|
|
@@ -306,17 +331,25 @@ program
|
|
|
306
331
|
.action(async (workdir, opts) => {
|
|
307
332
|
await withDatabase(() => {
|
|
308
333
|
let externalReport;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
+
}
|
|
320
353
|
if (opts.json) {
|
|
321
354
|
console.log(JSON.stringify(result, null, 2));
|
|
322
355
|
}
|
|
@@ -362,10 +395,18 @@ const ALLOWED_KEYS = new Set([
|
|
|
362
395
|
'enableAgenticOrchestration',
|
|
363
396
|
'autoCapture',
|
|
364
397
|
'llmFallbacks',
|
|
398
|
+
'language',
|
|
365
399
|
]);
|
|
366
400
|
const KEY_VALIDATORS = {
|
|
367
401
|
'llm.provider': (v) => ['anthropic', 'openai', 'ollama'].includes(v) ? null : `must be one of: anthropic, openai, ollama`,
|
|
368
|
-
'
|
|
402
|
+
'language': (v) => {
|
|
403
|
+
if (v.trim().length === 0)
|
|
404
|
+
return 'must not be blank — use `memesh config unset language` to clear it';
|
|
405
|
+
if (v.length > MAX_LANGUAGE_LENGTH)
|
|
406
|
+
return `must be ${MAX_LANGUAGE_LENGTH} characters or fewer (a language name or locale code)`;
|
|
407
|
+
return languageValueError(v);
|
|
408
|
+
},
|
|
409
|
+
'embedder.provider': (v) => ['openai', 'ollama'].includes(v) ? null : `must be one of: openai, ollama`,
|
|
369
410
|
'autoUpdate': (v) => ['off', 'patch', 'minor', 'major'].includes(v) ? null : `must be one of: off, patch, minor, major`,
|
|
370
411
|
'llmFallbacks': (v) => {
|
|
371
412
|
let parsed;
|
|
@@ -548,13 +589,13 @@ program
|
|
|
548
589
|
});
|
|
549
590
|
program
|
|
550
591
|
.command('serve')
|
|
551
|
-
.description('Start HTTP API server')
|
|
592
|
+
.description('Start the HTTP API server and web dashboard')
|
|
552
593
|
.option('--port <port>', 'Port number', '3737')
|
|
553
594
|
.option('--host <host>', 'Host to bind', '127.0.0.1')
|
|
554
|
-
.option('--allow-remote', 'Allow binding to non-loopback hosts
|
|
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.')
|
|
555
596
|
.action(async (opts) => {
|
|
556
597
|
const { startServer } = await import('../http/server.js');
|
|
557
|
-
startServer(opts.host, parseInt(opts.port, 10), { allowRemote: opts.allowRemote });
|
|
598
|
+
startServer(opts.host, parseInt(opts.port, 10), { allowRemote: opts.allowRemote, autoUpdateCheck: true });
|
|
558
599
|
});
|
|
559
600
|
program
|
|
560
601
|
.command('update')
|
|
@@ -849,18 +890,118 @@ dreamCmd
|
|
|
849
890
|
.option('--max-llm-calls <n>', 'Hard cap on LLM calls (default 100)', (v) => parseInt(v, 10))
|
|
850
891
|
.option('--window-days <n>', 'Look-back window in days (default 56 = 8 weeks)', (v) => parseInt(v, 10))
|
|
851
892
|
.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`)')
|
|
893
|
+
.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.')
|
|
894
|
+
.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.')
|
|
895
|
+
.option('--min-interval-hours <n>', 'With --if-due: minimum hours between mined runs for this project (default 24).', (v) => parseInt(v, 10))
|
|
852
896
|
.action(async (opts) => {
|
|
897
|
+
if (opts.fromTranscripts) {
|
|
898
|
+
const windowDays = typeof opts.windowDays === 'number' && !Number.isNaN(opts.windowDays) ? opts.windowDays : 3;
|
|
899
|
+
if (opts.dryRun) {
|
|
900
|
+
const { scanTranscripts } = await import('../../core/transcript-source.js');
|
|
901
|
+
const { countConversationTurns } = await import('../../core/transcript-extractor.js');
|
|
902
|
+
const sessions = scanTranscripts({ windowDays });
|
|
903
|
+
console.log(`[dry-run] transcript sessions for this project in the last ${windowDays} day(s): ${sessions.length}`);
|
|
904
|
+
let totalTurns = 0;
|
|
905
|
+
for (const s of sessions) {
|
|
906
|
+
const turns = countConversationTurns(s.path);
|
|
907
|
+
totalTurns += turns;
|
|
908
|
+
console.log(` ${s.sessionId} ${turns} conversation turns ${s.lineCount} lines ${(s.sizeBytes / 1024).toFixed(0)}KB ${s.modifiedAt}`);
|
|
909
|
+
}
|
|
910
|
+
console.log(` total: ${totalTurns} conversation turns across ${sessions.length} session(s)`);
|
|
911
|
+
console.log('');
|
|
912
|
+
console.log('Run without --dry-run to extract high-value memories and stage them as proposals.');
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
if (opts.ifDue) {
|
|
916
|
+
const { isTranscriptMiningEnabled } = await import('../../core/config.js');
|
|
917
|
+
if (!isTranscriptMiningEnabled(readConfig())) {
|
|
918
|
+
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.');
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
const { getProjectName } = await import('../../core/paths.js');
|
|
922
|
+
const { lastTranscriptMineAt, transcriptMiningDue } = await import('../../core/transcript-source.js');
|
|
923
|
+
const projectKey = getProjectName(process.cwd());
|
|
924
|
+
const intervalH = typeof opts.minIntervalHours === 'number' && !Number.isNaN(opts.minIntervalHours) ? opts.minIntervalHours : 24;
|
|
925
|
+
const last = lastTranscriptMineAt(projectKey);
|
|
926
|
+
if (!transcriptMiningDue(Date.now(), last, intervalH)) {
|
|
927
|
+
const agoH = last === null ? null : (Date.now() - last) / 3600_000;
|
|
928
|
+
console.log(`Not due yet: this project was mined ${agoH === null ? 'recently' : `${agoH.toFixed(1)}h ago`}; interval is ${intervalH}h. Nothing to do.`);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
if (opts.project) {
|
|
933
|
+
console.log('note: --project does not scope --from-transcripts — the transcript source is always the current project. Ignoring --project.');
|
|
934
|
+
}
|
|
935
|
+
await withDatabase(async () => {
|
|
936
|
+
const { runTranscriptSource } = await import('../../core/transcript-extractor.js');
|
|
937
|
+
const { getDatabase } = await import('../../db.js');
|
|
938
|
+
const cfg = readConfig();
|
|
939
|
+
const llm = detectCapabilities().llm;
|
|
940
|
+
if (!llm) {
|
|
941
|
+
console.error('No LLM configured. Run `memesh config set llm.provider <anthropic|openai|ollama>` first (or set ANTHROPIC_API_KEY / OPENAI_API_KEY).');
|
|
942
|
+
console.error('LLM is required for `--from-transcripts` because extracting durable memory from prose is a semantic decision, not a rule.');
|
|
943
|
+
process.exit(1);
|
|
944
|
+
}
|
|
945
|
+
const result = await runTranscriptSource(getDatabase(), llm, {
|
|
946
|
+
windowDays,
|
|
947
|
+
maxLlmCalls: opts.maxLlmCalls,
|
|
948
|
+
fallbacks: cfg.llmFallbacks,
|
|
949
|
+
});
|
|
950
|
+
const { getProjectName } = await import('../../core/paths.js');
|
|
951
|
+
const { recordTranscriptMine } = await import('../../core/transcript-source.js');
|
|
952
|
+
recordTranscriptMine(getProjectName(process.cwd()), Date.now());
|
|
953
|
+
console.log(`Transcript mining complete in ${result.durationMs}ms`);
|
|
954
|
+
console.log(` sessions scanned: ${result.sessionsScanned}`);
|
|
955
|
+
console.log(` LLM calls: ${result.llmCalls}`);
|
|
956
|
+
console.log(` candidates extracted: ${result.candidatesExtracted}`);
|
|
957
|
+
console.log(` proposals created: ${result.proposalsCreated}`);
|
|
958
|
+
if (result.duplicatesSkipped > 0)
|
|
959
|
+
console.log(` duplicates skipped: ${result.duplicatesSkipped} (already a pending proposal)`);
|
|
960
|
+
if (result.nearDuplicatesSkipped > 0) {
|
|
961
|
+
console.log(` near-duplicates skipped: ${result.nearDuplicatesSkipped} candidate(s) skipped as near-duplicates of existing memories`);
|
|
962
|
+
for (const d of result.nearDuplicates) {
|
|
963
|
+
console.log(` - "${d.candidateName}" ~= existing "${d.matchedEntityName}" (distance ${d.distance.toFixed(3)})`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (result.secretsDropped > 0)
|
|
967
|
+
console.log(` secret-bearing candidates dropped: ${result.secretsDropped}`);
|
|
968
|
+
if (result.llmFailures > 0)
|
|
969
|
+
console.log(` LLM call failures: ${result.llmFailures} (sessions not mined — retry when the provider is reachable)`);
|
|
970
|
+
if (result.parseFailures > 0)
|
|
971
|
+
console.log(` unparsable replies: ${result.parseFailures} (chunk reply not valid JSON — likely truncated; those candidates were lost, retry)`);
|
|
972
|
+
if (result.truncatedTurns > 0) {
|
|
973
|
+
console.log(` size-cap truncation: ${result.truncatedTurns} conversation turn(s) beyond the cap were NOT analysed`);
|
|
974
|
+
for (const t of result.truncatedSessions) {
|
|
975
|
+
console.log(` - session ${t.sessionId}: ${t.truncatedTurns} tail turn(s) not analysed`);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
if (result.skipped.length > 0) {
|
|
979
|
+
const reasonCounts = new Map();
|
|
980
|
+
for (const s of result.skipped)
|
|
981
|
+
reasonCounts.set(s.reason, (reasonCounts.get(s.reason) ?? 0) + 1);
|
|
982
|
+
console.log(` skipped: ${result.skipped.length}`);
|
|
983
|
+
for (const [reason, n] of reasonCounts)
|
|
984
|
+
console.log(` - ${reason}${n > 1 ? ` (×${n})` : ''}`);
|
|
985
|
+
}
|
|
986
|
+
if (result.proposalsCreated > 0) {
|
|
987
|
+
console.log('');
|
|
988
|
+
console.log('Review with: memesh dream list');
|
|
989
|
+
console.log('Accept: memesh dream accept <id>');
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
853
994
|
await withDatabase(async () => {
|
|
854
995
|
const { runDreamer } = await import('../../core/dreamer.js');
|
|
855
|
-
const { readConfig } = await import('../../core/config.js');
|
|
856
996
|
const { getDatabase } = await import('../../db.js');
|
|
857
997
|
const cfg = readConfig();
|
|
858
|
-
|
|
859
|
-
|
|
998
|
+
const llm = detectCapabilities().llm;
|
|
999
|
+
if (!llm) {
|
|
1000
|
+
console.error('No LLM configured. Run `memesh config set llm.provider <anthropic|openai|ollama>` first (or set ANTHROPIC_API_KEY / OPENAI_API_KEY).');
|
|
860
1001
|
console.error('LLM is required for `memesh dream` because consolidation is a semantic decision, not a rule.');
|
|
861
1002
|
process.exit(1);
|
|
862
1003
|
}
|
|
863
|
-
const result = await runDreamer(getDatabase(),
|
|
1004
|
+
const result = await runDreamer(getDatabase(), llm, {
|
|
864
1005
|
project: opts.project,
|
|
865
1006
|
dryRun: !!opts.dryRun,
|
|
866
1007
|
maxLlmCalls: opts.maxLlmCalls,
|
|
@@ -900,14 +1041,15 @@ dreamCmd
|
|
|
900
1041
|
.action(async (opts) => {
|
|
901
1042
|
await withDatabase(async () => {
|
|
902
1043
|
const { runPatternDetector } = await import('../../core/dreamer.js');
|
|
903
|
-
const { readConfig } = await import('../../core/config.js');
|
|
904
1044
|
const { getDatabase } = await import('../../db.js');
|
|
905
1045
|
const cfg = readConfig();
|
|
906
|
-
|
|
1046
|
+
const llm = detectCapabilities().llm;
|
|
1047
|
+
if (!llm) {
|
|
907
1048
|
console.error('No LLM configured. Pattern detection requires an LLM.');
|
|
1049
|
+
console.error('Run `memesh config set llm.provider <anthropic|openai|ollama>` first (or set ANTHROPIC_API_KEY / OPENAI_API_KEY).');
|
|
908
1050
|
process.exit(1);
|
|
909
1051
|
}
|
|
910
|
-
const result = await runPatternDetector(getDatabase(),
|
|
1052
|
+
const result = await runPatternDetector(getDatabase(), llm, {
|
|
911
1053
|
project: opts.project,
|
|
912
1054
|
dryRun: !!opts.dryRun,
|
|
913
1055
|
maxLlmCalls: opts.maxLlmCalls,
|
|
@@ -952,12 +1094,48 @@ dreamCmd
|
|
|
952
1094
|
console.log(`${proposals.length} ${opts.status} proposal(s):`);
|
|
953
1095
|
console.log('');
|
|
954
1096
|
for (const p of proposals) {
|
|
955
|
-
|
|
956
|
-
console.log(`
|
|
1097
|
+
const srcLabel = p.source_kind === 'transcript' ? ' (transcript)' : '';
|
|
1098
|
+
console.log(` #${p.id} [${p.project}/${p.cluster_key}]${srcLabel} ${p.source_count} source(s) → "${p.digest_name}"`);
|
|
1099
|
+
if (p.digest_observations_preview !== null) {
|
|
1100
|
+
console.log(` ${p.digest_observations_preview}`);
|
|
1101
|
+
}
|
|
957
1102
|
console.log(` created: ${p.created_at}`);
|
|
958
1103
|
console.log('');
|
|
959
1104
|
}
|
|
960
|
-
console.log(`Apply: memesh dream accept <id> | Reject: memesh dream reject <id>`);
|
|
1105
|
+
console.log(`Inspect: memesh dream show <id> | Apply: memesh dream accept <id> | Reject: memesh dream reject <id>`);
|
|
1106
|
+
});
|
|
1107
|
+
});
|
|
1108
|
+
dreamCmd
|
|
1109
|
+
.command('show <id>')
|
|
1110
|
+
.description('Show a proposal in full — name, type, ALL observations, tags, source — so you can review the whole thing before accepting')
|
|
1111
|
+
.option('--json', 'Output JSON')
|
|
1112
|
+
.action(async (id, opts) => {
|
|
1113
|
+
await withDatabase(async () => {
|
|
1114
|
+
const { getProposalDetail } = await import('../../core/dreamer.js');
|
|
1115
|
+
const { getDatabase } = await import('../../db.js');
|
|
1116
|
+
const detail = getProposalDetail(getDatabase(), parseInt(id, 10));
|
|
1117
|
+
if (!detail) {
|
|
1118
|
+
console.error(`proposal #${id} not found`);
|
|
1119
|
+
console.error('See ids with: memesh dream list');
|
|
1120
|
+
process.exit(1);
|
|
1121
|
+
}
|
|
1122
|
+
if (opts.json) {
|
|
1123
|
+
console.log(JSON.stringify(detail, null, 2));
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
console.log(`Proposal #${detail.id} [${detail.project}/${detail.cluster_key}] source: ${detail.source_kind} status: ${detail.status}`);
|
|
1127
|
+
console.log(`created: ${detail.created_at}`);
|
|
1128
|
+
console.log('');
|
|
1129
|
+
console.log(`name: ${detail.digest.name}`);
|
|
1130
|
+
console.log(`type: ${detail.digest.type}`);
|
|
1131
|
+
console.log(`observations (${detail.digest.observations.length}):`);
|
|
1132
|
+
for (const o of detail.digest.observations)
|
|
1133
|
+
console.log(` - ${o}`);
|
|
1134
|
+
if (detail.digest.tags.length > 0)
|
|
1135
|
+
console.log(`tags: ${detail.digest.tags.join(', ')}`);
|
|
1136
|
+
console.log(`source: ${JSON.stringify(detail.source)}`);
|
|
1137
|
+
console.log('');
|
|
1138
|
+
console.log(`Accept: memesh dream accept ${detail.id} | Reject: memesh dream reject ${detail.id}`);
|
|
961
1139
|
});
|
|
962
1140
|
});
|
|
963
1141
|
dreamCmd
|
|
@@ -969,7 +1147,16 @@ dreamCmd
|
|
|
969
1147
|
const { getDatabase } = await import('../../db.js');
|
|
970
1148
|
const { KnowledgeGraph } = await import('../../knowledge-graph.js');
|
|
971
1149
|
const kg = new KnowledgeGraph(getDatabase());
|
|
972
|
-
|
|
1150
|
+
let result;
|
|
1151
|
+
try {
|
|
1152
|
+
result = applyProposal(getDatabase(), parseInt(id, 10), kg);
|
|
1153
|
+
}
|
|
1154
|
+
catch (err) {
|
|
1155
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1156
|
+
console.error('See pending ids with: memesh dream list');
|
|
1157
|
+
process.exit(1);
|
|
1158
|
+
}
|
|
1159
|
+
await flushPendingEmbeddings();
|
|
973
1160
|
console.log(`Applied proposal #${result.proposalId}`);
|
|
974
1161
|
console.log(` digest entity: ${result.digestEntityName}`);
|
|
975
1162
|
console.log(` sources archived: ${result.sourcesArchived}`);
|
|
@@ -983,7 +1170,14 @@ dreamCmd
|
|
|
983
1170
|
await withDatabase(async () => {
|
|
984
1171
|
const { rejectProposal } = await import('../../core/dreamer.js');
|
|
985
1172
|
const { getDatabase } = await import('../../db.js');
|
|
986
|
-
|
|
1173
|
+
try {
|
|
1174
|
+
rejectProposal(getDatabase(), parseInt(id, 10), opts.reason);
|
|
1175
|
+
}
|
|
1176
|
+
catch (err) {
|
|
1177
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1178
|
+
console.error('See pending ids with: memesh dream list');
|
|
1179
|
+
process.exit(1);
|
|
1180
|
+
}
|
|
987
1181
|
console.log(`Rejected proposal #${id}`);
|
|
988
1182
|
});
|
|
989
1183
|
});
|
|
@@ -1155,9 +1349,8 @@ program
|
|
|
1155
1349
|
console.error('❌ Could not produce a test embedding at this database\'s vector width, so\n' +
|
|
1156
1350
|
' the index was left untouched. Rebuilding it deletes every stored\n' +
|
|
1157
1351
|
' embedding, and nothing here could regenerate them.\n' +
|
|
1158
|
-
' Check that your OpenAI API key is valid
|
|
1159
|
-
'
|
|
1160
|
-
' again. `memesh doctor` reports which provider is configured.');
|
|
1352
|
+
' Check that Ollama is running (or that your OpenAI API key is valid) —\n' +
|
|
1353
|
+
' then run this again. `memesh doctor` reports which provider is configured.');
|
|
1161
1354
|
process.exit(1);
|
|
1162
1355
|
}
|
|
1163
1356
|
}
|
|
@@ -1274,40 +1467,11 @@ program.action(async () => {
|
|
|
1274
1467
|
if (stray.length > 0) {
|
|
1275
1468
|
console.error(`Error: unknown command '${stray[0]}'.`);
|
|
1276
1469
|
console.error(` Run 'memesh --help' to see available commands.`);
|
|
1277
|
-
process.
|
|
1278
|
-
|
|
1279
|
-
const { startServer } = await import('../http/server.js');
|
|
1280
|
-
const server = startServer('127.0.0.1', 0);
|
|
1281
|
-
await new Promise((resolve, reject) => {
|
|
1282
|
-
server.once('listening', resolve);
|
|
1283
|
-
server.once('error', reject);
|
|
1284
|
-
});
|
|
1285
|
-
const addr = server.address();
|
|
1286
|
-
if (!addr) {
|
|
1287
|
-
console.error('Failed to start dashboard server');
|
|
1288
|
-
process.exit(1);
|
|
1289
|
-
}
|
|
1290
|
-
const url = `http://127.0.0.1:${addr.port}/dashboard`;
|
|
1291
|
-
console.log(`MeMesh dashboard: ${url}`);
|
|
1292
|
-
console.log('Press Ctrl+C to stop.');
|
|
1293
|
-
const { execFile } = await import('child_process');
|
|
1294
|
-
if (process.platform === 'darwin') {
|
|
1295
|
-
execFile('open', [url]);
|
|
1296
|
-
}
|
|
1297
|
-
else if (process.platform === 'win32') {
|
|
1298
|
-
execFile('cmd.exe', ['/c', 'start', '', url]);
|
|
1299
|
-
}
|
|
1300
|
-
else {
|
|
1301
|
-
execFile('xdg-open', [url]);
|
|
1470
|
+
process.exitCode = 1;
|
|
1471
|
+
return;
|
|
1302
1472
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
try {
|
|
1306
|
-
closeDatabase();
|
|
1307
|
-
}
|
|
1308
|
-
catch { }
|
|
1309
|
-
process.exit(0);
|
|
1310
|
-
});
|
|
1473
|
+
program.outputHelp();
|
|
1474
|
+
process.exitCode = 0;
|
|
1311
1475
|
});
|
|
1312
1476
|
program.parse();
|
|
1313
1477
|
//# sourceMappingURL=cli.js.map
|