@remnic/cli 1.0.15 → 1.0.17

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 +383 -8
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import fs7 from "fs";
3
3
  import os from "os";
4
4
  import path11 from "path";
5
- import { createHash } from "crypto";
5
+ import { createDecipheriv, createHash } from "crypto";
6
6
  import * as childProcess2 from "child_process";
7
7
  import { fileURLToPath as fileURLToPath4 } from "url";
8
8
  import {
@@ -95,8 +95,8 @@ import {
95
95
  defaultOfflineSyncStatePath,
96
96
  normalizeOfflineSyncSnapshot,
97
97
  offlineSyncStateFromSnapshot,
98
+ readOfflineSyncFileContentChunk,
98
99
  readOfflineSyncState,
99
- summarizeOfflineSyncChangeset,
100
100
  summarizeOfflineSyncPendingChanges,
101
101
  writeOfflineSyncState,
102
102
  buildActionConfidenceInputFromOptions,
@@ -106,7 +106,24 @@ import {
106
106
  forkCapsule,
107
107
  readForkLineage
108
108
  } from "@remnic/core";
109
- import { keyring, readHeader, secureStoreDir } from "@remnic/core/secure-store";
109
+ import {
110
+ AUTH_TAG_LENGTH,
111
+ ENVELOPE_HEADER_SIZE,
112
+ ENVELOPE_LAYOUT,
113
+ ENVELOPE_SALT_LENGTH,
114
+ ENVELOPE_VERSION,
115
+ FILE_FORMAT_FLAGS,
116
+ FILE_FORMAT_VERSION,
117
+ IV_LENGTH,
118
+ MAGIC_BYTES,
119
+ MAGIC_HEADER_SIZE,
120
+ SecureStoreLockedError,
121
+ filePathAad,
122
+ isEncryptedFile,
123
+ keyring,
124
+ readHeader,
125
+ secureStoreDir
126
+ } from "@remnic/core/secure-store";
110
127
 
111
128
  // src/optional-module-loader.ts
112
129
  function isSpecifierNotFoundError(err, specifier) {
@@ -6728,6 +6745,41 @@ async function fetchOfflineFileContentChunk(args) {
6728
6745
  content
6729
6746
  };
6730
6747
  }
6748
+ async function postOfflineFileContentChunk(args) {
6749
+ const response = await fetch(
6750
+ offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/apply-file-content", {
6751
+ namespace: args.namespace
6752
+ }),
6753
+ {
6754
+ method: "POST",
6755
+ headers: {
6756
+ authorization: `Bearer ${args.token}`,
6757
+ "content-type": "application/octet-stream",
6758
+ "x-remnic-include-transcripts": args.includeTranscripts ? "true" : "false",
6759
+ "x-remnic-source-id": encodeURIComponent(args.sourceId),
6760
+ "x-remnic-file-path": encodeURIComponent(args.file.path),
6761
+ "x-remnic-file-sha256": args.file.sha256,
6762
+ "x-remnic-file-bytes": String(args.file.bytes),
6763
+ "x-remnic-file-mtime-ms": String(args.file.mtimeMs),
6764
+ "x-remnic-chunk-offset": String(args.offset),
6765
+ ...args.baseSha256 ? { "x-remnic-base-sha256": args.baseSha256 } : {}
6766
+ },
6767
+ body: new Blob([new Uint8Array(args.content)])
6768
+ }
6769
+ );
6770
+ if (!response.ok) {
6771
+ let detail = "";
6772
+ try {
6773
+ detail = await response.text();
6774
+ } catch {
6775
+ detail = "";
6776
+ }
6777
+ throw new Error(
6778
+ `offline sync apply-file-content request failed: ${response.status} ${response.statusText}${detail ? ` - ${detail.slice(0, 500)}` : ""}`
6779
+ );
6780
+ }
6781
+ return await response.json();
6782
+ }
6731
6783
  function resolvedOfflineSnapshotNamespace(snapshot, requestedNamespace) {
6732
6784
  const resolved = typeof snapshot.namespace === "string" && snapshot.namespace.trim().length > 0 ? snapshot.namespace.trim() : void 0;
6733
6785
  return resolved ?? requestedNamespace;
@@ -6782,6 +6834,13 @@ function shouldDirectHydrateOfflineFile(options) {
6782
6834
  }
6783
6835
  return !options.current && !options.base;
6784
6836
  }
6837
+ function offlineDirectPushFiles(options) {
6838
+ const base = offlineFileStateMap(options.baseFiles);
6839
+ return options.currentFiles.filter((current) => {
6840
+ if (current.bytes < OFFLINE_SYNC_DIRECT_HYDRATE_MIN_BYTES) return false;
6841
+ return current.sha256 !== base.get(current.path)?.sha256;
6842
+ }).sort((left, right) => right.bytes - left.bytes || left.path.localeCompare(right.path));
6843
+ }
6785
6844
  function resolveOfflineDirectHydrationPath(memoryDir, relPath) {
6786
6845
  const base = path11.resolve(memoryDir);
6787
6846
  const target = path11.resolve(base, relPath);
@@ -6791,6 +6850,133 @@ function resolveOfflineDirectHydrationPath(memoryDir, relPath) {
6791
6850
  }
6792
6851
  return target;
6793
6852
  }
6853
+ async function pushOfflineFileContent(args) {
6854
+ if (args.readFileChunks) {
6855
+ return pushOfflineFileContentFromChunkReader(args);
6856
+ }
6857
+ let offset = 0;
6858
+ let finalResult = null;
6859
+ while (offset < args.file.bytes || args.file.bytes === 0 && offset === 0) {
6860
+ const chunk = await readOfflineSyncFileContentChunk({
6861
+ root: args.memoryDir,
6862
+ path: args.file.path,
6863
+ offset,
6864
+ length: Math.min(
6865
+ OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
6866
+ Math.max(1, args.file.bytes - offset)
6867
+ ),
6868
+ includeTranscripts: args.includeTranscripts,
6869
+ readFile: args.readFile
6870
+ });
6871
+ if (chunk.path !== args.file.path || chunk.sha256 !== void 0 && chunk.sha256 !== args.file.sha256 || chunk.bytes !== args.file.bytes || chunk.mtimeMs !== args.file.mtimeMs || chunk.offset !== offset) {
6872
+ throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
6873
+ }
6874
+ if (chunk.chunkBytes === 0 && args.file.bytes > 0) {
6875
+ throw new Error(`local offline content chunk was empty before EOF: ${args.file.path}`);
6876
+ }
6877
+ finalResult = await postOfflineFileContentChunk({
6878
+ remoteUrl: args.remoteUrl,
6879
+ token: args.token,
6880
+ namespace: args.namespace,
6881
+ includeTranscripts: args.includeTranscripts,
6882
+ sourceId: args.sourceId,
6883
+ file: args.file,
6884
+ baseSha256: args.baseSha256,
6885
+ offset,
6886
+ content: chunk.content
6887
+ });
6888
+ if (finalResult.conflict) {
6889
+ return finalResult;
6890
+ }
6891
+ offset += chunk.chunkBytes;
6892
+ if (args.file.bytes === 0) break;
6893
+ }
6894
+ if (!finalResult?.done) {
6895
+ throw new Error(`offline sync large-file push did not finish for ${args.file.path}`);
6896
+ }
6897
+ return finalResult;
6898
+ }
6899
+ async function pushOfflineFileContentFromChunkReader(args) {
6900
+ const filePath = resolveOfflineDirectHydrationPath(args.memoryDir, args.file.path);
6901
+ const stat = fs7.statSync(filePath);
6902
+ if (stat.mtimeMs !== args.file.mtimeMs) {
6903
+ throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
6904
+ }
6905
+ const hash = createHash("sha256");
6906
+ const chunks = args.readFileChunks({
6907
+ root: path11.resolve(args.memoryDir),
6908
+ path: args.file.path,
6909
+ filePath,
6910
+ chunkSize: OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES
6911
+ });
6912
+ let offset = 0;
6913
+ let pending = null;
6914
+ let finalResult = null;
6915
+ for await (const rawChunk of chunks) {
6916
+ const chunk = Buffer.from(rawChunk);
6917
+ if (chunk.length === 0) continue;
6918
+ if (chunk.length > OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES) {
6919
+ throw new Error(`local offline content chunk exceeds max size: ${args.file.path}`);
6920
+ }
6921
+ if (pending) {
6922
+ hash.update(pending);
6923
+ finalResult = await postOfflineFileContentChunk({
6924
+ remoteUrl: args.remoteUrl,
6925
+ token: args.token,
6926
+ namespace: args.namespace,
6927
+ includeTranscripts: args.includeTranscripts,
6928
+ sourceId: args.sourceId,
6929
+ file: args.file,
6930
+ baseSha256: args.baseSha256,
6931
+ offset,
6932
+ content: pending
6933
+ });
6934
+ if (finalResult.conflict) {
6935
+ return finalResult;
6936
+ }
6937
+ offset += pending.length;
6938
+ }
6939
+ pending = chunk;
6940
+ }
6941
+ if (pending) hash.update(pending);
6942
+ const finalBytes = offset + (pending?.length ?? 0);
6943
+ const digest = hash.digest("hex");
6944
+ if (digest !== args.file.sha256 || finalBytes !== args.file.bytes) {
6945
+ throw new Error(`local file changed while pushing offline content: ${args.file.path}`);
6946
+ }
6947
+ if (pending) {
6948
+ finalResult = await postOfflineFileContentChunk({
6949
+ remoteUrl: args.remoteUrl,
6950
+ token: args.token,
6951
+ namespace: args.namespace,
6952
+ includeTranscripts: args.includeTranscripts,
6953
+ sourceId: args.sourceId,
6954
+ file: args.file,
6955
+ baseSha256: args.baseSha256,
6956
+ offset,
6957
+ content: pending
6958
+ });
6959
+ if (finalResult.conflict) {
6960
+ return finalResult;
6961
+ }
6962
+ } else if (args.file.bytes === 0) {
6963
+ finalResult = await postOfflineFileContentChunk({
6964
+ remoteUrl: args.remoteUrl,
6965
+ token: args.token,
6966
+ namespace: args.namespace,
6967
+ includeTranscripts: args.includeTranscripts,
6968
+ sourceId: args.sourceId,
6969
+ file: args.file,
6970
+ baseSha256: args.baseSha256,
6971
+ offset: 0,
6972
+ content: Buffer.alloc(0)
6973
+ });
6974
+ }
6975
+ if (!finalResult?.done) {
6976
+ throw new Error(`offline sync large-file push did not finish for ${args.file.path}`);
6977
+ }
6978
+ return finalResult;
6979
+ }
6794
6980
  async function fetchOfflineFileContent(args) {
6795
6981
  const chunks = [];
6796
6982
  const hash = createHash("sha256");
@@ -6978,19 +7164,137 @@ function waitForOfflineInterval(ms, setCancel) {
6978
7164
  async function createOfflineStorageIo(memoryDir) {
6979
7165
  const storage = new StorageManager(memoryDir);
6980
7166
  const header = await readHeader(memoryDir);
7167
+ let secureStoreKey = null;
6981
7168
  if (header) {
6982
7169
  storage.setSecureStoreRequired(true);
6983
7170
  const key = keyring.getKey(secureStoreDir(memoryDir));
6984
7171
  if (key) {
6985
7172
  storage.setSecureStoreKey(key);
7173
+ secureStoreKey = key;
6986
7174
  }
6987
7175
  }
6988
7176
  return {
6989
7177
  readFile: async ({ filePath }) => storage.readOfflineSyncFile(filePath),
7178
+ readFileChunks: ({ filePath, chunkSize }) => readOfflineSyncFileChunks({
7179
+ filePath,
7180
+ memoryDir,
7181
+ secureStoreKey,
7182
+ chunkSize
7183
+ }),
6990
7184
  writeFile: async ({ filePath, content }) => storage.writeOfflineSyncFile(filePath, content),
6991
7185
  deleteFile: async ({ filePath }) => storage.deleteOfflineSyncFile(filePath)
6992
7186
  };
6993
7187
  }
7188
+ async function* readOfflineSyncFileChunks(options) {
7189
+ const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE);
7190
+ if (!isEncryptedFile(header)) {
7191
+ yield* readPlainOfflineFileChunks(options.filePath, options.chunkSize);
7192
+ return;
7193
+ }
7194
+ if (!options.secureStoreKey) {
7195
+ throw new SecureStoreLockedError(
7196
+ `secure-store is locked \u2014 cannot read encrypted file at ${options.filePath}. Run \`remnic secure-store unlock\` to decrypt.`
7197
+ );
7198
+ }
7199
+ yield* readEncryptedOfflineFileChunks({
7200
+ filePath: options.filePath,
7201
+ memoryDir: options.memoryDir,
7202
+ key: options.secureStoreKey,
7203
+ chunkSize: options.chunkSize
7204
+ });
7205
+ }
7206
+ async function readFilePrefix(filePath, length) {
7207
+ const handle = await fs7.promises.open(filePath, "r");
7208
+ try {
7209
+ const out = Buffer.alloc(length);
7210
+ const { bytesRead } = await handle.read(out, 0, length, 0);
7211
+ return out.subarray(0, bytesRead);
7212
+ } finally {
7213
+ await handle.close();
7214
+ }
7215
+ }
7216
+ async function* readPlainOfflineFileChunks(filePath, chunkSize) {
7217
+ const stream = fs7.createReadStream(filePath, { highWaterMark: chunkSize });
7218
+ for await (const chunk of stream) {
7219
+ yield Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
7220
+ }
7221
+ }
7222
+ async function* readEncryptedOfflineFileChunks(options) {
7223
+ const header = await readFilePrefix(options.filePath, MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE);
7224
+ if (header.length < MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE || !isEncryptedFile(header)) {
7225
+ throw new Error(`secure-store encrypted file is truncated: ${options.filePath}`);
7226
+ }
7227
+ const version = header.readUInt8(MAGIC_BYTES.length);
7228
+ const flags = header.readUInt8(MAGIC_BYTES.length + 1);
7229
+ if (version !== FILE_FORMAT_VERSION) {
7230
+ throw new Error(`secure-store file has unsupported version ${version}: ${options.filePath}`);
7231
+ }
7232
+ if (flags !== FILE_FORMAT_FLAGS) {
7233
+ throw new Error(`secure-store file has unsupported flags 0x${flags.toString(16)}: ${options.filePath}`);
7234
+ }
7235
+ const envelopeHeader = header.subarray(MAGIC_HEADER_SIZE);
7236
+ const envelopeVersion = envelopeHeader.readUInt8(ENVELOPE_LAYOUT.version);
7237
+ if (envelopeVersion !== ENVELOPE_VERSION) {
7238
+ throw new Error(`secure-store envelope has unsupported version ${envelopeVersion}: ${options.filePath}`);
7239
+ }
7240
+ const salt = envelopeHeader.subarray(
7241
+ ENVELOPE_LAYOUT.salt,
7242
+ ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH
7243
+ );
7244
+ const iv = envelopeHeader.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH);
7245
+ const authTag = envelopeHeader.subarray(
7246
+ ENVELOPE_LAYOUT.authTag,
7247
+ ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
7248
+ );
7249
+ const decipher = createDecipheriv("aes-256-gcm", options.key, iv, {
7250
+ authTagLength: AUTH_TAG_LENGTH
7251
+ });
7252
+ decipher.setAuthTag(authTag);
7253
+ decipher.setAAD(Buffer.concat([secureStoreEnvelopeHeaderAad(salt), filePathAad(options.filePath, options.memoryDir)]));
7254
+ let pending = Buffer.alloc(0);
7255
+ const stream = fs7.createReadStream(options.filePath, {
7256
+ start: MAGIC_HEADER_SIZE + ENVELOPE_HEADER_SIZE,
7257
+ highWaterMark: options.chunkSize
7258
+ });
7259
+ for await (const encryptedChunk of stream) {
7260
+ const plain = decipher.update(Buffer.isBuffer(encryptedChunk) ? encryptedChunk : Buffer.from(encryptedChunk));
7261
+ if (plain.length > 0) {
7262
+ pending = Buffer.concat([pending, plain], pending.length + plain.length);
7263
+ }
7264
+ while (pending.length >= options.chunkSize) {
7265
+ yield pending.subarray(0, options.chunkSize);
7266
+ pending = pending.subarray(options.chunkSize);
7267
+ }
7268
+ }
7269
+ const finalPlain = decipher.final();
7270
+ if (finalPlain.length > 0) {
7271
+ pending = Buffer.concat([pending, finalPlain], pending.length + finalPlain.length);
7272
+ }
7273
+ while (pending.length >= options.chunkSize) {
7274
+ yield pending.subarray(0, options.chunkSize);
7275
+ pending = pending.subarray(options.chunkSize);
7276
+ }
7277
+ if (pending.length > 0) yield pending;
7278
+ }
7279
+ function secureStoreEnvelopeHeaderAad(salt) {
7280
+ const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
7281
+ out.writeUInt8(ENVELOPE_VERSION, 0);
7282
+ Buffer.from(salt).copy(out, 1);
7283
+ return out;
7284
+ }
7285
+ function formatOfflineLargeFilePushFailureMessage(failures) {
7286
+ const paths = failures.slice(0, 5).map((failure) => `${failure.path}: ${failure.error}`).join("; ");
7287
+ const suffix = failures.length > 5 ? `; +${failures.length - 5} more` : "";
7288
+ return `offline sync large-file push failed for ${failures.length} file${failures.length === 1 ? "" : "s"}: ${paths}${suffix}`;
7289
+ }
7290
+ var OfflineLargeFilePushError = class extends Error {
7291
+ failures;
7292
+ constructor(failures) {
7293
+ super(formatOfflineLargeFilePushFailureMessage(failures));
7294
+ this.name = "OfflineLargeFilePushError";
7295
+ this.failures = failures;
7296
+ }
7297
+ };
6994
7298
  async function runOfflineSyncOnce(options) {
6995
7299
  fs7.mkdirSync(options.memoryDir, { recursive: true });
6996
7300
  let activeStatePath = options.statePath;
@@ -7030,20 +7334,90 @@ async function runOfflineSyncOnce(options) {
7030
7334
  }
7031
7335
  const baseFiles = priorState?.baseFiles ?? [];
7032
7336
  const storageIo = await createOfflineStorageIo(options.memoryDir);
7337
+ const localSourceId = localOfflineSourceId(options.memoryDir);
7338
+ const pendingSummary = await summarizeOfflineSyncPendingChanges({
7339
+ root: options.memoryDir,
7340
+ sourceId: localSourceId,
7341
+ baseFiles,
7342
+ includeTranscripts: options.includeTranscripts,
7343
+ readFile: storageIo.readFile
7344
+ });
7345
+ const currentSnapshotForPush = await buildOfflineSyncSnapshot({
7346
+ root: options.memoryDir,
7347
+ sourceId: localSourceId,
7348
+ includeContent: false,
7349
+ includeTranscripts: options.includeTranscripts,
7350
+ readFile: storageIo.readFile
7351
+ });
7352
+ const baseByPath = offlineFileStateMap(baseFiles);
7353
+ let directPushAppliedUpserts = 0;
7354
+ let directPushSkipped = 0;
7355
+ let directPushNamespace;
7356
+ const directPushConflicts = [];
7357
+ const directPushedPaths = /* @__PURE__ */ new Set();
7358
+ const directPushFailures = [];
7359
+ for (const file of offlineDirectPushFiles({
7360
+ currentFiles: currentSnapshotForPush.files,
7361
+ baseFiles
7362
+ })) {
7363
+ let result;
7364
+ try {
7365
+ result = await pushOfflineFileContent({
7366
+ remoteUrl: options.remoteUrl,
7367
+ token: options.token,
7368
+ namespace: syncNamespace,
7369
+ includeTranscripts: options.includeTranscripts,
7370
+ memoryDir: options.memoryDir,
7371
+ sourceId: localSourceId,
7372
+ file,
7373
+ baseSha256: baseByPath.get(file.path)?.sha256,
7374
+ readFile: storageIo.readFile,
7375
+ readFileChunks: storageIo.readFileChunks
7376
+ });
7377
+ } catch (error) {
7378
+ directPushFailures.push({
7379
+ path: file.path,
7380
+ error: error instanceof Error ? error.message : String(error)
7381
+ });
7382
+ continue;
7383
+ }
7384
+ directPushNamespace = result.namespace ?? directPushNamespace;
7385
+ directPushedPaths.add(file.path);
7386
+ if (result.conflict) {
7387
+ directPushConflicts.push({
7388
+ path: result.conflict.path,
7389
+ reason: result.conflict.reason,
7390
+ ...result.conflict.conflictPath ? { conflictPath: result.conflict.conflictPath } : {}
7391
+ });
7392
+ } else {
7393
+ if (result.applied) directPushAppliedUpserts += 1;
7394
+ if (result.skipped) directPushSkipped += 1;
7395
+ }
7396
+ }
7397
+ if (directPushFailures.length > 0) {
7398
+ throw new OfflineLargeFilePushError(directPushFailures);
7399
+ }
7033
7400
  const changeset = await buildOfflineSyncChangeset({
7034
7401
  root: options.memoryDir,
7035
- sourceId: localOfflineSourceId(options.memoryDir),
7402
+ sourceId: localSourceId,
7036
7403
  baseFiles,
7404
+ excludePaths: [...directPushedPaths],
7037
7405
  includeTranscripts: options.includeTranscripts,
7038
7406
  readFile: storageIo.readFile
7039
7407
  });
7040
- const pendingSummary = summarizeOfflineSyncChangeset(changeset);
7041
- const pushed = changeset.changes.length > 0 ? await pushOfflineChanges({
7408
+ const pushedInline = changeset.changes.length > 0 ? await pushOfflineChanges({
7042
7409
  remoteUrl: options.remoteUrl,
7043
7410
  token: options.token,
7044
7411
  namespace: syncNamespace,
7045
7412
  changeset
7046
7413
  }) : null;
7414
+ const pushed = directPushedPaths.size > 0 || pushedInline ? {
7415
+ namespace: pushedInline?.namespace ?? directPushNamespace ?? syncNamespace ?? "",
7416
+ appliedUpserts: (pushedInline?.appliedUpserts ?? 0) + directPushAppliedUpserts,
7417
+ appliedDeletes: pushedInline?.appliedDeletes ?? 0,
7418
+ skipped: (pushedInline?.skipped ?? 0) + directPushSkipped,
7419
+ conflicts: [...directPushConflicts, ...pushedInline?.conflicts ?? []]
7420
+ } : null;
7047
7421
  const remoteSnapshotMetadata = await fetchOfflineSnapshot({
7048
7422
  remoteUrl: options.remoteUrl,
7049
7423
  token: options.token,
@@ -7053,7 +7427,7 @@ async function runOfflineSyncOnce(options) {
7053
7427
  });
7054
7428
  const currentSnapshot = await buildOfflineSyncSnapshot({
7055
7429
  root: options.memoryDir,
7056
- sourceId: localOfflineSourceId(options.memoryDir),
7430
+ sourceId: localSourceId,
7057
7431
  includeContent: false,
7058
7432
  includeTranscripts: options.includeTranscripts,
7059
7433
  readFile: storageIo.readFile
@@ -7071,7 +7445,7 @@ async function runOfflineSyncOnce(options) {
7071
7445
  });
7072
7446
  const applyCurrentSnapshot = directHydratedPaths.size > 0 ? await buildOfflineSyncSnapshot({
7073
7447
  root: options.memoryDir,
7074
- sourceId: localOfflineSourceId(options.memoryDir),
7448
+ sourceId: localSourceId,
7075
7449
  includeContent: false,
7076
7450
  includeTranscripts: options.includeTranscripts,
7077
7451
  readFile: storageIo.readFile
@@ -10238,6 +10612,7 @@ export {
10238
10612
  buildQueryRecallRequest,
10239
10613
  chunkOfflineFileContentBatches,
10240
10614
  extractXrayRawArgs,
10615
+ formatOfflineLargeFilePushFailureMessage,
10241
10616
  getBenchUsageText,
10242
10617
  hasFlag,
10243
10618
  main,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/cli",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
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.1",
30
- "@remnic/server": "^1.0.5",
31
- "@remnic/core": "^1.1.21"
29
+ "@remnic/plugin-pi": "^1.0.3",
30
+ "@remnic/core": "^1.1.23",
31
+ "@remnic/server": "^1.0.5"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@remnic/bench": "^1.0.0",
@@ -77,8 +77,8 @@
77
77
  "@remnic/export-weclone": "1.0.1",
78
78
  "@remnic/import-weclone": "1.0.1",
79
79
  "@remnic/import-chatgpt": "0.1.0",
80
- "@remnic/import-claude": "0.1.0",
81
80
  "@remnic/import-gemini": "0.1.0",
81
+ "@remnic/import-claude": "0.1.0",
82
82
  "@remnic/import-lossless-claw": "0.1.1",
83
83
  "@remnic/import-mem0": "0.1.0",
84
84
  "@remnic/import-supermemory": "0.1.2"