@amemhq/core 1.1.0 → 2.1.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-XEMQZNLD.js} +257 -57
- package/dist/chunk-XEMQZNLD.js.map +1 -0
- package/dist/cli-migrate.cjs +259 -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 +128 -43
- package/dist/cli-migrate.js.map +1 -1
- package/dist/index.cjs +256 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +167 -29
- package/dist/index.d.ts +167 -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.cjs
CHANGED
|
@@ -31,6 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
// src/cli-migrate.ts
|
|
32
32
|
var cli_migrate_exports = {};
|
|
33
33
|
__export(cli_migrate_exports, {
|
|
34
|
+
carried: () => carried,
|
|
35
|
+
deriveTarget: () => deriveTarget,
|
|
34
36
|
parseArgs: () => parseArgs
|
|
35
37
|
});
|
|
36
38
|
module.exports = __toCommonJS(cli_migrate_exports);
|
|
@@ -40,9 +42,10 @@ var pipeline = null;
|
|
|
40
42
|
var extractor = null;
|
|
41
43
|
var loadedKey = null;
|
|
42
44
|
var cachedDim = null;
|
|
43
|
-
var DEFAULT_EMBEDDING_MODEL = "Xenova/
|
|
45
|
+
var DEFAULT_EMBEDDING_MODEL = "Xenova/bge-m3";
|
|
46
|
+
var pinnedModel = null;
|
|
44
47
|
function getEmbeddingModel() {
|
|
45
|
-
return process.env.AMEM_EMBED_MODEL?.trim() || DEFAULT_EMBEDDING_MODEL;
|
|
48
|
+
return process.env.AMEM_EMBED_MODEL?.trim() || pinnedModel || DEFAULT_EMBEDDING_MODEL;
|
|
46
49
|
}
|
|
47
50
|
var CLS_POOLED_MODELS = /* @__PURE__ */ new Set([
|
|
48
51
|
"bge-m3",
|
|
@@ -69,6 +72,27 @@ function getEmbeddingDevice() {
|
|
|
69
72
|
function getEmbeddingDtype() {
|
|
70
73
|
return process.env.AMEM_EMBED_DTYPE?.trim() || void 0;
|
|
71
74
|
}
|
|
75
|
+
function applyModelPaths(env) {
|
|
76
|
+
const cache = process.env.AMEM_MODEL_CACHE?.trim();
|
|
77
|
+
if (cache) env.cacheDir = cache;
|
|
78
|
+
const local = process.env.AMEM_MODEL_DIR?.trim();
|
|
79
|
+
if (local) {
|
|
80
|
+
env.localModelPath = local;
|
|
81
|
+
env.allowLocalModels = true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function makeProgressReporter() {
|
|
85
|
+
const lastPct = /* @__PURE__ */ new Map();
|
|
86
|
+
return (e) => {
|
|
87
|
+
if (e.status !== "progress" || !e.file || typeof e.progress !== "number") return;
|
|
88
|
+
if (!e.file.endsWith(".onnx") && !e.file.endsWith(".onnx_data")) return;
|
|
89
|
+
const pct = Math.floor(e.progress / 10) * 10;
|
|
90
|
+
if (lastPct.get(e.file) === pct) return;
|
|
91
|
+
lastPct.set(e.file, pct);
|
|
92
|
+
const size = e.total ? ` of ${(e.total / 1e9).toFixed(2)} GB` : "";
|
|
93
|
+
console.log(`[amem] downloading ${e.file}: ${pct}%${size}`);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
72
96
|
function extractorKey() {
|
|
73
97
|
return `${getEmbeddingModel()}|${getEmbeddingDevice() ?? ""}|${getEmbeddingDtype() ?? ""}`;
|
|
74
98
|
}
|
|
@@ -78,11 +102,13 @@ async function getExtractor() {
|
|
|
78
102
|
if (!pipeline) {
|
|
79
103
|
const mod = await import("@huggingface/transformers");
|
|
80
104
|
pipeline = mod.pipeline;
|
|
105
|
+
applyModelPaths(mod.env);
|
|
81
106
|
}
|
|
82
107
|
const device = getEmbeddingDevice();
|
|
83
108
|
const dtype = getEmbeddingDtype();
|
|
84
109
|
extractor = await pipeline("feature-extraction", getEmbeddingModel(), {
|
|
85
110
|
revision: "main",
|
|
111
|
+
progress_callback: makeProgressReporter(),
|
|
86
112
|
// Omitted entirely when unset, so an unconfigured install gets exactly the
|
|
87
113
|
// library defaults it got before these existed.
|
|
88
114
|
...device ? { device } : {},
|
|
@@ -202,6 +228,47 @@ async function createCollectionRaw(collection, size) {
|
|
|
202
228
|
async function upsertPointsRaw(collection, points) {
|
|
203
229
|
await qdrant("PUT", `/collections/${collection}/points?wait=true`, { points });
|
|
204
230
|
}
|
|
231
|
+
async function scrollIdsRaw(collection, limit = 1e4) {
|
|
232
|
+
const ids = /* @__PURE__ */ new Set();
|
|
233
|
+
let offset = void 0;
|
|
234
|
+
for (; ; ) {
|
|
235
|
+
const body = { with_payload: false, with_vector: false, limit };
|
|
236
|
+
if (offset !== void 0 && offset !== null) body.offset = offset;
|
|
237
|
+
const res = await qdrant("POST", `/collections/${collection}/points/scroll`, body);
|
|
238
|
+
for (const p of res.points) ids.add(String(p.id));
|
|
239
|
+
offset = res.next_page_offset;
|
|
240
|
+
if (offset === void 0 || offset === null || res.points.length === 0) break;
|
|
241
|
+
}
|
|
242
|
+
return ids;
|
|
243
|
+
}
|
|
244
|
+
async function deleteCollectionRaw(collection) {
|
|
245
|
+
await qdrant("DELETE", `/collections/${collection}`);
|
|
246
|
+
}
|
|
247
|
+
async function snapshotCollectionRaw(collection) {
|
|
248
|
+
const r = await qdrant("POST", `/collections/${collection}/snapshots`);
|
|
249
|
+
return { name: r.name, size: r.size ?? 0 };
|
|
250
|
+
}
|
|
251
|
+
async function resolveAliasRaw(alias) {
|
|
252
|
+
try {
|
|
253
|
+
const res = await qdrant("GET", `/aliases`);
|
|
254
|
+
return res.aliases.find((a) => a.alias_name === alias)?.collection_name ?? null;
|
|
255
|
+
} catch {
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async function createAliasRaw(alias, collection) {
|
|
260
|
+
await qdrant("POST", `/collections/aliases`, {
|
|
261
|
+
actions: [{ create_alias: { collection_name: collection, alias_name: alias } }]
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async function setAliasRaw(alias, collection) {
|
|
265
|
+
await qdrant("POST", `/collections/aliases`, {
|
|
266
|
+
actions: [
|
|
267
|
+
{ delete_alias: { alias_name: alias } },
|
|
268
|
+
{ create_alias: { collection_name: collection, alias_name: alias } }
|
|
269
|
+
]
|
|
270
|
+
});
|
|
271
|
+
}
|
|
205
272
|
function noteToPoint(note) {
|
|
206
273
|
return {
|
|
207
274
|
id: note.id,
|
|
@@ -795,8 +862,19 @@ async function migrateCollection(opts) {
|
|
|
795
862
|
);
|
|
796
863
|
if (dryRun) {
|
|
797
864
|
log("[migrate] dry run \u2014 nothing written. Pass dryRun: false to apply.");
|
|
798
|
-
return {
|
|
865
|
+
return {
|
|
866
|
+
total: notes.length,
|
|
867
|
+
missingDerived,
|
|
868
|
+
refreshed: 0,
|
|
869
|
+
migrated: 0,
|
|
870
|
+
skipped: 0,
|
|
871
|
+
sourceDim,
|
|
872
|
+
targetDim,
|
|
873
|
+
model,
|
|
874
|
+
dryRun: true
|
|
875
|
+
};
|
|
799
876
|
}
|
|
877
|
+
let alreadyDone = /* @__PURE__ */ new Set();
|
|
800
878
|
const existingTargetDim = await collectionDimRaw(to);
|
|
801
879
|
if (existingTargetDim === null) {
|
|
802
880
|
await createCollectionRaw(to, targetDim);
|
|
@@ -805,9 +883,17 @@ async function migrateCollection(opts) {
|
|
|
805
883
|
if (existingTargetDim !== targetDim) {
|
|
806
884
|
throw new Error(`migrate: target "${to}" exists at ${existingTargetDim}d but the model produces ${targetDim}d`);
|
|
807
885
|
}
|
|
808
|
-
const
|
|
809
|
-
if (
|
|
810
|
-
|
|
886
|
+
const present = await scrollIdsRaw(to);
|
|
887
|
+
if (present.size > 0) {
|
|
888
|
+
const sourceIds = new Set(notes.map((n) => n.id));
|
|
889
|
+
const foreign = [...present].filter((id) => !sourceIds.has(id));
|
|
890
|
+
if (foreign.length > 0) {
|
|
891
|
+
throw new Error(
|
|
892
|
+
`migrate: target "${to}" holds ${foreign.length} point(s) that are not in "${from}" (e.g. ${foreign[0]}). That is not an interrupted migration \u2014 use a different target.`
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
alreadyDone = present;
|
|
896
|
+
log(`[migrate] resuming: ${present.size} of ${notes.length} already in ${to}`);
|
|
811
897
|
}
|
|
812
898
|
}
|
|
813
899
|
let refreshed = 0;
|
|
@@ -821,6 +907,7 @@ async function migrateCollection(opts) {
|
|
|
821
907
|
buffer = [];
|
|
822
908
|
};
|
|
823
909
|
for (const note of notes) {
|
|
910
|
+
if (alreadyDone.has(note.id)) continue;
|
|
824
911
|
if (refreshFields && missingDerivedFields(note)) {
|
|
825
912
|
try {
|
|
826
913
|
const built = await llmConstructNote(note.content);
|
|
@@ -836,7 +923,7 @@ async function migrateCollection(opts) {
|
|
|
836
923
|
buffer.push(point);
|
|
837
924
|
if (buffer.length >= BATCH) {
|
|
838
925
|
await flush();
|
|
839
|
-
log(`[migrate] ${migrated}/${notes.length}`);
|
|
926
|
+
log(`[migrate] ${alreadyDone.size + migrated}/${notes.length}`);
|
|
840
927
|
}
|
|
841
928
|
}
|
|
842
929
|
await flush();
|
|
@@ -844,82 +931,200 @@ async function migrateCollection(opts) {
|
|
|
844
931
|
if (finalCount !== notes.length) {
|
|
845
932
|
warn(`[migrate] target holds ${finalCount} point(s) but the source had ${notes.length} \u2014 check before switching`);
|
|
846
933
|
}
|
|
847
|
-
log(
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
934
|
+
log(`[migrate] done: ${migrated} written, ${alreadyDone.size} already present, ${refreshed} re-extracted.`);
|
|
935
|
+
return {
|
|
936
|
+
total: notes.length,
|
|
937
|
+
missingDerived,
|
|
938
|
+
refreshed,
|
|
939
|
+
migrated,
|
|
940
|
+
skipped: alreadyDone.size,
|
|
941
|
+
sourceDim,
|
|
942
|
+
targetDim,
|
|
943
|
+
model,
|
|
944
|
+
dryRun: false
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
async function switchToMigrated(opts) {
|
|
948
|
+
const { name, to } = opts;
|
|
949
|
+
const log = opts.logger?.info ?? ((m) => console.log(m));
|
|
950
|
+
if (name === to) throw new Error(`switch: "${name}" and "${to}" are the same collection`);
|
|
951
|
+
let snap;
|
|
952
|
+
const already = await resolveAliasRaw(name);
|
|
953
|
+
if (already === to) {
|
|
954
|
+
log(`[switch] "${name}" already points at "${to}" \u2014 nothing to do`);
|
|
955
|
+
return { name, to, moved: await countPointsRaw(to) };
|
|
956
|
+
}
|
|
957
|
+
const targetCount = await countPointsRaw(to);
|
|
958
|
+
if (targetCount === 0) throw new Error(`switch: "${to}" is empty \u2014 migrate into it first`);
|
|
959
|
+
if (already === null) {
|
|
960
|
+
const sourceCount = await countPointsRaw(name);
|
|
961
|
+
if (targetCount < sourceCount) {
|
|
962
|
+
throw new Error(
|
|
963
|
+
`switch: "${to}" holds ${targetCount} point(s) but "${name}" still holds ${sourceCount}. The migration is not finished \u2014 run it again before switching.`
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
log(`[switch] verified ${targetCount} in "${to}" against ${sourceCount} in "${name}"`);
|
|
967
|
+
if (opts.snapshot !== false) {
|
|
968
|
+
snap = await snapshotCollectionRaw(name);
|
|
969
|
+
log(`[switch] snapshotted "${name}" \u2192 ${snap.name} (${(snap.size / 1e6).toFixed(0)} MB)`);
|
|
970
|
+
}
|
|
971
|
+
await deleteCollectionRaw(name);
|
|
972
|
+
log(`[switch] dropped "${name}"`);
|
|
973
|
+
await createAliasRaw(name, to);
|
|
974
|
+
} else {
|
|
975
|
+
await setAliasRaw(name, to);
|
|
976
|
+
}
|
|
977
|
+
log(`[switch] "${name}" now resolves to "${to}"`);
|
|
978
|
+
return { name, to, moved: targetCount, snapshot: snap };
|
|
851
979
|
}
|
|
852
980
|
|
|
853
981
|
// src/cli-migrate.ts
|
|
854
|
-
var USAGE = `amem-migrate \u2014
|
|
982
|
+
var USAGE = `amem-migrate \u2014 move a memory store onto a different embedding model
|
|
855
983
|
|
|
856
|
-
|
|
984
|
+
amem-migrate what state the store is in, and what comes next
|
|
985
|
+
amem-migrate --apply do the next step; safe to interrupt and re-run
|
|
986
|
+
amem-migrate --switch put the new store behind the old name (irreversible)
|
|
857
987
|
|
|
858
988
|
Options
|
|
859
|
-
--
|
|
860
|
-
--
|
|
861
|
-
--
|
|
862
|
-
|
|
863
|
-
had them. Faster, and makes no LLM calls at all.
|
|
989
|
+
--from-collection <name> the store to migrate. Defaults to AMEM_COLLECTION.
|
|
990
|
+
--to-collection <name> where to build it. Derived from the source if omitted.
|
|
991
|
+
--no-refresh-fields skip re-extracting keywords for notes that never had
|
|
992
|
+
them. Makes the run completely offline.
|
|
864
993
|
-h, --help
|
|
865
994
|
|
|
866
|
-
|
|
995
|
+
AMEM_MODEL_CACHE=<dir> where model weights are cached. Set the same value
|
|
996
|
+
everywhere and the plugin and this command share one
|
|
997
|
+
copy instead of downloading it each.
|
|
998
|
+
AMEM_MODEL_DIR=<dir> read weights already on disk instead of downloading.
|
|
999
|
+
|
|
1000
|
+
Migrates onto amem's current default unless AMEM_EMBED_MODEL says otherwise:
|
|
1001
|
+
|
|
1002
|
+
AMEM_EMBED_MODEL=Alibaba-NLP/gte-multilingual-base amem-migrate --apply
|
|
867
1003
|
|
|
868
|
-
|
|
869
|
-
|
|
1004
|
+
Stop your agent before --apply, not before this. The bare run only downloads and
|
|
1005
|
+
reports, and the download is the long part \u2014 leaving the agent up through it costs
|
|
1006
|
+
nothing, while writing underneath a running agent means notes arrive after the
|
|
1007
|
+
rebuild has read them and you have to run --apply again.
|
|
870
1008
|
|
|
871
|
-
|
|
872
|
-
|
|
1009
|
+
Roughly: the download is your bandwidth (2.27 GB for the default), the rebuild is
|
|
1010
|
+
your CPU (about 3 notes a second on an M4), and notes missing keywords cost one
|
|
1011
|
+
LLM call each.
|
|
1012
|
+
|
|
1013
|
+
Nothing before --switch touches the original. If a run looks wrong, delete the
|
|
1014
|
+
target and start again.`;
|
|
873
1015
|
function parseArgs(argv) {
|
|
874
1016
|
const value = (flag) => {
|
|
875
1017
|
const i = argv.indexOf(flag);
|
|
876
1018
|
return i === -1 ? void 0 : argv[i + 1];
|
|
877
1019
|
};
|
|
878
1020
|
return {
|
|
879
|
-
help
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1021
|
+
// `help` as a bare word too. Without it, typing what most CLIs accept starts
|
|
1022
|
+
// a multi-gigabyte model download instead of printing anything.
|
|
1023
|
+
help: argv.includes("-h") || argv.includes("--help") || argv[0] === "help",
|
|
1024
|
+
apply: argv.includes("--apply"),
|
|
1025
|
+
switchOver: argv.includes("--switch"),
|
|
1026
|
+
from: value("--from-collection"),
|
|
1027
|
+
to: value("--to-collection"),
|
|
883
1028
|
refreshFields: !argv.includes("--no-refresh-fields")
|
|
884
1029
|
};
|
|
885
1030
|
}
|
|
1031
|
+
function deriveTarget(source) {
|
|
1032
|
+
const m = source.match(/^(.*)_v(\d+)$/);
|
|
1033
|
+
return m ? `${m[1]}_v${Number(m[2]) + 1}` : `${source}_v2`;
|
|
1034
|
+
}
|
|
1035
|
+
function carried(args) {
|
|
1036
|
+
return (args.from ? ` --from-collection ${args.from}` : "") + (args.to ? ` --to-collection ${args.to}` : "");
|
|
1037
|
+
}
|
|
1038
|
+
async function detect(from, to) {
|
|
1039
|
+
const alias = await resolveAliasRaw(from);
|
|
1040
|
+
if (alias !== null) return { kind: "switched", points: await countPointsRaw(from) };
|
|
1041
|
+
const sourceDim = await collectionDimRaw(from);
|
|
1042
|
+
if (sourceDim === null) return { kind: "no-source" };
|
|
1043
|
+
const modelDim = await getEmbeddingDim();
|
|
1044
|
+
if (sourceDim === modelDim) return { kind: "already-current", model: getEmbeddingModel() };
|
|
1045
|
+
const notes = await countPointsRaw(from);
|
|
1046
|
+
const targetDim = await collectionDimRaw(to);
|
|
1047
|
+
if (targetDim === null) return { kind: "not-started", notes };
|
|
1048
|
+
const done = (await scrollIdsRaw(to)).size;
|
|
1049
|
+
return done >= notes ? { kind: "ready-to-switch", notes } : { kind: "partial", done, notes };
|
|
1050
|
+
}
|
|
886
1051
|
async function main() {
|
|
887
1052
|
const args = parseArgs(process.argv.slice(2));
|
|
888
1053
|
if (args.help) {
|
|
889
1054
|
console.log(USAGE);
|
|
890
1055
|
return;
|
|
891
1056
|
}
|
|
892
|
-
const to = args.to;
|
|
893
|
-
if (!to) {
|
|
894
|
-
console.error("amem-migrate: --to <collection> is required\n");
|
|
895
|
-
console.error(USAGE);
|
|
896
|
-
process.exitCode = 1;
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
1057
|
const from = args.from ?? getCollection();
|
|
900
|
-
const
|
|
1058
|
+
const to = args.to ?? deriveTarget(from);
|
|
1059
|
+
const flags = carried(args);
|
|
1060
|
+
const phase = await detect(from, to);
|
|
1061
|
+
console.log(`store: ${from}`);
|
|
901
1062
|
console.log(`model: ${getEmbeddingModel()}`);
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1063
|
+
switch (phase.kind) {
|
|
1064
|
+
case "no-source":
|
|
1065
|
+
console.error(`
|
|
1066
|
+
No collection named "${from}". Nothing to migrate.`);
|
|
1067
|
+
process.exitCode = 1;
|
|
1068
|
+
return;
|
|
1069
|
+
case "switched":
|
|
1070
|
+
console.log(`
|
|
1071
|
+
"${from}" is already an alias \u2014 ${phase.points} notes, nothing to do.`);
|
|
1072
|
+
return;
|
|
1073
|
+
case "already-current":
|
|
1074
|
+
console.log(`
|
|
1075
|
+
Already on ${phase.model}. Nothing to migrate.`);
|
|
1076
|
+
return;
|
|
1077
|
+
case "not-started":
|
|
1078
|
+
if (!args.apply) {
|
|
1079
|
+
console.log(`
|
|
1080
|
+
${phase.notes} notes to rebuild into "${to}".`);
|
|
1081
|
+
console.log(`Run "amem-migrate${flags} --apply" to start. "${from}" is only read.`);
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
break;
|
|
1085
|
+
case "partial":
|
|
1086
|
+
if (!args.apply) {
|
|
1087
|
+
console.log(`
|
|
1088
|
+
${phase.done} of ${phase.notes} rebuilt into "${to}".`);
|
|
1089
|
+
console.log(`Run "amem-migrate${flags} --apply" to carry on from there.`);
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
break;
|
|
1093
|
+
case "ready-to-switch":
|
|
1094
|
+
if (!args.switchOver) {
|
|
1095
|
+
console.log(`
|
|
1096
|
+
All ${phase.notes} notes are in "${to}". "${from}" is untouched.`);
|
|
1097
|
+
console.log(`Check it, then run "amem-migrate${flags} --switch" to put "${to}" behind the name "${from}".`);
|
|
1098
|
+
console.log(`That drops "${from}" and cannot be undone.`);
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
{
|
|
1102
|
+
const res = await switchToMigrated({ name: from, to });
|
|
1103
|
+
console.log(`
|
|
1104
|
+
Done. Nothing to change in your config \u2014 "${from}" now resolves to "${to}".`);
|
|
1105
|
+
if (res.snapshot) {
|
|
1106
|
+
console.log(`
|
|
1107
|
+
The old store is kept as a snapshot, ${(res.snapshot.size / 1e6).toFixed(0)} MB:`);
|
|
1108
|
+
console.log(` <qdrant storage>/snapshots/${from}/${res.snapshot.name}`);
|
|
1109
|
+
console.log(`Delete that file once the new store has proven itself. Nothing else will.`);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return;
|
|
914
1113
|
}
|
|
915
|
-
if (
|
|
916
|
-
console.
|
|
917
|
-
|
|
1114
|
+
if (args.switchOver) {
|
|
1115
|
+
console.error(`
|
|
1116
|
+
Not finished yet \u2014 run "amem-migrate${flags} --apply" until it is before switching.`);
|
|
1117
|
+
process.exitCode = 1;
|
|
918
1118
|
return;
|
|
919
1119
|
}
|
|
1120
|
+
const result = await migrateCollection({ from, to, dryRun: false, refreshFields: args.refreshFields });
|
|
920
1121
|
console.log(`
|
|
921
|
-
${result.migrated
|
|
922
|
-
|
|
1122
|
+
${result.migrated + result.skipped} of ${result.total} rebuilt.`);
|
|
1123
|
+
if (result.migrated + result.skipped >= result.total) {
|
|
1124
|
+
console.log(`Check "${to}", then run "amem-migrate${flags} --switch".`);
|
|
1125
|
+
} else {
|
|
1126
|
+
console.log(`Run "amem-migrate${flags} --apply" again to carry on.`);
|
|
1127
|
+
}
|
|
923
1128
|
}
|
|
924
1129
|
main().catch((err) => {
|
|
925
1130
|
console.error(`amem-migrate: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -927,6 +1132,8 @@ main().catch((err) => {
|
|
|
927
1132
|
});
|
|
928
1133
|
// Annotate the CommonJS export names for ESM import in node:
|
|
929
1134
|
0 && (module.exports = {
|
|
1135
|
+
carried,
|
|
1136
|
+
deriveTarget,
|
|
930
1137
|
parseArgs
|
|
931
1138
|
});
|
|
932
1139
|
//# sourceMappingURL=cli-migrate.cjs.map
|