@amemhq/core 1.1.0 → 2.0.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/README.md +2 -2
- package/dist/{chunk-B2NS7WAM.js → chunk-K6WZTDM7.js} +229 -58
- package/dist/chunk-K6WZTDM7.js.map +1 -0
- package/dist/cli-migrate.cjs +206 -52
- package/dist/cli-migrate.cjs.map +1 -1
- package/dist/cli-migrate.d.cts +21 -7
- package/dist/cli-migrate.d.ts +21 -7
- package/dist/cli-migrate.js +103 -42
- package/dist/cli-migrate.js.map +1 -1
- package/dist/index.cjs +228 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +145 -29
- package/dist/index.d.ts +145 -29
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-B2NS7WAM.js.map +0 -1
package/dist/cli-migrate.d.cts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
interface MigrateArgs {
|
|
3
3
|
help: boolean;
|
|
4
|
-
|
|
4
|
+
apply: boolean;
|
|
5
|
+
switchOver: boolean;
|
|
5
6
|
from?: string;
|
|
6
|
-
|
|
7
|
+
to?: string;
|
|
7
8
|
refreshFields: boolean;
|
|
8
9
|
}
|
|
10
|
+
declare function parseArgs(argv: string[]): MigrateArgs;
|
|
9
11
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
12
|
+
* `amem_notes` → `amem_notes_v2`, and `amem_notes_v2` → `amem_notes_v3`.
|
|
13
|
+
*
|
|
14
|
+
* Derived rather than asked for: the name is an implementation detail of a
|
|
15
|
+
* mechanism the user is not supposed to have to learn, and a wrong guess at it is
|
|
16
|
+
* how you end up with two half-migrated stores.
|
|
13
17
|
*/
|
|
14
|
-
declare function
|
|
18
|
+
declare function deriveTarget(source: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* The collection flags this run was given, so every "now run …" line it prints is
|
|
21
|
+
* copy-pasteable as-is.
|
|
22
|
+
*
|
|
23
|
+
* Without it a mode B operator who passed `--from-collection` would be told to run
|
|
24
|
+
* a bare `amem-migrate --apply`, which falls back to AMEM_COLLECTION and migrates
|
|
25
|
+
* a different store. Only the collection flags are carried: forgetting
|
|
26
|
+
* `--no-refresh-fields` costs an LLM call, forgetting these loses the plot.
|
|
27
|
+
*/
|
|
28
|
+
declare function carried(args: MigrateArgs): string;
|
|
15
29
|
|
|
16
|
-
export { type MigrateArgs, parseArgs };
|
|
30
|
+
export { type MigrateArgs, carried, deriveTarget, parseArgs };
|
package/dist/cli-migrate.d.ts
CHANGED
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
interface MigrateArgs {
|
|
3
3
|
help: boolean;
|
|
4
|
-
|
|
4
|
+
apply: boolean;
|
|
5
|
+
switchOver: boolean;
|
|
5
6
|
from?: string;
|
|
6
|
-
|
|
7
|
+
to?: string;
|
|
7
8
|
refreshFields: boolean;
|
|
8
9
|
}
|
|
10
|
+
declare function parseArgs(argv: string[]): MigrateArgs;
|
|
9
11
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
12
|
+
* `amem_notes` → `amem_notes_v2`, and `amem_notes_v2` → `amem_notes_v3`.
|
|
13
|
+
*
|
|
14
|
+
* Derived rather than asked for: the name is an implementation detail of a
|
|
15
|
+
* mechanism the user is not supposed to have to learn, and a wrong guess at it is
|
|
16
|
+
* how you end up with two half-migrated stores.
|
|
13
17
|
*/
|
|
14
|
-
declare function
|
|
18
|
+
declare function deriveTarget(source: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* The collection flags this run was given, so every "now run …" line it prints is
|
|
21
|
+
* copy-pasteable as-is.
|
|
22
|
+
*
|
|
23
|
+
* Without it a mode B operator who passed `--from-collection` would be told to run
|
|
24
|
+
* a bare `amem-migrate --apply`, which falls back to AMEM_COLLECTION and migrates
|
|
25
|
+
* a different store. Only the collection flags are carried: forgetting
|
|
26
|
+
* `--no-refresh-fields` costs an LLM call, forgetting these loses the plot.
|
|
27
|
+
*/
|
|
28
|
+
declare function carried(args: MigrateArgs): string;
|
|
15
29
|
|
|
16
|
-
export { type MigrateArgs, parseArgs };
|
|
30
|
+
export { type MigrateArgs, carried, deriveTarget, parseArgs };
|
package/dist/cli-migrate.js
CHANGED
|
@@ -1,30 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
collectionDimRaw,
|
|
4
|
+
countPointsRaw,
|
|
3
5
|
getCollection,
|
|
6
|
+
getEmbeddingDim,
|
|
4
7
|
getEmbeddingModel,
|
|
5
|
-
migrateCollection
|
|
6
|
-
|
|
8
|
+
migrateCollection,
|
|
9
|
+
resolveAliasRaw,
|
|
10
|
+
scrollIdsRaw,
|
|
11
|
+
switchToMigrated
|
|
12
|
+
} from "./chunk-K6WZTDM7.js";
|
|
7
13
|
|
|
8
14
|
// src/cli-migrate.ts
|
|
9
|
-
var USAGE = `amem-migrate \u2014
|
|
15
|
+
var USAGE = `amem-migrate \u2014 move a memory store onto a different embedding model
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
amem-migrate what state the store is in, and what comes next
|
|
18
|
+
amem-migrate --apply do the next step; safe to interrupt and re-run
|
|
19
|
+
amem-migrate --switch put the new store behind the old name (irreversible)
|
|
12
20
|
|
|
13
21
|
Options
|
|
14
|
-
--
|
|
15
|
-
--
|
|
16
|
-
--
|
|
17
|
-
|
|
18
|
-
had them. Faster, and makes no LLM calls at all.
|
|
22
|
+
--from-collection <name> the store to migrate. Defaults to AMEM_COLLECTION.
|
|
23
|
+
--to-collection <name> where to build it. Derived from the source if omitted.
|
|
24
|
+
--no-refresh-fields skip re-extracting keywords for notes that never had
|
|
25
|
+
them. Makes the run completely offline.
|
|
19
26
|
-h, --help
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
Migrates onto amem's current default unless AMEM_EMBED_MODEL says otherwise:
|
|
22
29
|
|
|
23
|
-
AMEM_EMBED_MODEL=
|
|
24
|
-
npx --package=@amemhq/core amem-migrate --to amem_notes_v2 --apply
|
|
30
|
+
AMEM_EMBED_MODEL=Alibaba-NLP/gte-multilingual-base amem-migrate --apply
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
Nothing before --switch touches the original. If a run looks wrong, delete the
|
|
33
|
+
target and start again.`;
|
|
28
34
|
function parseArgs(argv) {
|
|
29
35
|
const value = (flag) => {
|
|
30
36
|
const i = argv.indexOf(flag);
|
|
@@ -32,55 +38,110 @@ function parseArgs(argv) {
|
|
|
32
38
|
};
|
|
33
39
|
return {
|
|
34
40
|
help: argv.includes("-h") || argv.includes("--help"),
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
apply: argv.includes("--apply"),
|
|
42
|
+
switchOver: argv.includes("--switch"),
|
|
43
|
+
from: value("--from-collection"),
|
|
44
|
+
to: value("--to-collection"),
|
|
38
45
|
refreshFields: !argv.includes("--no-refresh-fields")
|
|
39
46
|
};
|
|
40
47
|
}
|
|
48
|
+
function deriveTarget(source) {
|
|
49
|
+
const m = source.match(/^(.*)_v(\d+)$/);
|
|
50
|
+
return m ? `${m[1]}_v${Number(m[2]) + 1}` : `${source}_v2`;
|
|
51
|
+
}
|
|
52
|
+
function carried(args) {
|
|
53
|
+
return (args.from ? ` --from-collection ${args.from}` : "") + (args.to ? ` --to-collection ${args.to}` : "");
|
|
54
|
+
}
|
|
55
|
+
async function detect(from, to) {
|
|
56
|
+
const alias = await resolveAliasRaw(from);
|
|
57
|
+
if (alias !== null) return { kind: "switched", points: await countPointsRaw(from) };
|
|
58
|
+
const sourceDim = await collectionDimRaw(from);
|
|
59
|
+
if (sourceDim === null) return { kind: "no-source" };
|
|
60
|
+
const modelDim = await getEmbeddingDim();
|
|
61
|
+
if (sourceDim === modelDim) return { kind: "already-current", model: getEmbeddingModel() };
|
|
62
|
+
const notes = await countPointsRaw(from);
|
|
63
|
+
const targetDim = await collectionDimRaw(to);
|
|
64
|
+
if (targetDim === null) return { kind: "not-started", notes };
|
|
65
|
+
const done = (await scrollIdsRaw(to)).size;
|
|
66
|
+
return done >= notes ? { kind: "ready-to-switch", notes } : { kind: "partial", done, notes };
|
|
67
|
+
}
|
|
41
68
|
async function main() {
|
|
42
69
|
const args = parseArgs(process.argv.slice(2));
|
|
43
70
|
if (args.help) {
|
|
44
71
|
console.log(USAGE);
|
|
45
72
|
return;
|
|
46
73
|
}
|
|
47
|
-
const to = args.to;
|
|
48
|
-
if (!to) {
|
|
49
|
-
console.error("amem-migrate: --to <collection> is required\n");
|
|
50
|
-
console.error(USAGE);
|
|
51
|
-
process.exitCode = 1;
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
74
|
const from = args.from ?? getCollection();
|
|
55
|
-
const
|
|
75
|
+
const to = args.to ?? deriveTarget(from);
|
|
76
|
+
const flags = carried(args);
|
|
77
|
+
const phase = await detect(from, to);
|
|
78
|
+
console.log(`store: ${from}`);
|
|
56
79
|
console.log(`model: ${getEmbeddingModel()}`);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
80
|
+
switch (phase.kind) {
|
|
81
|
+
case "no-source":
|
|
82
|
+
console.error(`
|
|
83
|
+
No collection named "${from}". Nothing to migrate.`);
|
|
84
|
+
process.exitCode = 1;
|
|
85
|
+
return;
|
|
86
|
+
case "switched":
|
|
87
|
+
console.log(`
|
|
88
|
+
"${from}" is already an alias \u2014 ${phase.points} notes, nothing to do.`);
|
|
89
|
+
return;
|
|
90
|
+
case "already-current":
|
|
91
|
+
console.log(`
|
|
92
|
+
Already on ${phase.model}. Nothing to migrate.`);
|
|
93
|
+
return;
|
|
94
|
+
case "not-started":
|
|
95
|
+
if (!args.apply) {
|
|
96
|
+
console.log(`
|
|
97
|
+
${phase.notes} notes to rebuild into "${to}".`);
|
|
98
|
+
console.log(`Run "amem-migrate${flags} --apply" to start. "${from}" is only read.`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
break;
|
|
102
|
+
case "partial":
|
|
103
|
+
if (!args.apply) {
|
|
104
|
+
console.log(`
|
|
105
|
+
${phase.done} of ${phase.notes} rebuilt into "${to}".`);
|
|
106
|
+
console.log(`Run "amem-migrate${flags} --apply" to carry on from there.`);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
case "ready-to-switch":
|
|
111
|
+
if (!args.switchOver) {
|
|
112
|
+
console.log(`
|
|
113
|
+
All ${phase.notes} notes are in "${to}". "${from}" is untouched.`);
|
|
114
|
+
console.log(`Check it, then run "amem-migrate${flags} --switch" to put "${to}" behind the name "${from}".`);
|
|
115
|
+
console.log(`That drops "${from}" and cannot be undone.`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
await switchToMigrated({ name: from, to });
|
|
119
|
+
console.log(`
|
|
120
|
+
Done. Nothing to change in your config \u2014 "${from}" now resolves to "${to}".`);
|
|
121
|
+
return;
|
|
69
122
|
}
|
|
70
|
-
if (
|
|
71
|
-
console.
|
|
72
|
-
|
|
123
|
+
if (args.switchOver) {
|
|
124
|
+
console.error(`
|
|
125
|
+
Not finished yet \u2014 run "amem-migrate${flags} --apply" until it is before switching.`);
|
|
126
|
+
process.exitCode = 1;
|
|
73
127
|
return;
|
|
74
128
|
}
|
|
129
|
+
const result = await migrateCollection({ from, to, dryRun: false, refreshFields: args.refreshFields });
|
|
75
130
|
console.log(`
|
|
76
|
-
${result.migrated
|
|
77
|
-
|
|
131
|
+
${result.migrated + result.skipped} of ${result.total} rebuilt.`);
|
|
132
|
+
if (result.migrated + result.skipped >= result.total) {
|
|
133
|
+
console.log(`Check "${to}", then run "amem-migrate${flags} --switch".`);
|
|
134
|
+
} else {
|
|
135
|
+
console.log(`Run "amem-migrate${flags} --apply" again to carry on.`);
|
|
136
|
+
}
|
|
78
137
|
}
|
|
79
138
|
main().catch((err) => {
|
|
80
139
|
console.error(`amem-migrate: ${err instanceof Error ? err.message : String(err)}`);
|
|
81
140
|
process.exitCode = 1;
|
|
82
141
|
});
|
|
83
142
|
export {
|
|
143
|
+
carried,
|
|
144
|
+
deriveTarget,
|
|
84
145
|
parseArgs
|
|
85
146
|
};
|
|
86
147
|
//# sourceMappingURL=cli-migrate.js.map
|
package/dist/cli-migrate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli-migrate.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * amem-migrate — rebuild a collection under a different embedding model.\n *\n * This exists because `EmbeddingDimensionMismatchError` has to end in a command\n * someone can paste. Describing the procedure in prose is what the error message\n * used to do, and prose is not runnable at 2am when memory has stopped working.\n *\n * The engine is a library and never migrates on its own — re-embedding a whole\n * store is minutes of work and a decision the operator makes, not something an\n * import should trigger. So the policy lives here, in a command, and\n * `migrateCollection()` stays a plain function for anyone embedding the engine.\n */\nimport { migrateCollection } from './migrate.js'\nimport { getCollection } from './storage.js'\nimport { getEmbeddingModel } from './embedding.js'\n\nconst USAGE = `amem-migrate — rebuild a collection under the current embedding model\n\n npx --package=@amemhq/core amem-migrate --to <collection> [options]\n\nOptions\n --to <name> Target collection. Required. Must not already hold points.\n --from <name> Source collection. Defaults to AMEM_COLLECTION.\n --apply Actually write. Without this it is a dry run.\n --no-refresh-fields Skip re-extracting keywords/tags for notes that never\n had them. Faster, and makes no LLM calls at all.\n -h, --help\n\nThe model is whatever AMEM_EMBED_MODEL says, so set that first:\n\n AMEM_EMBED_MODEL=Xenova/bge-m3 \\\\\n npx --package=@amemhq/core amem-migrate --to amem_notes_v2 --apply\n\nThe source is only ever read. If the result looks wrong, point AMEM_COLLECTION\nback at it and nothing has been lost.`\n\nexport interface MigrateArgs {\n help: boolean\n to?: string\n from?: string\n dryRun: boolean\n refreshFields: boolean\n}\n\n/**\n * Exported so the defaults can be asserted. `dryRun` in particular: invert that\n * boolean and the command writes to a store while telling the operator it is\n * only looking.\n */\nexport function parseArgs(argv: string[]): MigrateArgs {\n const value = (flag: string): string | undefined => {\n const i = argv.indexOf(flag)\n return i === -1 ? undefined : argv[i + 1]\n }\n return {\n help: argv.includes('-h') || argv.includes('--help'),\n to: value('--to'),\n from: value('--from'),\n dryRun: !argv.includes('--apply'),\n refreshFields: !argv.includes('--no-refresh-fields'),\n }\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2))\n if (args.help) {\n console.log(USAGE)\n return\n }\n\n const to = args.to\n if (!to) {\n console.error('amem-migrate: --to <collection> is required\\n')\n console.error(USAGE)\n process.exitCode = 1\n return\n }\n\n const from = args.from ?? getCollection()\n const { dryRun, refreshFields } = args\n\n console.log(`model: ${getEmbeddingModel()}`)\n console.log(`from: ${from}`)\n console.log(`to: ${to}`)\n console.log(`mode: ${dryRun ? 'dry run — nothing will be written' : 'APPLY'}\\n`)\n\n const result = await migrateCollection({ from, to, dryRun, refreshFields })\n\n console.log(`\\n${result.total} notes in source (${result.sourceDim}-dim)`)\n console.log(`target is ${result.targetDim}-dim`)\n if (result.missingDerived > 0) {\n console.log(\n `${result.missingDerived} note(s) predate the extraction pipeline` +\n (refreshFields ? `, ${result.refreshed} re-extracted` : ' — skipped (--no-refresh-fields)')\n )\n }\n\n if (dryRun) {\n console.log(`\\nNothing was written. Re-run with --apply to migrate.`)\n return\n }\n\n console.log(`\\n${result.migrated} notes written to \"${to}\".`)\n console.log(`Point AMEM_COLLECTION at \"${to}\" to start using it. \"${from}\" is untouched.`)\n}\n\nmain().catch((err: unknown) => {\n console.error(`amem-migrate: ${err instanceof Error ? err.message : String(err)}`)\n process.exitCode = 1\n})\n"],"mappings":";;;;;;;;AAiBA,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCP,SAAS,UAAU,MAA6B;AACrD,QAAM,QAAQ,CAAC,SAAqC;AAClD,UAAM,IAAI,KAAK,QAAQ,IAAI;AAC3B,WAAO,MAAM,KAAK,SAAY,KAAK,IAAI,CAAC;AAAA,EAC1C;AACA,SAAO;AAAA,IACL,MAAM,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,QAAQ;AAAA,IACnD,IAAI,MAAM,MAAM;AAAA,IAChB,MAAM,MAAM,QAAQ;AAAA,IACpB,QAAQ,CAAC,KAAK,SAAS,SAAS;AAAA,IAChC,eAAe,CAAC,KAAK,SAAS,qBAAqB;AAAA,EACrD;AACF;AAEA,eAAe,OAAsB;AACnC,QAAM,OAAO,UAAU,QAAQ,KAAK,MAAM,CAAC,CAAC;AAC5C,MAAI,KAAK,MAAM;AACb,YAAQ,IAAI,KAAK;AACjB;AAAA,EACF;AAEA,QAAM,KAAK,KAAK;AAChB,MAAI,CAAC,IAAI;AACP,YAAQ,MAAM,+CAA+C;AAC7D,YAAQ,MAAM,KAAK;AACnB,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,OAAO,KAAK,QAAQ,cAAc;AACxC,QAAM,EAAE,QAAQ,cAAc,IAAI;AAElC,UAAQ,IAAI,WAAW,kBAAkB,CAAC,EAAE;AAC5C,UAAQ,IAAI,WAAW,IAAI,EAAE;AAC7B,UAAQ,IAAI,WAAW,EAAE,EAAE;AAC3B,UAAQ,IAAI,WAAW,SAAS,2CAAsC,OAAO;AAAA,CAAI;AAEjF,QAAM,SAAS,MAAM,kBAAkB,EAAE,MAAM,IAAI,QAAQ,cAAc,CAAC;AAE1E,UAAQ,IAAI;AAAA,EAAK,OAAO,KAAK,qBAAqB,OAAO,SAAS,OAAO;AACzE,UAAQ,IAAI,aAAa,OAAO,SAAS,MAAM;AAC/C,MAAI,OAAO,iBAAiB,GAAG;AAC7B,YAAQ;AAAA,MACN,GAAG,OAAO,cAAc,8CACrB,gBAAgB,KAAK,OAAO,SAAS,kBAAkB;AAAA,IAC5D;AAAA,EACF;AAEA,MAAI,QAAQ;AACV,YAAQ,IAAI;AAAA,qDAAwD;AACpE;AAAA,EACF;AAEA,UAAQ,IAAI;AAAA,EAAK,OAAO,QAAQ,sBAAsB,EAAE,IAAI;AAC5D,UAAQ,IAAI,6BAA6B,EAAE,yBAAyB,IAAI,iBAAiB;AAC3F;AAEA,KAAK,EAAE,MAAM,CAAC,QAAiB;AAC7B,UAAQ,MAAM,iBAAiB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AACjF,UAAQ,WAAW;AACrB,CAAC;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli-migrate.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * amem-migrate — move a memory store onto a different embedding model.\n *\n * Written for the person who got here from an error message, not for someone\n * embedding the engine. A developer using `@amemhq/core` directly has\n * `migrateCollection()` and `switchToMigrated()` and can sequence them however\n * their deployment wants; this is the other audience, who installed a plugin and\n * whose memory has stopped working.\n *\n * So it takes no decisions from the caller that it can take itself. It works out\n * which phase the store is in, does the next safe thing, and prints the one\n * command that comes after. The target collection name is derived; nobody has to\n * know Qdrant has collections at all.\n *\n * Exactly one step is irreversible — dropping the old collection to free its name\n * for the alias — and that one has its own flag rather than being the tail of a\n * run that started out read-only.\n */\nimport { migrateCollection, switchToMigrated } from './migrate.js'\nimport { getCollection, collectionDimRaw, countPointsRaw, scrollIdsRaw, resolveAliasRaw } from './storage.js'\nimport { getEmbeddingModel, getEmbeddingDim } from './embedding.js'\n\nconst USAGE = `amem-migrate — move a memory store onto a different embedding model\n\n amem-migrate what state the store is in, and what comes next\n amem-migrate --apply do the next step; safe to interrupt and re-run\n amem-migrate --switch put the new store behind the old name (irreversible)\n\nOptions\n --from-collection <name> the store to migrate. Defaults to AMEM_COLLECTION.\n --to-collection <name> where to build it. Derived from the source if omitted.\n --no-refresh-fields skip re-extracting keywords for notes that never had\n them. Makes the run completely offline.\n -h, --help\n\nMigrates onto amem's current default unless AMEM_EMBED_MODEL says otherwise:\n\n AMEM_EMBED_MODEL=Alibaba-NLP/gte-multilingual-base amem-migrate --apply\n\nNothing before --switch touches the original. If a run looks wrong, delete the\ntarget and start again.`\n\nexport interface MigrateArgs {\n help: boolean\n apply: boolean\n switchOver: boolean\n from?: string\n to?: string\n refreshFields: boolean\n}\n\nexport function parseArgs(argv: string[]): MigrateArgs {\n const value = (flag: string): string | undefined => {\n const i = argv.indexOf(flag)\n return i === -1 ? undefined : argv[i + 1]\n }\n return {\n help: argv.includes('-h') || argv.includes('--help'),\n apply: argv.includes('--apply'),\n switchOver: argv.includes('--switch'),\n from: value('--from-collection'),\n to: value('--to-collection'),\n refreshFields: !argv.includes('--no-refresh-fields'),\n }\n}\n\n/**\n * `amem_notes` → `amem_notes_v2`, and `amem_notes_v2` → `amem_notes_v3`.\n *\n * Derived rather than asked for: the name is an implementation detail of a\n * mechanism the user is not supposed to have to learn, and a wrong guess at it is\n * how you end up with two half-migrated stores.\n */\nexport function deriveTarget(source: string): string {\n const m = source.match(/^(.*)_v(\\d+)$/)\n return m ? `${m[1]}_v${Number(m[2]) + 1}` : `${source}_v2`\n}\n\n/**\n * The collection flags this run was given, so every \"now run …\" line it prints is\n * copy-pasteable as-is.\n *\n * Without it a mode B operator who passed `--from-collection` would be told to run\n * a bare `amem-migrate --apply`, which falls back to AMEM_COLLECTION and migrates\n * a different store. Only the collection flags are carried: forgetting\n * `--no-refresh-fields` costs an LLM call, forgetting these loses the plot.\n */\nexport function carried(args: MigrateArgs): string {\n return (args.from ? ` --from-collection ${args.from}` : '') + (args.to ? ` --to-collection ${args.to}` : '')\n}\n\ntype Phase =\n | { kind: 'no-source' }\n | { kind: 'already-current'; model: string }\n | { kind: 'not-started'; notes: number }\n | { kind: 'partial'; done: number; notes: number }\n | { kind: 'ready-to-switch'; notes: number }\n | { kind: 'switched'; points: number }\n\nasync function detect(from: string, to: string): Promise<Phase> {\n const alias = await resolveAliasRaw(from)\n if (alias !== null) return { kind: 'switched', points: await countPointsRaw(from) }\n\n const sourceDim = await collectionDimRaw(from)\n if (sourceDim === null) return { kind: 'no-source' }\n\n const modelDim = await getEmbeddingDim()\n if (sourceDim === modelDim) return { kind: 'already-current', model: getEmbeddingModel() }\n\n const notes = await countPointsRaw(from)\n const targetDim = await collectionDimRaw(to)\n if (targetDim === null) return { kind: 'not-started', notes }\n\n const done = (await scrollIdsRaw(to)).size\n return done >= notes ? { kind: 'ready-to-switch', notes } : { kind: 'partial', done, notes }\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2))\n if (args.help) {\n console.log(USAGE)\n return\n }\n\n const from = args.from ?? getCollection()\n const to = args.to ?? deriveTarget(from)\n const flags = carried(args)\n const phase = await detect(from, to)\n\n console.log(`store: ${from}`)\n console.log(`model: ${getEmbeddingModel()}`)\n\n switch (phase.kind) {\n case 'no-source':\n console.error(`\\nNo collection named \"${from}\". Nothing to migrate.`)\n process.exitCode = 1\n return\n\n case 'switched':\n console.log(`\\n\"${from}\" is already an alias — ${phase.points} notes, nothing to do.`)\n return\n\n case 'already-current':\n console.log(`\\nAlready on ${phase.model}. Nothing to migrate.`)\n return\n\n case 'not-started':\n if (!args.apply) {\n console.log(`\\n${phase.notes} notes to rebuild into \"${to}\".`)\n console.log(`Run \"amem-migrate${flags} --apply\" to start. \"${from}\" is only read.`)\n return\n }\n break\n\n case 'partial':\n if (!args.apply) {\n console.log(`\\n${phase.done} of ${phase.notes} rebuilt into \"${to}\".`)\n console.log(`Run \"amem-migrate${flags} --apply\" to carry on from there.`)\n return\n }\n break\n\n case 'ready-to-switch':\n if (!args.switchOver) {\n console.log(`\\nAll ${phase.notes} notes are in \"${to}\". \"${from}\" is untouched.`)\n console.log(`Check it, then run \"amem-migrate${flags} --switch\" to put \"${to}\" behind the name \"${from}\".`)\n console.log(`That drops \"${from}\" and cannot be undone.`)\n return\n }\n await switchToMigrated({ name: from, to })\n console.log(`\\nDone. Nothing to change in your config — \"${from}\" now resolves to \"${to}\".`)\n return\n }\n\n if (args.switchOver) {\n console.error(`\\nNot finished yet — run \"amem-migrate${flags} --apply\" until it is before switching.`)\n process.exitCode = 1\n return\n }\n\n const result = await migrateCollection({ from, to, dryRun: false, refreshFields: args.refreshFields })\n console.log(`\\n${result.migrated + result.skipped} of ${result.total} rebuilt.`)\n if (result.migrated + result.skipped >= result.total) {\n console.log(`Check \"${to}\", then run \"amem-migrate${flags} --switch\".`)\n } else {\n console.log(`Run \"amem-migrate${flags} --apply\" again to carry on.`)\n }\n}\n\nmain().catch((err: unknown) => {\n console.error(`amem-migrate: ${err instanceof Error ? err.message : String(err)}`)\n process.exitCode = 1\n})\n"],"mappings":"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","names":[]}
|