@remnic/cli 1.0.17 → 1.0.19

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.
Files changed (2) hide show
  1. package/dist/index.js +82 -5
  2. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -88,7 +88,9 @@ import {
88
88
  formatProcedureStatsText,
89
89
  parseXrayCliOptions,
90
90
  renderXray,
91
+ OFFLINE_SYNC_APPLY_MAX_BODY_BYTES,
91
92
  OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
93
+ OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES,
92
94
  applyOfflineSyncSnapshot,
93
95
  buildOfflineSyncChangeset,
94
96
  buildOfflineSyncSnapshot,
@@ -6687,8 +6689,19 @@ async function fetchOfflineFiles(args) {
6687
6689
  }
6688
6690
  );
6689
6691
  }
6690
- var OFFLINE_SYNC_DIRECT_HYDRATE_MIN_BYTES = 16 * 1024 * 1024;
6692
+ var OFFLINE_SYNC_DIRECT_DEFAULT_MIN_BYTES = 16 * 1024 * 1024;
6691
6693
  var OFFLINE_SYNC_FILES_CONTENT_MAX_BATCH_BYTES = 8 * 1024 * 1024;
6694
+ var OFFLINE_SYNC_APPLY_MAX_REQUEST_BYTES = Math.floor(OFFLINE_SYNC_APPLY_MAX_BODY_BYTES / 2);
6695
+ var OFFLINE_SYNC_DIRECT_PUSH_INLINE_MARGIN_BYTES = 256 * 1024;
6696
+ var OFFLINE_SYNC_INLINE_CONTENT_MAX_BYTES = Math.max(
6697
+ 1,
6698
+ Math.floor((OFFLINE_SYNC_APPLY_MAX_REQUEST_BYTES - OFFLINE_SYNC_DIRECT_PUSH_INLINE_MARGIN_BYTES) * 3 / 4)
6699
+ );
6700
+ var OFFLINE_SYNC_DIRECT_PUSH_MIN_BYTES = Math.min(
6701
+ OFFLINE_SYNC_DIRECT_DEFAULT_MIN_BYTES,
6702
+ OFFLINE_SYNC_INLINE_CONTENT_MAX_BYTES
6703
+ );
6704
+ var OFFLINE_SYNC_DIRECT_HYDRATE_MIN_BYTES = OFFLINE_SYNC_DIRECT_PUSH_MIN_BYTES;
6692
6705
  function parseOfflineHeaderNumber(headers, name) {
6693
6706
  const raw = headers.get(name);
6694
6707
  if (raw === null) throw new Error(`offline file content response omitted ${name}`);
@@ -6837,7 +6850,7 @@ function shouldDirectHydrateOfflineFile(options) {
6837
6850
  function offlineDirectPushFiles(options) {
6838
6851
  const base = offlineFileStateMap(options.baseFiles);
6839
6852
  return options.currentFiles.filter((current) => {
6840
- if (current.bytes < OFFLINE_SYNC_DIRECT_HYDRATE_MIN_BYTES) return false;
6853
+ if (current.bytes < OFFLINE_SYNC_DIRECT_PUSH_MIN_BYTES) return false;
6841
6854
  return current.sha256 !== base.get(current.path)?.sha256;
6842
6855
  }).sort((left, right) => right.bytes - left.bytes || left.path.localeCompare(right.path));
6843
6856
  }
@@ -6850,6 +6863,7 @@ function resolveOfflineDirectHydrationPath(memoryDir, relPath) {
6850
6863
  }
6851
6864
  return target;
6852
6865
  }
6866
+ var OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES = OFFLINE_SYNC_FILE_CONTENT_TRANSFER_CHUNK_BYTES;
6853
6867
  async function pushOfflineFileContent(args) {
6854
6868
  if (args.readFileChunks) {
6855
6869
  return pushOfflineFileContentFromChunkReader(args);
@@ -6862,7 +6876,7 @@ async function pushOfflineFileContent(args) {
6862
6876
  path: args.file.path,
6863
6877
  offset,
6864
6878
  length: Math.min(
6865
- OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
6879
+ OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES,
6866
6880
  Math.max(1, args.file.bytes - offset)
6867
6881
  ),
6868
6882
  includeTranscripts: args.includeTranscripts,
@@ -6907,7 +6921,7 @@ async function pushOfflineFileContentFromChunkReader(args) {
6907
6921
  root: path11.resolve(args.memoryDir),
6908
6922
  path: args.file.path,
6909
6923
  filePath,
6910
- chunkSize: OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES
6924
+ chunkSize: OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES
6911
6925
  });
6912
6926
  let offset = 0;
6913
6927
  let pending = null;
@@ -7126,7 +7140,39 @@ async function hydrateOfflineSnapshotContent(args) {
7126
7140
  })
7127
7141
  };
7128
7142
  }
7129
- async function pushOfflineChanges(args) {
7143
+ function chunkOfflineChangesetApplyBatches(changeset, namespace, maxRequestBytes = OFFLINE_SYNC_APPLY_MAX_REQUEST_BYTES) {
7144
+ if (!Number.isInteger(maxRequestBytes) || maxRequestBytes < 1) {
7145
+ throw new Error("offline sync apply max request bytes must be a positive integer");
7146
+ }
7147
+ const chunks = [];
7148
+ let current = [];
7149
+ const requestBytesFor = (changes) => Buffer.byteLength(JSON.stringify({
7150
+ namespace,
7151
+ changeset: {
7152
+ ...changeset,
7153
+ changes
7154
+ }
7155
+ }), "utf-8");
7156
+ for (const change of changeset.changes) {
7157
+ const withChange = [...current, change];
7158
+ if (current.length > 0 && requestBytesFor(withChange) > maxRequestBytes) {
7159
+ chunks.push({ ...changeset, changes: current });
7160
+ current = [];
7161
+ }
7162
+ const singleBytes = requestBytesFor([...current, change]);
7163
+ if (singleBytes > maxRequestBytes) {
7164
+ throw new Error(
7165
+ `offline sync change for ${change.path} exceeds the apply request size budget; retry after direct-push threshold is lowered`
7166
+ );
7167
+ }
7168
+ current.push(change);
7169
+ }
7170
+ if (current.length > 0) {
7171
+ chunks.push({ ...changeset, changes: current });
7172
+ }
7173
+ return chunks;
7174
+ }
7175
+ async function postOfflineChangesBatch(args) {
7130
7176
  return fetchOfflineJson(
7131
7177
  offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/apply"),
7132
7178
  args.token,
@@ -7139,6 +7185,31 @@ async function pushOfflineChanges(args) {
7139
7185
  }
7140
7186
  );
7141
7187
  }
7188
+ async function pushOfflineChanges(args) {
7189
+ let namespace = args.namespace ?? "";
7190
+ let appliedUpserts = 0;
7191
+ let appliedDeletes = 0;
7192
+ let skipped = 0;
7193
+ const conflicts = [];
7194
+ for (const changeset of chunkOfflineChangesetApplyBatches(args.changeset, args.namespace)) {
7195
+ const result = await postOfflineChangesBatch({
7196
+ ...args,
7197
+ changeset
7198
+ });
7199
+ namespace = result.namespace || namespace;
7200
+ appliedUpserts += result.appliedUpserts;
7201
+ appliedDeletes += result.appliedDeletes;
7202
+ skipped += result.skipped;
7203
+ conflicts.push(...result.conflicts);
7204
+ }
7205
+ return {
7206
+ namespace,
7207
+ appliedUpserts,
7208
+ appliedDeletes,
7209
+ skipped,
7210
+ conflicts
7211
+ };
7212
+ }
7142
7213
  function parseOfflineIntervalMs(args) {
7143
7214
  const raw = resolveRequiredValueFlag(args, "--interval-ms");
7144
7215
  if (raw === void 0) return 6e4;
@@ -10604,12 +10675,17 @@ if (argv1Base.endsWith("remnic.ts") || argv1Base.endsWith("remnic.js") || argv1B
10604
10675
  }
10605
10676
  export {
10606
10677
  BENCHMARK_CATALOG,
10678
+ OFFLINE_SYNC_APPLY_MAX_REQUEST_BYTES,
10679
+ OFFLINE_SYNC_DIRECT_HYDRATE_MIN_BYTES,
10680
+ OFFLINE_SYNC_DIRECT_PUSH_MIN_BYTES,
10681
+ OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES,
10607
10682
  TAXONOMY_RESOLVE_BOOLEAN_FLAGS,
10608
10683
  TAXONOMY_RESOLVE_VALUE_FLAGS,
10609
10684
  __benchDatasetTestHooks,
10610
10685
  buildBenchRuntimeProfileRequest,
10611
10686
  buildPackageBenchExecutionPlans,
10612
10687
  buildQueryRecallRequest,
10688
+ chunkOfflineChangesetApplyBatches,
10613
10689
  chunkOfflineFileContentBatches,
10614
10690
  extractXrayRawArgs,
10615
10691
  formatOfflineLargeFilePushFailureMessage,
@@ -10628,6 +10704,7 @@ export {
10628
10704
  resolveSyncSourceDir,
10629
10705
  runTrainingExport,
10630
10706
  runXrayCommand,
10707
+ shouldDirectHydrateOfflineFile,
10631
10708
  stripConfigArgv,
10632
10709
  stripResolveFlags
10633
10710
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/cli",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
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.3",
30
- "@remnic/core": "^1.1.23",
31
- "@remnic/server": "^1.0.5"
29
+ "@remnic/plugin-pi": "^1.0.5",
30
+ "@remnic/server": "^1.0.5",
31
+ "@remnic/core": "^1.1.25"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@remnic/bench": "^1.0.0",
@@ -73,13 +73,13 @@
73
73
  "devDependencies": {
74
74
  "tsup": "^8.5.1",
75
75
  "typescript": "^5.9.3",
76
- "@remnic/bench": "1.0.1",
77
76
  "@remnic/export-weclone": "1.0.1",
77
+ "@remnic/bench": "1.0.1",
78
78
  "@remnic/import-weclone": "1.0.1",
79
- "@remnic/import-chatgpt": "0.1.0",
80
- "@remnic/import-gemini": "0.1.0",
81
79
  "@remnic/import-claude": "0.1.0",
80
+ "@remnic/import-gemini": "0.1.0",
82
81
  "@remnic/import-lossless-claw": "0.1.1",
82
+ "@remnic/import-chatgpt": "0.1.0",
83
83
  "@remnic/import-mem0": "0.1.0",
84
84
  "@remnic/import-supermemory": "0.1.2"
85
85
  },