@remnic/cli 1.0.24 → 1.0.25

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 +153 -21
  2. package/package.json +5 -5
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ import path11 from "path";
5
5
  import { createDecipheriv, createHash } from "crypto";
6
6
  import * as childProcess2 from "child_process";
7
7
  import { fileURLToPath as fileURLToPath4 } from "url";
8
+ import { gzipSync } from "zlib";
8
9
  import {
9
10
  parseConfig,
10
11
  isOpenaiApiKeyDisabled,
@@ -6648,6 +6649,7 @@ function offlineEndpoint(remoteUrl, pathname, params = {}) {
6648
6649
  return url.toString();
6649
6650
  }
6650
6651
  var OFFLINE_SYNC_REQUEST_TIMEOUT_DEFAULT_MS = 15 * 6e4;
6652
+ var OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES = 16 * 1024 * 1024;
6651
6653
  function parseOfflineSyncRequestTimeoutMs(raw, fallback = OFFLINE_SYNC_REQUEST_TIMEOUT_DEFAULT_MS) {
6652
6654
  if (raw === void 0 || raw.trim().length === 0) return fallback;
6653
6655
  const parsed = Number(raw);
@@ -6746,29 +6748,130 @@ async function fetchOfflineJson(url, token, init = {}) {
6746
6748
  }
6747
6749
  );
6748
6750
  }
6751
+ async function parseOfflineSnapshotStreamResponse(response) {
6752
+ if (!response.body) {
6753
+ throw new Error("offline sync snapshot stream response omitted body");
6754
+ }
6755
+ const reader = response.body.getReader();
6756
+ const decoder = new TextDecoder();
6757
+ let buffered = "";
6758
+ let header = null;
6759
+ const files = [];
6760
+ const handleLine = (line) => {
6761
+ if (line.trim().length === 0) return;
6762
+ const parsed = JSON.parse(line);
6763
+ if (parsed.type === "snapshot") {
6764
+ if (header) throw new Error("offline sync snapshot stream repeated header");
6765
+ header = {
6766
+ ...typeof parsed.namespace === "string" && parsed.namespace.length > 0 ? { namespace: parsed.namespace } : {},
6767
+ format: parsed.format,
6768
+ schemaVersion: parsed.schemaVersion,
6769
+ createdAt: parsed.createdAt,
6770
+ sourceId: parsed.sourceId,
6771
+ includeTranscripts: parsed.includeTranscripts
6772
+ };
6773
+ return;
6774
+ }
6775
+ if (parsed.type === "file") {
6776
+ if (!header) throw new Error("offline sync snapshot stream file arrived before header");
6777
+ files.push(parsed.file);
6778
+ return;
6779
+ }
6780
+ throw new Error("offline sync snapshot stream contained unknown event");
6781
+ };
6782
+ for (; ; ) {
6783
+ const { value, done } = await reader.read();
6784
+ if (done) break;
6785
+ buffered += decoder.decode(value, { stream: true });
6786
+ for (; ; ) {
6787
+ const newline = buffered.indexOf("\n");
6788
+ if (newline < 0) break;
6789
+ const line = buffered.slice(0, newline);
6790
+ buffered = buffered.slice(newline + 1);
6791
+ handleLine(line);
6792
+ }
6793
+ }
6794
+ buffered += decoder.decode();
6795
+ handleLine(buffered);
6796
+ const finalHeader = header;
6797
+ if (!finalHeader) throw new Error("offline sync snapshot stream omitted header");
6798
+ const snapshot = normalizeOfflineSyncSnapshot({
6799
+ format: finalHeader.format,
6800
+ schemaVersion: finalHeader.schemaVersion,
6801
+ createdAt: finalHeader.createdAt,
6802
+ sourceId: finalHeader.sourceId,
6803
+ includeTranscripts: finalHeader.includeTranscripts,
6804
+ files
6805
+ });
6806
+ return {
6807
+ ...finalHeader.namespace ? { namespace: finalHeader.namespace } : {},
6808
+ ...snapshot
6809
+ };
6810
+ }
6811
+ async function fetchOfflineSnapshotStream(args) {
6812
+ const url = offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/snapshot-stream", {
6813
+ namespace: args.namespace,
6814
+ include_transcripts: args.includeTranscripts ? "true" : "false",
6815
+ content: "false"
6816
+ });
6817
+ return fetchOfflineWithResponse(
6818
+ url,
6819
+ args.token,
6820
+ {},
6821
+ {},
6822
+ async (response) => {
6823
+ if (!response.ok) {
6824
+ await throwOfflineResponseError(response, url, {}, "offline sync snapshot-stream request");
6825
+ }
6826
+ return parseOfflineSnapshotStreamResponse(response);
6827
+ }
6828
+ );
6829
+ }
6749
6830
  async function fetchOfflineSnapshot(args) {
6831
+ let tryStreamSnapshot = false;
6750
6832
  if (args.includeContent === false && args.baseFiles && args.baseFiles.length > 0) {
6751
- const postBody = offlineSnapshotBasePostBody({
6752
- namespace: args.namespace,
6753
- includeTranscripts: args.includeTranscripts,
6754
- baseFiles: args.baseFiles,
6755
- baseCapturedAt: args.baseCapturedAt
6756
- });
6757
- if (offlineSnapshotBasePostBodyFits(postBody)) {
6758
- try {
6759
- return await fetchOfflineJson(
6760
- offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/snapshot"),
6761
- args.token,
6762
- {
6763
- method: "POST",
6764
- body: postBody
6765
- }
6766
- );
6767
- } catch (error) {
6768
- if (!isOfflineSnapshotPostFallbackError(error)) throw error;
6833
+ if (args.baseFiles.length > OFFLINE_SYNC_SNAPSHOT_BASE_POST_MAX_FILES) {
6834
+ tryStreamSnapshot = true;
6835
+ } else {
6836
+ const postBody = offlineSnapshotBasePostBody({
6837
+ namespace: args.namespace,
6838
+ includeTranscripts: args.includeTranscripts,
6839
+ baseFiles: args.baseFiles,
6840
+ baseCapturedAt: args.baseCapturedAt
6841
+ });
6842
+ const postRequest = offlineSnapshotBasePostRequest(postBody);
6843
+ if (postRequest) {
6844
+ const postRequestUsesGzip = new Headers(postRequest.headers).get("content-encoding")?.toLowerCase() === "gzip";
6845
+ try {
6846
+ return await fetchOfflineJson(
6847
+ offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/snapshot"),
6848
+ args.token,
6849
+ {
6850
+ method: "POST",
6851
+ ...postRequest
6852
+ }
6853
+ );
6854
+ } catch (error) {
6855
+ if (!isOfflineSnapshotPostFallbackError(error, { compressed: postRequestUsesGzip })) throw error;
6856
+ tryStreamSnapshot = true;
6857
+ }
6858
+ } else {
6859
+ tryStreamSnapshot = true;
6769
6860
  }
6770
6861
  }
6771
6862
  }
6863
+ if (tryStreamSnapshot) {
6864
+ try {
6865
+ return await fetchOfflineSnapshotStream({
6866
+ remoteUrl: args.remoteUrl,
6867
+ token: args.token,
6868
+ namespace: args.namespace,
6869
+ includeTranscripts: args.includeTranscripts
6870
+ });
6871
+ } catch (error) {
6872
+ if (!isOfflineSnapshotStreamFallbackError(error)) throw error;
6873
+ }
6874
+ }
6772
6875
  return fetchOfflineJson(
6773
6876
  offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/snapshot", {
6774
6877
  namespace: args.namespace,
@@ -6788,11 +6891,36 @@ function offlineSnapshotBasePostBody(args) {
6788
6891
  });
6789
6892
  }
6790
6893
  function offlineSnapshotBasePostBodyFits(body) {
6791
- return Buffer.byteLength(body, "utf-8") <= OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES;
6894
+ const bytes = Buffer.byteLength(body, "utf-8");
6895
+ return bytes <= OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES && bytes <= OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES;
6896
+ }
6897
+ var OFFLINE_SYNC_SNAPSHOT_BASE_POST_MAX_FILES = 5e4;
6898
+ function offlineSnapshotBasePostRequest(body) {
6899
+ const bytes = Buffer.byteLength(body, "utf-8");
6900
+ if (bytes > OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES) return null;
6901
+ if (bytes <= OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES) {
6902
+ return { body };
6903
+ }
6904
+ const compressed = gzipSync(body);
6905
+ if (compressed.byteLength > OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES) {
6906
+ return null;
6907
+ }
6908
+ return {
6909
+ body: compressed,
6910
+ headers: {
6911
+ "content-encoding": "gzip"
6912
+ }
6913
+ };
6914
+ }
6915
+ function isOfflineSnapshotPostFallbackError(error, options = {}) {
6916
+ const message = error instanceof Error ? error.message : String(error);
6917
+ if (/offline-sync\/snapshot\b.* returned (404|405|413)\b/.test(message)) return true;
6918
+ if (!options.compressed) return false;
6919
+ return /offline-sync\/snapshot\b.* returned (400|415)\b/.test(message) && /\b(unsupported_content_encoding|invalid_gzip_body|invalid_json)\b/.test(message);
6792
6920
  }
6793
- function isOfflineSnapshotPostFallbackError(error) {
6921
+ function isOfflineSnapshotStreamFallbackError(error) {
6794
6922
  const message = error instanceof Error ? error.message : String(error);
6795
- return /offline-sync\/snapshot\b.* returned (404|405|413)\b/.test(message);
6923
+ return /offline-sync\/snapshot-stream\b.* returned (404|405)\b/.test(message);
6796
6924
  }
6797
6925
  async function fetchOfflineFiles(args) {
6798
6926
  return fetchOfflineJson(
@@ -11273,6 +11401,8 @@ export {
11273
11401
  OFFLINE_SYNC_DIRECT_PUSH_MIN_BYTES,
11274
11402
  OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES,
11275
11403
  OFFLINE_SYNC_REQUEST_TIMEOUT_DEFAULT_MS,
11404
+ OFFLINE_SYNC_SNAPSHOT_BASE_POST_MAX_FILES,
11405
+ OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES,
11276
11406
  TAXONOMY_RESOLVE_BOOLEAN_FLAGS,
11277
11407
  TAXONOMY_RESOLVE_VALUE_FLAGS,
11278
11408
  __benchDatasetTestHooks,
@@ -11284,6 +11414,7 @@ export {
11284
11414
  chunkOfflineFileContentBatches,
11285
11415
  directHydrateLargeOfflineFiles,
11286
11416
  extractXrayRawArgs,
11417
+ fetchOfflineSnapshot,
11287
11418
  formatOfflineLargeFilePushFailureMessage,
11288
11419
  formatOfflineRequestForError,
11289
11420
  getBenchUsageText,
@@ -11293,6 +11424,7 @@ export {
11293
11424
  offlinePartialHydrationForPaths,
11294
11425
  offlineSnapshotBasePostBody,
11295
11426
  offlineSnapshotBasePostBodyFits,
11427
+ offlineSnapshotBasePostRequest,
11296
11428
  offlineSnapshotContentFilesForApply,
11297
11429
  parseBenchArgs,
11298
11430
  parseCapsuleForkArgs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/cli",
3
- "version": "1.0.24",
3
+ "version": "1.0.25",
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.9",
29
30
  "@remnic/server": "^1.0.5",
30
- "@remnic/plugin-pi": "^1.0.10",
31
- "@remnic/core": "^1.1.30"
31
+ "@remnic/core": "^1.1.31"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@remnic/bench": "^1.0.0",
@@ -80,8 +80,8 @@
80
80
  "@remnic/import-claude": "0.1.0",
81
81
  "@remnic/import-gemini": "0.1.0",
82
82
  "@remnic/import-lossless-claw": "0.1.1",
83
- "@remnic/import-mem0": "0.1.0",
84
- "@remnic/import-supermemory": "0.1.2"
83
+ "@remnic/import-supermemory": "0.1.2",
84
+ "@remnic/import-mem0": "0.1.0"
85
85
  },
86
86
  "license": "MIT",
87
87
  "repository": {