@pcircle/memesh 4.6.0 → 4.6.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/AGENTS.md +21 -0
- package/README.de.md +12 -13
- package/README.md +12 -14
- package/README.zh-TW.md +12 -13
- package/dashboard/dist/index.html +14 -13
- package/dist/core/analytics.d.ts +9 -0
- package/dist/core/analytics.d.ts.map +1 -1
- package/dist/core/analytics.js +36 -18
- package/dist/core/analytics.js.map +1 -1
- package/dist/core/briefing.d.ts.map +1 -1
- package/dist/core/briefing.js +1 -0
- package/dist/core/briefing.js.map +1 -1
- package/dist/core/config.d.ts +0 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.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/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +25 -6
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/dreamer.d.ts +2 -2
- package/dist/core/dreamer.d.ts.map +1 -1
- package/dist/core/dreamer.js +221 -0
- package/dist/core/dreamer.js.map +1 -1
- package/dist/core/embedder.d.ts +4 -1
- package/dist/core/embedder.d.ts.map +1 -1
- package/dist/core/embedder.js +67 -17
- package/dist/core/embedder.js.map +1 -1
- package/dist/core/graph.d.ts +12 -0
- package/dist/core/graph.d.ts.map +1 -1
- package/dist/core/graph.js +56 -1
- package/dist/core/graph.js.map +1 -1
- package/dist/core/guards.d.ts +20 -0
- package/dist/core/guards.d.ts.map +1 -0
- package/dist/core/guards.js +103 -0
- package/dist/core/guards.js.map +1 -0
- package/dist/core/kg-backfill.d.ts +5 -1
- package/dist/core/kg-backfill.d.ts.map +1 -1
- package/dist/core/kg-backfill.js +155 -2
- package/dist/core/kg-backfill.js.map +1 -1
- package/dist/core/operations.d.ts +13 -2
- package/dist/core/operations.d.ts.map +1 -1
- package/dist/core/operations.js +93 -15
- package/dist/core/operations.js.map +1 -1
- package/dist/core/serializer.d.ts.map +1 -1
- package/dist/core/serializer.js +8 -0
- package/dist/core/serializer.js.map +1 -1
- package/dist/core/types.d.ts +1 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/why.d.ts +54 -0
- package/dist/core/why.d.ts.map +1 -0
- package/dist/core/why.js +168 -0
- package/dist/core/why.js.map +1 -0
- package/dist/core/work-topology.d.ts +3 -0
- package/dist/core/work-topology.d.ts.map +1 -1
- package/dist/core/work-topology.js +11 -2
- package/dist/core/work-topology.js.map +1 -1
- package/dist/db.d.ts +31 -4
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +163 -31
- package/dist/db.js.map +1 -1
- package/dist/skills-manifest.json +29 -19
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +1 -1
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/transports/cli/cli.js +198 -61
- 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 +43 -5
- package/dist/transports/http/server.js.map +1 -1
- package/dist/transports/mcp/handlers.d.ts.map +1 -1
- package/dist/transports/mcp/handlers.js +2 -2
- package/dist/transports/mcp/handlers.js.map +1 -1
- package/dist/transports/schemas.d.ts +8 -0
- package/dist/transports/schemas.d.ts.map +1 -1
- package/dist/transports/schemas.js +7 -0
- package/dist/transports/schemas.js.map +1 -1
- package/hooks/hooks.json +10 -0
- package/package.json +1 -1
- package/scripts/hooks/_generated/guards.js +110 -0
- package/scripts/hooks/_generated/sqlite.js +1 -1
- package/scripts/hooks/_generated/work-topology.js +11 -2
- package/scripts/hooks/_shared.js +77 -4
- package/scripts/hooks/guard-check.js +76 -0
- package/scripts/hooks/post-commit.js +27 -0
- package/scripts/hooks/pre-edit-recall.js +157 -121
- package/scripts/hooks/session-start.js +34 -23
- package/scripts/hooks/session-summary.js +43 -90
- package/skills/memesh/SKILL.md +11 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command } from 'commander';
|
|
2
|
+
import { Command, Option } from 'commander';
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
|
-
import { openDatabase, closeDatabase, getDatabase, reindexFts,
|
|
7
|
+
import { openDatabase, closeDatabase, getDatabase, reindexFts, readVectorGeneration, generationRowIds, discardVectorGeneration, } from '../../db.js';
|
|
8
8
|
import { remember, recallWithConflicts, forget, exportMemories, importMemories, learn, reindex, setPinned } from '../../core/operations.js';
|
|
9
9
|
import { readConfig, writeConfig, maskApiKey, detectCapabilities } from '../../core/config.js';
|
|
10
10
|
import { MAX_LANGUAGE_LENGTH, languageValueError } from '../../core/output-language.js';
|
|
11
|
-
import { getDbPath, homeDir, redactSecrets, redactUserPaths } from '../../core/paths.js';
|
|
11
|
+
import { getDbPath, getProjectName, homeDir, redactSecrets, redactUserPaths } from '../../core/paths.js';
|
|
12
12
|
import { flushPendingEmbeddings, canRefillVectorIndex } from '../../core/embedder.js';
|
|
13
13
|
import { NAMESPACES } from '../../core/types.js';
|
|
14
14
|
import { assembleBriefing } from '../../core/briefing.js';
|
|
@@ -159,7 +159,7 @@ program
|
|
|
159
159
|
.action(async (query, opts) => {
|
|
160
160
|
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
161
161
|
await withDatabase(async () => {
|
|
162
|
-
const { entities, conflicts } = await recallWithConflicts({
|
|
162
|
+
const { entities, conflicts, retrieval } = await recallWithConflicts({
|
|
163
163
|
query: query || undefined,
|
|
164
164
|
tag: opts.tag,
|
|
165
165
|
limit: parseInt(opts.limit),
|
|
@@ -168,12 +168,7 @@ program
|
|
|
168
168
|
cross_project: opts.crossProject,
|
|
169
169
|
});
|
|
170
170
|
if (opts.json) {
|
|
171
|
-
|
|
172
|
-
console.log(JSON.stringify({ entities, conflicts }));
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
console.log(JSON.stringify(entities));
|
|
176
|
-
}
|
|
171
|
+
console.log(JSON.stringify(conflicts.length > 0 ? { entities, retrieval, conflicts } : { entities, retrieval }));
|
|
177
172
|
}
|
|
178
173
|
else if (entities.length === 0) {
|
|
179
174
|
console.log('No results found.');
|
|
@@ -203,7 +198,11 @@ program
|
|
|
203
198
|
console.log(` ... +${e.observations.length - 3} more`);
|
|
204
199
|
}
|
|
205
200
|
}
|
|
206
|
-
|
|
201
|
+
const truncatedNote = retrieval.truncated ? ' (limit reached — more may exist)' : '';
|
|
202
|
+
console.log(`\n${entities.length} result(s)${truncatedNote}`);
|
|
203
|
+
if (retrieval.degraded) {
|
|
204
|
+
console.log('Warning: semantic search unavailable right now — keyword-only results (degraded). Run `memesh doctor` to see why.');
|
|
205
|
+
}
|
|
207
206
|
if (conflicts.length > 0) {
|
|
208
207
|
console.log('\nWarning: Conflicts detected:');
|
|
209
208
|
for (const c of conflicts) {
|
|
@@ -450,6 +449,83 @@ program
|
|
|
450
449
|
console.log(result.text);
|
|
451
450
|
});
|
|
452
451
|
});
|
|
452
|
+
const WHY_ABSTENTION_TEXT = {
|
|
453
|
+
git_unavailable: 'git is not installed or not on PATH — commit attribution unavailable.',
|
|
454
|
+
not_a_git_repo: 'Not inside a git repository — commit attribution unavailable.',
|
|
455
|
+
file_not_tracked: 'File is not tracked by git — commit attribution unavailable.',
|
|
456
|
+
history_unreadable: "git could not read this file's history (too much output, too slow, or the repository has no commits yet) — nothing is listed because the question went unanswered, not because no commit touched the file.",
|
|
457
|
+
no_commits_supplied: 'No commit hashes were supplied — only the file-tag half of this answer ran.',
|
|
458
|
+
line_out_of_range: 'That line does not exist in the tracked file.',
|
|
459
|
+
line_uncommitted: 'That line is not committed yet — nothing to attribute.',
|
|
460
|
+
no_commit_entity: 'memesh has no memory of this commit (it predates capture, or was made without hooks / on another machine).',
|
|
461
|
+
no_session_link: 'This commit was captured before commits recorded their session — the session link does not exist.',
|
|
462
|
+
};
|
|
463
|
+
program
|
|
464
|
+
.command('why')
|
|
465
|
+
.description('Explain a file: commits memesh remembers touching it, their sessions, and related memories')
|
|
466
|
+
.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', '10')
|
|
469
|
+
.option('--json', 'Output as JSON')
|
|
470
|
+
.action(async (file, opts) => {
|
|
471
|
+
await withDatabase(async () => {
|
|
472
|
+
const { resolveFileCommits, explainCommits } = await import('../../core/why.js');
|
|
473
|
+
const cwd = process.cwd();
|
|
474
|
+
const limit = parseInt(opts.limit, 10);
|
|
475
|
+
const line = opts.line !== undefined ? parseInt(opts.line, 10) : undefined;
|
|
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
|
+
}
|
|
482
|
+
const resolved = resolveFileCommits(cwd, file, { line, limit });
|
|
483
|
+
const result = explainCommits(getDatabase(), {
|
|
484
|
+
file,
|
|
485
|
+
commits: resolved.commits,
|
|
486
|
+
project: getProjectName(cwd),
|
|
487
|
+
limit,
|
|
488
|
+
abstentions: resolved.abstention ? [resolved.abstention] : [],
|
|
489
|
+
});
|
|
490
|
+
if (opts.json) {
|
|
491
|
+
console.log(JSON.stringify(result, null, 2));
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
console.log(`why ${result.file} (project: ${result.project ?? 'all'})`);
|
|
495
|
+
for (const code of result.abstentions) {
|
|
496
|
+
console.log(` ! ${WHY_ABSTENTION_TEXT[code] ?? code}`);
|
|
497
|
+
}
|
|
498
|
+
if (result.commits.length === 0 && result.abstentions.length === 0) {
|
|
499
|
+
console.log(' No commits touch this file.');
|
|
500
|
+
}
|
|
501
|
+
for (const c of result.commits) {
|
|
502
|
+
const head = [c.commit.hash.slice(0, 10), c.commit.date, c.commit.subject].filter(Boolean).join(' ');
|
|
503
|
+
console.log(`\n ${head}`);
|
|
504
|
+
if (c.entity) {
|
|
505
|
+
console.log(` memory: ${c.entity.name} [mem:${c.entity.id}]`);
|
|
506
|
+
for (const obs of c.entity.observations.slice(0, 3))
|
|
507
|
+
console.log(` - ${obs}`);
|
|
508
|
+
}
|
|
509
|
+
if (c.session) {
|
|
510
|
+
console.log(` session: ${c.session.session_id}`);
|
|
511
|
+
for (const s of c.session.entities)
|
|
512
|
+
console.log(` - ${s.name} (${s.type})`);
|
|
513
|
+
if (c.session.truncated) {
|
|
514
|
+
console.log(` … first ${c.session.entities.length} of a larger session — more exist`);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
for (const code of c.abstentions) {
|
|
518
|
+
console.log(` ! ${WHY_ABSTENTION_TEXT[code] ?? code}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const fm = result.file_memories.entities;
|
|
522
|
+
if (fm.length > 0) {
|
|
523
|
+
console.log(`\n Related by file tag (file:${result.basename} — associated, not commit-derived):`);
|
|
524
|
+
for (const e of fm)
|
|
525
|
+
console.log(` - ${e.name} (${e.type})${e.title ? `: ${e.title}` : ''}`);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
});
|
|
453
529
|
program
|
|
454
530
|
.command('setup')
|
|
455
531
|
.description('Detect Claude Code / Codex / Gemini on this machine, wire memesh into each, and verify')
|
|
@@ -615,7 +691,6 @@ const ALLOWED_KEYS = new Set([
|
|
|
615
691
|
'llm.apiKey',
|
|
616
692
|
'llm.model',
|
|
617
693
|
'embedder.provider',
|
|
618
|
-
'embedder.model',
|
|
619
694
|
'autoUpdate',
|
|
620
695
|
'sessionLimit',
|
|
621
696
|
'autoCapture',
|
|
@@ -1005,7 +1080,8 @@ kgCmd
|
|
|
1005
1080
|
.option('--session-cooccurrence', 'Rule 3: link high-signal orphans co-created in the same session')
|
|
1006
1081
|
.option('--name-tokens', 'Rule 4: link orphans sharing ≥3 name content tokens (or Jaccard ≥ 0.50)')
|
|
1007
1082
|
.option('--min-jaccard <n>', 'Jaccard threshold for name similarity (default 0.50)', parseFloat)
|
|
1008
|
-
.option('--all-rules', 'Enable all heuristic rules (Rules 1–
|
|
1083
|
+
.option('--all-rules', 'Enable all heuristic rules (Rules 1–5)')
|
|
1084
|
+
.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)')
|
|
1009
1085
|
.option('--reset-idempotency', 'Clear the persistent "already-attempted" orphan cache before running (use after schema changes or to reconsider every orphan)')
|
|
1010
1086
|
.option('--json', 'Output as JSON')
|
|
1011
1087
|
.action(async (opts) => {
|
|
@@ -1020,6 +1096,7 @@ kgCmd
|
|
|
1020
1096
|
dryRun: !!opts.dryRun,
|
|
1021
1097
|
includeSessionCooccurrence: allRules || !!opts.sessionCooccurrence,
|
|
1022
1098
|
includeNameTokenSimilarity: allRules || !!opts.nameTokens,
|
|
1099
|
+
includeEvidenceLinks: opts.evidenceLinks !== false,
|
|
1023
1100
|
minNameJaccard: opts.minJaccard,
|
|
1024
1101
|
resetIdempotency: !!opts.resetIdempotency,
|
|
1025
1102
|
};
|
|
@@ -1059,6 +1136,7 @@ kgCmd
|
|
|
1059
1136
|
console.log(` project clustering: ${result.byRule.projectClustering}`);
|
|
1060
1137
|
console.log(` session co-occurrence: ${result.byRule.sessionCooccurrence}`);
|
|
1061
1138
|
console.log(` name token similarity: ${result.byRule.nameTokenSimilarity}`);
|
|
1139
|
+
console.log(` evidence links: ${result.byRule.evidenceLinks}`);
|
|
1062
1140
|
if (result.candidatesProposed > result.edgesWritten) {
|
|
1063
1141
|
console.log(` (${result.candidatesProposed - result.edgesWritten} candidates were already-existing edges; INSERT OR IGNORE skipped them.)`);
|
|
1064
1142
|
}
|
|
@@ -1759,17 +1837,60 @@ program
|
|
|
1759
1837
|
.description('Regenerate vector embeddings for all entities (--fts rebuilds the keyword index instead)')
|
|
1760
1838
|
.option('--namespace <namespace>', 'Reindex only entities in this namespace')
|
|
1761
1839
|
.option('--fts', 'Rebuild the full-text keyword index instead of the vector index')
|
|
1762
|
-
.option('--
|
|
1763
|
-
'stored embedding first. Needed only when switching embedding providers.')
|
|
1840
|
+
.option('--discard-generation', 'Throw away a half-built vector index left by an interrupted rebuild, without rebuilding')
|
|
1764
1841
|
.option('--json', 'Output as JSON')
|
|
1842
|
+
.addOption(new Option('--vectors').hideHelp())
|
|
1765
1843
|
.action(async (opts) => {
|
|
1844
|
+
if (opts.vectors) {
|
|
1845
|
+
if (opts.json) {
|
|
1846
|
+
console.log(JSON.stringify({
|
|
1847
|
+
refused: true,
|
|
1848
|
+
reason: 'the --vectors flag is retired',
|
|
1849
|
+
fix: 'run plain memesh reindex; to change provider first: memesh config set embedder.provider ollama|openai',
|
|
1850
|
+
indexTouched: false,
|
|
1851
|
+
}));
|
|
1852
|
+
process.exit(1);
|
|
1853
|
+
}
|
|
1854
|
+
console.error('`memesh reindex --vectors` has been retired.');
|
|
1855
|
+
console.error('');
|
|
1856
|
+
console.error('It existed to consent to dropping every stored embedding before a refill.');
|
|
1857
|
+
console.error('A rebuild now happens beside the live index and replaces it only when');
|
|
1858
|
+
console.error('complete, so there is nothing left to consent to.');
|
|
1859
|
+
console.error('');
|
|
1860
|
+
console.error('Run plain `memesh reindex`. To change embedding provider first:');
|
|
1861
|
+
console.error(' memesh config set embedder.provider ollama (or openai)');
|
|
1862
|
+
process.exit(1);
|
|
1863
|
+
}
|
|
1766
1864
|
requireOneOf(opts.namespace, NAMESPACES, '--namespace');
|
|
1865
|
+
if (opts.discardGeneration) {
|
|
1866
|
+
await withDatabase(async () => {
|
|
1867
|
+
const read = readVectorGeneration();
|
|
1868
|
+
const staged = generationRowIds().size;
|
|
1869
|
+
if (read.state === 'none' && staged === 0) {
|
|
1870
|
+
if (opts.json)
|
|
1871
|
+
console.log(JSON.stringify({ discarded: false, staged: 0 }));
|
|
1872
|
+
else
|
|
1873
|
+
console.log('Nothing to discard: there is no half-built vector index.');
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1876
|
+
const describe = read.state === 'open'
|
|
1877
|
+
? `${read.info.dimension}-dim, provider ${read.info.provider}, started ${read.info.startedAt}`
|
|
1878
|
+
: read.state === 'unreadable'
|
|
1879
|
+
? `marker unreadable (${read.detail})`
|
|
1880
|
+
: 'no marker';
|
|
1881
|
+
discardVectorGeneration();
|
|
1882
|
+
if (opts.json) {
|
|
1883
|
+
console.log(JSON.stringify({ discarded: true, staged, generation: read, liveIndexTouched: false }));
|
|
1884
|
+
}
|
|
1885
|
+
else {
|
|
1886
|
+
console.log(`Discarded a half-built vector index: ${staged} staged vectors (${describe}).\n` +
|
|
1887
|
+
' Your live index was not touched. Run `memesh reindex` to build a new one.');
|
|
1888
|
+
}
|
|
1889
|
+
});
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1767
1892
|
try {
|
|
1768
1893
|
if (opts.fts) {
|
|
1769
|
-
if (opts.vectors) {
|
|
1770
|
-
console.error('❌ --fts and --vectors rebuild different indexes. Run them separately.');
|
|
1771
|
-
process.exit(1);
|
|
1772
|
-
}
|
|
1773
1894
|
await withDatabase(async () => {
|
|
1774
1895
|
const { entities } = reindexFts();
|
|
1775
1896
|
if (opts.json) {
|
|
@@ -1781,68 +1902,84 @@ program
|
|
|
1781
1902
|
});
|
|
1782
1903
|
return;
|
|
1783
1904
|
}
|
|
1784
|
-
if (opts.
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1905
|
+
if (!opts.namespace && !(await canRefillVectorIndex())) {
|
|
1906
|
+
const embedder = detectCapabilities().embeddings;
|
|
1907
|
+
const written = readConfig().embedder?.provider;
|
|
1908
|
+
const known = embedder === 'openai' || embedder === 'ollama';
|
|
1909
|
+
const invalid = written !== undefined && !known;
|
|
1910
|
+
const unconfigured = written === undefined && !known;
|
|
1911
|
+
const reason = invalid
|
|
1912
|
+
? `embedder.provider is set to '${written}', which is not a provider MeMesh knows`
|
|
1913
|
+
: unconfigured
|
|
1914
|
+
? 'no embedding provider is configured, so there is nothing to build vectors with'
|
|
1915
|
+
: 'could not produce a test embedding at the configured vector width';
|
|
1916
|
+
const fix = invalid || unconfigured
|
|
1917
|
+
? (invalid ? 'Set it to one MeMesh knows: ' : 'Pick one first: ') +
|
|
1918
|
+
'`memesh config set embedder.provider ollama` (local, needs `ollama serve`) ' +
|
|
1919
|
+
'or `memesh config set embedder.provider openai` (needs OPENAI_API_KEY). Until then, recall ' +
|
|
1920
|
+
'runs on keyword search, which needs no rebuild.'
|
|
1921
|
+
: 'Check that Ollama is running (or that your OpenAI API key is valid), then run this again. ' +
|
|
1922
|
+
'`memesh doctor` reports which provider is configured.';
|
|
1923
|
+
if (opts.json) {
|
|
1924
|
+
console.log(JSON.stringify({ refused: true, reason, fix, indexTouched: false }));
|
|
1792
1925
|
}
|
|
1793
|
-
|
|
1794
|
-
console.error(
|
|
1795
|
-
'
|
|
1796
|
-
|
|
1797
|
-
' Check that Ollama is running (or that your OpenAI API key is valid) —\n' +
|
|
1798
|
-
' then run this again. `memesh doctor` reports which provider is configured.');
|
|
1799
|
-
process.exit(1);
|
|
1926
|
+
else {
|
|
1927
|
+
console.error(`❌ Nothing was rebuilt: ${reason}.\n` +
|
|
1928
|
+
' Your existing index is untouched and still answering queries.\n' +
|
|
1929
|
+
` ${fix}`);
|
|
1800
1930
|
}
|
|
1931
|
+
process.exit(1);
|
|
1801
1932
|
}
|
|
1802
1933
|
await withDatabase(async () => {
|
|
1803
1934
|
const result = await reindex({ namespace: opts.namespace });
|
|
1804
|
-
const incomplete = result.missingVectors > 0
|
|
1935
|
+
const incomplete = result.missingVectors > 0
|
|
1936
|
+
|| result.failed > 0
|
|
1937
|
+
|| result.generationSwapped === false
|
|
1938
|
+
|| result.abortedAfter !== null;
|
|
1805
1939
|
if (opts.json) {
|
|
1806
1940
|
console.log(JSON.stringify(result));
|
|
1807
1941
|
}
|
|
1808
|
-
else
|
|
1809
|
-
console.log(`⚠️ Reindex incomplete:`);
|
|
1942
|
+
else {
|
|
1943
|
+
console.log(incomplete ? `⚠️ Reindex incomplete:` : `✅ Reindex complete:`);
|
|
1810
1944
|
console.log(` Processed: ${result.processed}`);
|
|
1811
1945
|
console.log(` Embedded: ${result.embedded}`);
|
|
1812
1946
|
console.log(` Skipped: ${result.skipped}`);
|
|
1813
|
-
if (
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1947
|
+
if (incomplete) {
|
|
1948
|
+
if (result.abortedAfter !== null) {
|
|
1949
|
+
console.log(` Stopped early after ${result.abortedAfter} entities: the provider failed ` +
|
|
1950
|
+
`repeatedly. Everything embedded so far is kept — run this again to continue.`);
|
|
1951
|
+
}
|
|
1952
|
+
if (result.generationSwapped === false) {
|
|
1953
|
+
console.log(` The new index was NOT switched in, so your existing index is untouched ` +
|
|
1954
|
+
`and still answering queries.`);
|
|
1955
|
+
}
|
|
1956
|
+
if (result.missingVectors > 0) {
|
|
1957
|
+
console.log(` Still without a vector: ${result.missingVectors}`);
|
|
1958
|
+
}
|
|
1959
|
+
if (result.failed > 0 && result.missingVectors === 0) {
|
|
1960
|
+
console.log(` Could not be regenerated: ${result.failed} ` +
|
|
1961
|
+
`(these still hold their previous embedding)`);
|
|
1962
|
+
}
|
|
1963
|
+
for (const [outcome, count] of Object.entries(result.outcomes)) {
|
|
1964
|
+
if (outcome !== 'stored' && count > 0)
|
|
1965
|
+
console.log(` ${outcome}: ${count}`);
|
|
1966
|
+
}
|
|
1819
1967
|
}
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1968
|
+
else if (!result.pendingReindexCleared) {
|
|
1969
|
+
console.log(` Note: ${result.missingVectorsDatabaseWide} memories in other namespaces still ` +
|
|
1970
|
+
`have no vector, so the reindex-needed flag stays set.`);
|
|
1823
1971
|
}
|
|
1824
1972
|
}
|
|
1825
|
-
else if (!result.pendingReindexCleared) {
|
|
1826
|
-
console.log(`✅ Reindex complete:`);
|
|
1827
|
-
console.log(` Processed: ${result.processed}`);
|
|
1828
|
-
console.log(` Embedded: ${result.embedded}`);
|
|
1829
|
-
console.log(` Skipped: ${result.skipped}`);
|
|
1830
|
-
console.log(` Note: ${result.missingVectorsDatabaseWide} memories in other namespaces still ` +
|
|
1831
|
-
`have no vector, so the reindex-needed flag stays set.`);
|
|
1832
|
-
}
|
|
1833
|
-
else {
|
|
1834
|
-
console.log(`✅ Reindex complete:`);
|
|
1835
|
-
console.log(` Processed: ${result.processed}`);
|
|
1836
|
-
console.log(` Embedded: ${result.embedded}`);
|
|
1837
|
-
console.log(` Skipped: ${result.skipped}`);
|
|
1838
|
-
}
|
|
1839
1973
|
if (incomplete)
|
|
1840
1974
|
process.exitCode = 1;
|
|
1841
1975
|
});
|
|
1842
1976
|
}
|
|
1843
1977
|
catch (err) {
|
|
1844
1978
|
if (err instanceof Error) {
|
|
1845
|
-
|
|
1979
|
+
if (opts.json)
|
|
1980
|
+
console.log(JSON.stringify({ refused: true, reason: err.message, indexTouched: false }));
|
|
1981
|
+
else
|
|
1982
|
+
console.error(`❌ Reindex failed: ${err.message}`);
|
|
1846
1983
|
process.exit(1);
|
|
1847
1984
|
}
|
|
1848
1985
|
throw err;
|