@remnic/cli 1.0.13 → 1.0.15
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/dist/index.js +34 -25
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -97,6 +97,7 @@ import {
|
|
|
97
97
|
offlineSyncStateFromSnapshot,
|
|
98
98
|
readOfflineSyncState,
|
|
99
99
|
summarizeOfflineSyncChangeset,
|
|
100
|
+
summarizeOfflineSyncPendingChanges,
|
|
100
101
|
writeOfflineSyncState,
|
|
101
102
|
buildActionConfidenceInputFromOptions,
|
|
102
103
|
evaluateActionConfidence,
|
|
@@ -6670,6 +6671,7 @@ async function fetchOfflineFiles(args) {
|
|
|
6670
6671
|
);
|
|
6671
6672
|
}
|
|
6672
6673
|
var OFFLINE_SYNC_DIRECT_HYDRATE_MIN_BYTES = 16 * 1024 * 1024;
|
|
6674
|
+
var OFFLINE_SYNC_FILES_CONTENT_MAX_BATCH_BYTES = 8 * 1024 * 1024;
|
|
6673
6675
|
function parseOfflineHeaderNumber(headers, name) {
|
|
6674
6676
|
const raw = headers.get(name);
|
|
6675
6677
|
if (raw === null) throw new Error(`offline file content response omitted ${name}`);
|
|
@@ -6761,16 +6763,16 @@ async function readFirstOfflineSyncState(paths) {
|
|
|
6761
6763
|
function offlineFileStateMap(files) {
|
|
6762
6764
|
return new Map(files.map((file) => [file.path, file]));
|
|
6763
6765
|
}
|
|
6764
|
-
function
|
|
6766
|
+
function offlineSnapshotContentFilesForApply(options) {
|
|
6765
6767
|
const base = offlineFileStateMap(options.baseFiles);
|
|
6766
6768
|
const current = options.currentFiles ? offlineFileStateMap(options.currentFiles) : null;
|
|
6767
|
-
const
|
|
6769
|
+
const files = [];
|
|
6768
6770
|
for (const incoming of options.snapshot.files) {
|
|
6769
6771
|
if (current?.get(incoming.path)?.sha256 === incoming.sha256) continue;
|
|
6770
6772
|
if (base.get(incoming.path)?.sha256 === incoming.sha256) continue;
|
|
6771
|
-
|
|
6773
|
+
files.push(incoming);
|
|
6772
6774
|
}
|
|
6773
|
-
return
|
|
6775
|
+
return files.sort((left, right) => left.path.localeCompare(right.path));
|
|
6774
6776
|
}
|
|
6775
6777
|
function shouldDirectHydrateOfflineFile(options) {
|
|
6776
6778
|
if (options.incoming.bytes < OFFLINE_SYNC_DIRECT_HYDRATE_MIN_BYTES) return false;
|
|
@@ -6852,19 +6854,22 @@ async function directHydrateLargeOfflineFiles(args) {
|
|
|
6852
6854
|
}
|
|
6853
6855
|
return hydrated;
|
|
6854
6856
|
}
|
|
6855
|
-
function
|
|
6857
|
+
function chunkOfflineFileContentBatches(files) {
|
|
6856
6858
|
const chunks = [];
|
|
6857
6859
|
let current = [];
|
|
6858
|
-
let
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6860
|
+
let currentPathBytes = 256;
|
|
6861
|
+
let currentContentBytes = 0;
|
|
6862
|
+
for (const file of files) {
|
|
6863
|
+
const pathCost = Buffer.byteLength(JSON.stringify(file.path), "utf-8") + 1;
|
|
6864
|
+
if (current.length > 0 && (current.length >= 1e3 || currentPathBytes + pathCost > 96e3 || currentContentBytes + file.bytes > OFFLINE_SYNC_FILES_CONTENT_MAX_BATCH_BYTES)) {
|
|
6862
6865
|
chunks.push(current);
|
|
6863
6866
|
current = [];
|
|
6864
|
-
|
|
6867
|
+
currentPathBytes = 256;
|
|
6868
|
+
currentContentBytes = 0;
|
|
6865
6869
|
}
|
|
6866
|
-
current.push(
|
|
6867
|
-
|
|
6870
|
+
current.push(file);
|
|
6871
|
+
currentPathBytes += pathCost;
|
|
6872
|
+
currentContentBytes += file.bytes;
|
|
6868
6873
|
}
|
|
6869
6874
|
if (current.length > 0) chunks.push(current);
|
|
6870
6875
|
return chunks;
|
|
@@ -6878,32 +6883,34 @@ function isMissingOfflineContentError(error) {
|
|
|
6878
6883
|
return /^missing decoded content for /.test(message);
|
|
6879
6884
|
}
|
|
6880
6885
|
async function hydrateOfflineSnapshotContent(args) {
|
|
6881
|
-
const
|
|
6882
|
-
|
|
6886
|
+
const snapshot = normalizeOfflineSyncSnapshot(args.snapshot);
|
|
6887
|
+
const neededFiles = offlineSnapshotContentFilesForApply({
|
|
6888
|
+
snapshot,
|
|
6883
6889
|
baseFiles: args.baseFiles,
|
|
6884
6890
|
currentFiles: args.currentFiles
|
|
6885
6891
|
});
|
|
6886
|
-
if (
|
|
6887
|
-
const expectedByPath = new Map(
|
|
6892
|
+
if (neededFiles.length === 0) return { ...args.snapshot, files: snapshot.files };
|
|
6893
|
+
const expectedByPath = new Map(snapshot.files.map((file) => [file.path, file]));
|
|
6888
6894
|
const contentByPath = /* @__PURE__ */ new Map();
|
|
6895
|
+
const updatedByPath = /* @__PURE__ */ new Map();
|
|
6889
6896
|
try {
|
|
6890
|
-
for (const batch of
|
|
6897
|
+
for (const batch of chunkOfflineFileContentBatches(neededFiles)) {
|
|
6891
6898
|
const partial = await fetchOfflineFiles({
|
|
6892
6899
|
remoteUrl: args.remoteUrl,
|
|
6893
6900
|
token: args.token,
|
|
6894
6901
|
namespace: args.namespace,
|
|
6895
6902
|
includeTranscripts: args.includeTranscripts,
|
|
6896
|
-
paths: batch
|
|
6903
|
+
paths: batch.map((file) => file.path)
|
|
6897
6904
|
});
|
|
6898
6905
|
for (const file of partial.files) {
|
|
6899
6906
|
const expected = expectedByPath.get(file.path);
|
|
6900
6907
|
if (!expected) continue;
|
|
6901
|
-
if (file.sha256 !== expected.sha256 || file.bytes !== expected.bytes) {
|
|
6902
|
-
throw new Error(`remote file changed while fetching offline content: ${file.path}`);
|
|
6903
|
-
}
|
|
6904
6908
|
if (typeof file.contentBase64 !== "string") {
|
|
6905
6909
|
throw new Error(`remote offline content response omitted contentBase64 for ${file.path}`);
|
|
6906
6910
|
}
|
|
6911
|
+
if (file.sha256 !== expected.sha256 || file.bytes !== expected.bytes || file.mtimeMs !== expected.mtimeMs) {
|
|
6912
|
+
updatedByPath.set(file.path, file);
|
|
6913
|
+
}
|
|
6907
6914
|
contentByPath.set(file.path, file.contentBase64);
|
|
6908
6915
|
}
|
|
6909
6916
|
}
|
|
@@ -6917,7 +6924,7 @@ async function hydrateOfflineSnapshotContent(args) {
|
|
|
6917
6924
|
includeContent: true
|
|
6918
6925
|
});
|
|
6919
6926
|
}
|
|
6920
|
-
const missing =
|
|
6927
|
+
const missing = neededFiles.map((file) => file.path).filter((relPath) => !contentByPath.has(relPath));
|
|
6921
6928
|
if (missing.length > 0) {
|
|
6922
6929
|
throw new Error(
|
|
6923
6930
|
`remote offline content response omitted ${missing.length} changed file${missing.length === 1 ? "" : "s"}; retry sync`
|
|
@@ -6925,7 +6932,9 @@ async function hydrateOfflineSnapshotContent(args) {
|
|
|
6925
6932
|
}
|
|
6926
6933
|
return {
|
|
6927
6934
|
...args.snapshot,
|
|
6928
|
-
files:
|
|
6935
|
+
files: snapshot.files.map((file) => {
|
|
6936
|
+
const updated = updatedByPath.get(file.path);
|
|
6937
|
+
if (updated) return updated;
|
|
6929
6938
|
const contentBase64 = contentByPath.get(file.path);
|
|
6930
6939
|
return contentBase64 === void 0 ? file : { ...file, contentBase64 };
|
|
6931
6940
|
})
|
|
@@ -7269,14 +7278,13 @@ Environment fallbacks:
|
|
|
7269
7278
|
});
|
|
7270
7279
|
}
|
|
7271
7280
|
const storageIo = await createOfflineStorageIo(memoryDir);
|
|
7272
|
-
const
|
|
7281
|
+
const summary = await summarizeOfflineSyncPendingChanges({
|
|
7273
7282
|
root: memoryDir,
|
|
7274
7283
|
sourceId: localOfflineSourceId(memoryDir),
|
|
7275
7284
|
baseFiles: state?.baseFiles ?? [],
|
|
7276
7285
|
includeTranscripts,
|
|
7277
7286
|
readFile: storageIo.readFile
|
|
7278
7287
|
});
|
|
7279
|
-
const summary = summarizeOfflineSyncChangeset(changeset);
|
|
7280
7288
|
if (json) {
|
|
7281
7289
|
console.log(JSON.stringify({ statePath: statePath ?? null, state, pending: summary }, null, 2));
|
|
7282
7290
|
} else {
|
|
@@ -10228,6 +10236,7 @@ export {
|
|
|
10228
10236
|
buildBenchRuntimeProfileRequest,
|
|
10229
10237
|
buildPackageBenchExecutionPlans,
|
|
10230
10238
|
buildQueryRecallRequest,
|
|
10239
|
+
chunkOfflineFileContentBatches,
|
|
10231
10240
|
extractXrayRawArgs,
|
|
10232
10241
|
getBenchUsageText,
|
|
10233
10242
|
hasFlag,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
4
4
|
"description": "CLI for Remnic memory — init, query, doctor, daemon management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"yaml": "^2.4.2",
|
|
29
|
-
"@remnic/plugin-pi": "^1.0.
|
|
30
|
-
"@remnic/
|
|
31
|
-
"@remnic/
|
|
29
|
+
"@remnic/plugin-pi": "^1.0.1",
|
|
30
|
+
"@remnic/server": "^1.0.5",
|
|
31
|
+
"@remnic/core": "^1.1.21"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@remnic/bench": "^1.0.0",
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
"@remnic/import-weclone": "1.0.1",
|
|
79
79
|
"@remnic/import-chatgpt": "0.1.0",
|
|
80
80
|
"@remnic/import-claude": "0.1.0",
|
|
81
|
+
"@remnic/import-gemini": "0.1.0",
|
|
81
82
|
"@remnic/import-lossless-claw": "0.1.1",
|
|
82
|
-
"@remnic/import-supermemory": "0.1.2",
|
|
83
83
|
"@remnic/import-mem0": "0.1.0",
|
|
84
|
-
"@remnic/import-
|
|
84
|
+
"@remnic/import-supermemory": "0.1.2"
|
|
85
85
|
},
|
|
86
86
|
"license": "MIT",
|
|
87
87
|
"repository": {
|