@remnic/cli 1.0.24 → 9.3.515

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 +406 -133
  2. package/package.json +22 -22
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,
@@ -850,7 +851,12 @@ function validateBenchFlags(action, args) {
850
851
  if (!arg.startsWith("-")) {
851
852
  continue;
852
853
  }
853
- if (allowed.legacyEqualsPrefixes?.some((prefix) => arg.startsWith(prefix))) {
854
+ const legacyEqualsPrefix = allowed.legacyEqualsPrefixes?.find((prefix) => arg.startsWith(prefix));
855
+ if (legacyEqualsPrefix) {
856
+ const value = arg.slice(legacyEqualsPrefix.length);
857
+ if (value.trim().length === 0) {
858
+ throw new Error(`ERROR: ${legacyEqualsPrefix.slice(0, -1)} requires a value.`);
859
+ }
854
860
  continue;
855
861
  }
856
862
  if (isBenchValueFlag(arg)) {
@@ -1973,6 +1979,66 @@ function isCandidateReady(candidate, existsSync3) {
1973
1979
  function resolveServerBin(options = {}) {
1974
1980
  return resolveServerBinDetails(options).path;
1975
1981
  }
1982
+ function readVerifiedDaemonPid(options) {
1983
+ const readFileSync3 = options.readFileSync ?? fs4.readFileSync;
1984
+ const unlinkSync = options.unlinkSync ?? fs4.unlinkSync;
1985
+ const processKill = options.processKill ?? process.kill;
1986
+ const execFileSync3 = options.execFileSync ?? ((command, args, execOptions) => childProcess.execFileSync(command, args, execOptions));
1987
+ for (const file of options.pidFiles) {
1988
+ let pid;
1989
+ try {
1990
+ pid = parseDaemonPid(readFileSync3(file, "utf8"));
1991
+ } catch {
1992
+ continue;
1993
+ }
1994
+ if (pid === void 0) {
1995
+ removePidFileBestEffort(file, unlinkSync);
1996
+ continue;
1997
+ }
1998
+ try {
1999
+ processKill(pid, 0);
2000
+ } catch {
2001
+ removePidFileBestEffort(file, unlinkSync);
2002
+ continue;
2003
+ }
2004
+ const command = readProcessCommand(pid, execFileSync3);
2005
+ if (command === void 0) {
2006
+ return pid;
2007
+ }
2008
+ if (doesProcessCommandLookLikeRemnicDaemon(command, options.expectedServerBin)) {
2009
+ return pid;
2010
+ }
2011
+ removePidFileBestEffort(file, unlinkSync);
2012
+ }
2013
+ return void 0;
2014
+ }
2015
+ function doesProcessCommandLookLikeRemnicDaemon(command, expectedServerBin) {
2016
+ const normalizedCommand = command.trim();
2017
+ const normalizedExpected = path8.resolve(expandTilde(expectedServerBin));
2018
+ return normalizedCommand.includes(normalizedExpected) || /(?:^|\s|[/\\])(?:remnic-server|engram-server)(?:\.js)?(?:\s|$)/.test(normalizedCommand) || /@remnic[/\\]server[/\\]/.test(normalizedCommand) || /packages[/\\]remnic-server[/\\](?:bin[/\\]remnic-server\.js|dist[/\\]index\.js|src[/\\]index\.ts)/.test(normalizedCommand);
2019
+ }
2020
+ function parseDaemonPid(raw) {
2021
+ const trimmed = raw.trim();
2022
+ if (!/^\d+$/.test(trimmed)) return void 0;
2023
+ const pid = Number(trimmed);
2024
+ return Number.isSafeInteger(pid) && pid > 0 ? pid : void 0;
2025
+ }
2026
+ function readProcessCommand(pid, execFileSync3) {
2027
+ try {
2028
+ return execFileSync3("ps", ["-p", String(pid), "-o", "command="], {
2029
+ encoding: "utf8",
2030
+ stdio: "pipe"
2031
+ });
2032
+ } catch {
2033
+ return void 0;
2034
+ }
2035
+ }
2036
+ function removePidFileBestEffort(file, unlinkSync) {
2037
+ try {
2038
+ unlinkSync(file);
2039
+ } catch {
2040
+ }
2041
+ }
1976
2042
  function inspectLaunchdPlist(plistPath, options = {}) {
1977
2043
  const existsSync3 = options.existsSync ?? fs4.existsSync;
1978
2044
  const readFileSync3 = options.readFileSync ?? fs4.readFileSync;
@@ -2431,7 +2497,8 @@ Usage:
2431
2497
 
2432
2498
  Required:
2433
2499
  --adapter <name> One of: ${SUPPORTED_IMPORTERS.join(" | ")}
2434
- --file <path> Path to the source export (JSON or ZIP). May be
2500
+ --file <path> Path to a text/JSON source export. ZIP archives
2501
+ are not accepted by this single-file path yet. May be
2435
2502
  omitted for API-only adapters (mem0).
2436
2503
 
2437
2504
  Options:
@@ -2522,6 +2589,11 @@ function rejectLeftoverImportArgs(args, command) {
2522
2589
  }
2523
2590
  }
2524
2591
  async function runImportCommand(args, io) {
2592
+ if (args.file && isZipFilePath(args.file)) {
2593
+ throw new Error(
2594
+ `ZIP imports are not supported by --file yet: '${args.file}'. Extract the archive first or use --all-from-bundle for supported bundle layouts.`
2595
+ );
2596
+ }
2525
2597
  const adapter = await io.loadAdapter(args.adapter);
2526
2598
  let input;
2527
2599
  if (args.file) {
@@ -2574,6 +2646,16 @@ async function runImportCommand(args, io) {
2574
2646
  }
2575
2647
  return result;
2576
2648
  }
2649
+ function isZipFilePath(filePath) {
2650
+ return pathExtension(filePath) === ".zip";
2651
+ }
2652
+ function pathExtension(filePath) {
2653
+ const normalized = filePath.trim().toLowerCase();
2654
+ const lastSlash = Math.max(normalized.lastIndexOf("/"), normalized.lastIndexOf("\\"));
2655
+ const base = normalized.slice(lastSlash + 1);
2656
+ const dot = base.lastIndexOf(".");
2657
+ return dot >= 0 ? base.slice(dot) : "";
2658
+ }
2577
2659
  function parseImportBundleArgs(rest) {
2578
2660
  const args = [...rest];
2579
2661
  if (!args.includes("--all-from-bundle")) return void 0;
@@ -3836,7 +3918,8 @@ var __benchDatasetTestHooks = {
3836
3918
  seed,
3837
3919
  benchmarkOptions
3838
3920
  );
3839
- }
3921
+ },
3922
+ printBenchStatusLineForTest: printBenchStatusLine
3840
3923
  };
3841
3924
  function printBenchPackageSummary(result, outputPath, outputLabel = "Results saved") {
3842
3925
  console.log(`Benchmark: ${result.meta.benchmark}`);
@@ -3851,6 +3934,13 @@ function printBenchPackageSummary(result, outputPath, outputLabel = "Results sav
3851
3934
  }
3852
3935
  console.log(`${outputLabel}: ${outputPath}`);
3853
3936
  }
3937
+ function printBenchStatusLine(jsonMode, message) {
3938
+ if (jsonMode) {
3939
+ console.error(message);
3940
+ } else {
3941
+ console.log(message);
3942
+ }
3943
+ }
3854
3944
  function printStoredBenchResultSummary(result, summary) {
3855
3945
  printBenchPackageSummary(result, summary.path, "Stored result");
3856
3946
  console.log(`Run id: ${summary.id}`);
@@ -4671,7 +4761,8 @@ async function runBenchViaPackage(parsed, benchmarkId, runtimeProfile, benchStat
4671
4761
  if (completed % 50 === 0 || completed === total) {
4672
4762
  const elapsed = Math.round((Date.now() - benchStartTime) / 1e3);
4673
4763
  const remaining = total && elapsed > 0 ? Math.round((total - completed) / (completed / elapsed)) : "?";
4674
- console.log(
4764
+ printBenchStatusLine(
4765
+ parsed.json,
4675
4766
  ` [${benchmarkId}] ${completed}/${total ?? "?"} tasks (${elapsed}s elapsed, ~${remaining}s remaining)`
4676
4767
  );
4677
4768
  }
@@ -6648,6 +6739,7 @@ function offlineEndpoint(remoteUrl, pathname, params = {}) {
6648
6739
  return url.toString();
6649
6740
  }
6650
6741
  var OFFLINE_SYNC_REQUEST_TIMEOUT_DEFAULT_MS = 15 * 6e4;
6742
+ var OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES = 16 * 1024 * 1024;
6651
6743
  function parseOfflineSyncRequestTimeoutMs(raw, fallback = OFFLINE_SYNC_REQUEST_TIMEOUT_DEFAULT_MS) {
6652
6744
  if (raw === void 0 || raw.trim().length === 0) return fallback;
6653
6745
  const parsed = Number(raw);
@@ -6746,29 +6838,130 @@ async function fetchOfflineJson(url, token, init = {}) {
6746
6838
  }
6747
6839
  );
6748
6840
  }
6841
+ async function parseOfflineSnapshotStreamResponse(response) {
6842
+ if (!response.body) {
6843
+ throw new Error("offline sync snapshot stream response omitted body");
6844
+ }
6845
+ const reader = response.body.getReader();
6846
+ const decoder = new TextDecoder();
6847
+ let buffered = "";
6848
+ let header = null;
6849
+ const files = [];
6850
+ const handleLine = (line) => {
6851
+ if (line.trim().length === 0) return;
6852
+ const parsed = JSON.parse(line);
6853
+ if (parsed.type === "snapshot") {
6854
+ if (header) throw new Error("offline sync snapshot stream repeated header");
6855
+ header = {
6856
+ ...typeof parsed.namespace === "string" && parsed.namespace.length > 0 ? { namespace: parsed.namespace } : {},
6857
+ format: parsed.format,
6858
+ schemaVersion: parsed.schemaVersion,
6859
+ createdAt: parsed.createdAt,
6860
+ sourceId: parsed.sourceId,
6861
+ includeTranscripts: parsed.includeTranscripts
6862
+ };
6863
+ return;
6864
+ }
6865
+ if (parsed.type === "file") {
6866
+ if (!header) throw new Error("offline sync snapshot stream file arrived before header");
6867
+ files.push(parsed.file);
6868
+ return;
6869
+ }
6870
+ throw new Error("offline sync snapshot stream contained unknown event");
6871
+ };
6872
+ for (; ; ) {
6873
+ const { value, done } = await reader.read();
6874
+ if (done) break;
6875
+ buffered += decoder.decode(value, { stream: true });
6876
+ for (; ; ) {
6877
+ const newline = buffered.indexOf("\n");
6878
+ if (newline < 0) break;
6879
+ const line = buffered.slice(0, newline);
6880
+ buffered = buffered.slice(newline + 1);
6881
+ handleLine(line);
6882
+ }
6883
+ }
6884
+ buffered += decoder.decode();
6885
+ handleLine(buffered);
6886
+ const finalHeader = header;
6887
+ if (!finalHeader) throw new Error("offline sync snapshot stream omitted header");
6888
+ const snapshot = normalizeOfflineSyncSnapshot({
6889
+ format: finalHeader.format,
6890
+ schemaVersion: finalHeader.schemaVersion,
6891
+ createdAt: finalHeader.createdAt,
6892
+ sourceId: finalHeader.sourceId,
6893
+ includeTranscripts: finalHeader.includeTranscripts,
6894
+ files
6895
+ });
6896
+ return {
6897
+ ...finalHeader.namespace ? { namespace: finalHeader.namespace } : {},
6898
+ ...snapshot
6899
+ };
6900
+ }
6901
+ async function fetchOfflineSnapshotStream(args) {
6902
+ const url = offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/snapshot-stream", {
6903
+ namespace: args.namespace,
6904
+ include_transcripts: args.includeTranscripts ? "true" : "false",
6905
+ content: "false"
6906
+ });
6907
+ return fetchOfflineWithResponse(
6908
+ url,
6909
+ args.token,
6910
+ {},
6911
+ {},
6912
+ async (response) => {
6913
+ if (!response.ok) {
6914
+ await throwOfflineResponseError(response, url, {}, "offline sync snapshot-stream request");
6915
+ }
6916
+ return parseOfflineSnapshotStreamResponse(response);
6917
+ }
6918
+ );
6919
+ }
6749
6920
  async function fetchOfflineSnapshot(args) {
6921
+ let tryStreamSnapshot = false;
6750
6922
  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;
6923
+ if (args.baseFiles.length > OFFLINE_SYNC_SNAPSHOT_BASE_POST_MAX_FILES) {
6924
+ tryStreamSnapshot = true;
6925
+ } else {
6926
+ const postBody = offlineSnapshotBasePostBody({
6927
+ namespace: args.namespace,
6928
+ includeTranscripts: args.includeTranscripts,
6929
+ baseFiles: args.baseFiles,
6930
+ baseCapturedAt: args.baseCapturedAt
6931
+ });
6932
+ const postRequest = offlineSnapshotBasePostRequest(postBody);
6933
+ if (postRequest) {
6934
+ const postRequestUsesGzip = new Headers(postRequest.headers).get("content-encoding")?.toLowerCase() === "gzip";
6935
+ try {
6936
+ return await fetchOfflineJson(
6937
+ offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/snapshot"),
6938
+ args.token,
6939
+ {
6940
+ method: "POST",
6941
+ ...postRequest
6942
+ }
6943
+ );
6944
+ } catch (error) {
6945
+ if (!isOfflineSnapshotPostFallbackError(error, { compressed: postRequestUsesGzip })) throw error;
6946
+ tryStreamSnapshot = true;
6947
+ }
6948
+ } else {
6949
+ tryStreamSnapshot = true;
6769
6950
  }
6770
6951
  }
6771
6952
  }
6953
+ if (tryStreamSnapshot) {
6954
+ try {
6955
+ return await fetchOfflineSnapshotStream({
6956
+ remoteUrl: args.remoteUrl,
6957
+ token: args.token,
6958
+ namespace: args.namespace,
6959
+ includeTranscripts: args.includeTranscripts
6960
+ });
6961
+ } catch (error) {
6962
+ if (!isOfflineSnapshotStreamFallbackError(error)) throw error;
6963
+ }
6964
+ }
6772
6965
  return fetchOfflineJson(
6773
6966
  offlineEndpoint(args.remoteUrl, "/remnic/v1/offline-sync/snapshot", {
6774
6967
  namespace: args.namespace,
@@ -6788,11 +6981,36 @@ function offlineSnapshotBasePostBody(args) {
6788
6981
  });
6789
6982
  }
6790
6983
  function offlineSnapshotBasePostBodyFits(body) {
6791
- return Buffer.byteLength(body, "utf-8") <= OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES;
6984
+ const bytes = Buffer.byteLength(body, "utf-8");
6985
+ return bytes <= OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES && bytes <= OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES;
6986
+ }
6987
+ var OFFLINE_SYNC_SNAPSHOT_BASE_POST_MAX_FILES = 5e4;
6988
+ function offlineSnapshotBasePostRequest(body) {
6989
+ const bytes = Buffer.byteLength(body, "utf-8");
6990
+ if (bytes > OFFLINE_SYNC_SNAPSHOT_BASE_MAX_BODY_BYTES) return null;
6991
+ if (bytes <= OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES) {
6992
+ return { body };
6993
+ }
6994
+ const compressed = gzipSync(body);
6995
+ if (compressed.byteLength > OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES) {
6996
+ return null;
6997
+ }
6998
+ return {
6999
+ body: compressed,
7000
+ headers: {
7001
+ "content-encoding": "gzip"
7002
+ }
7003
+ };
7004
+ }
7005
+ function isOfflineSnapshotPostFallbackError(error, options = {}) {
7006
+ const message = error instanceof Error ? error.message : String(error);
7007
+ if (/offline-sync\/snapshot\b.* returned (404|405|413)\b/.test(message)) return true;
7008
+ if (!options.compressed) return false;
7009
+ return /offline-sync\/snapshot\b.* returned (400|415)\b/.test(message) && /\b(unsupported_content_encoding|invalid_gzip_body|invalid_json)\b/.test(message);
6792
7010
  }
6793
- function isOfflineSnapshotPostFallbackError(error) {
7011
+ function isOfflineSnapshotStreamFallbackError(error) {
6794
7012
  const message = error instanceof Error ? error.message : String(error);
6795
- return /offline-sync\/snapshot\b.* returned (404|405|413)\b/.test(message);
7013
+ return /offline-sync\/snapshot-stream\b.* returned (404|405)\b/.test(message);
6796
7014
  }
6797
7015
  async function fetchOfflineFiles(args) {
6798
7016
  return fetchOfflineJson(
@@ -8681,109 +8899,113 @@ async function cmdConnectors(action, rest, json) {
8681
8899
  const remnicCfg = raw.remnic ?? raw.engram ?? raw;
8682
8900
  const config = parseConfig(remnicCfg);
8683
8901
  const orchestrator = new Orchestrator(config);
8684
- await orchestrator.initialize();
8685
- await orchestrator.deferredReady;
8686
- const cfg = config.connectors;
8687
- const sharedIngestFn = async (docs) => {
8688
- const fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
8689
- const turns = docs.map((doc) => ({
8690
- role: "assistant",
8691
- content: doc.title ? `# ${doc.title}
8902
+ try {
8903
+ await orchestrator.initialize();
8904
+ await orchestrator.deferredReady;
8905
+ const cfg = config.connectors;
8906
+ const sharedIngestFn = async (docs) => {
8907
+ const fetchedAt = (/* @__PURE__ */ new Date()).toISOString();
8908
+ const turns = docs.map((doc) => ({
8909
+ role: "assistant",
8910
+ content: doc.title ? `# ${doc.title}
8692
8911
 
8693
8912
  ${doc.content}` : doc.content,
8694
- timestamp: fetchedAt
8695
- }));
8696
- await orchestrator.ingestBulkImportBatch(turns);
8697
- };
8698
- const makeWriteCursorFn = (id) => async (state) => {
8699
- await writeLiveConnectorState(config.memoryDir, id, {
8700
- id,
8701
- cursor: state.cursor,
8702
- lastSyncAt: (/* @__PURE__ */ new Date()).toISOString(),
8703
- lastSyncStatus: state.lastSyncStatus,
8704
- ...state.lastSyncError !== void 0 ? { lastSyncError: state.lastSyncError } : {},
8705
- totalDocsImported: state.totalDocsImported
8706
- });
8707
- };
8708
- let runResult;
8709
- if (connectorName === GDRIVE_ID) {
8710
- if (!cfg?.googleDrive?.enabled) {
8711
- process.stderr.write(
8712
- `connectors run: connector "${connectorName}" is disabled. Set connectors.googleDrive.enabled=true in config.
8913
+ timestamp: fetchedAt
8914
+ }));
8915
+ await orchestrator.ingestBulkImportBatch(turns);
8916
+ };
8917
+ const makeWriteCursorFn = (id) => async (state) => {
8918
+ await writeLiveConnectorState(config.memoryDir, id, {
8919
+ id,
8920
+ cursor: state.cursor,
8921
+ lastSyncAt: (/* @__PURE__ */ new Date()).toISOString(),
8922
+ lastSyncStatus: state.lastSyncStatus,
8923
+ ...state.lastSyncError !== void 0 ? { lastSyncError: state.lastSyncError } : {},
8924
+ totalDocsImported: state.totalDocsImported
8925
+ });
8926
+ };
8927
+ let runResult;
8928
+ if (connectorName === GDRIVE_ID) {
8929
+ if (!cfg?.googleDrive?.enabled) {
8930
+ process.stderr.write(
8931
+ `connectors run: connector "${connectorName}" is disabled. Set connectors.googleDrive.enabled=true in config.
8713
8932
  `
8714
- );
8715
- process.exitCode = 1;
8716
- return;
8717
- }
8718
- let validatedCfg;
8719
- try {
8720
- validatedCfg = validateGDriveCfg(cfg.googleDrive);
8721
- } catch (err) {
8722
- process.stderr.write(
8723
- `connectors run: invalid config for "${connectorName}": ${err instanceof Error ? err.message : String(err)}
8933
+ );
8934
+ process.exitCode = 1;
8935
+ return;
8936
+ }
8937
+ let validatedCfg;
8938
+ try {
8939
+ validatedCfg = validateGDriveCfg(cfg.googleDrive);
8940
+ } catch (err) {
8941
+ process.stderr.write(
8942
+ `connectors run: invalid config for "${connectorName}": ${err instanceof Error ? err.message : String(err)}
8724
8943
  `
8725
- );
8726
- process.exitCode = 1;
8727
- return;
8728
- }
8729
- const connector = makeGDriveConnector();
8730
- const state = await readLiveConnectorState(config.memoryDir, connectorName);
8731
- runResult = await pollOnce({
8732
- connectorId: connectorName,
8733
- priorState: state,
8734
- syncFn: (cursor) => connector.syncIncremental({
8735
- cursor,
8736
- config: validatedCfg
8737
- }),
8738
- ingestFn: sharedIngestFn,
8739
- writeCursorFn: makeWriteCursorFn(connectorName)
8740
- });
8741
- } else if (connectorName === NOTION_ID) {
8742
- if (!cfg?.notion?.enabled) {
8944
+ );
8945
+ process.exitCode = 1;
8946
+ return;
8947
+ }
8948
+ const connector = makeGDriveConnector();
8949
+ const state = await readLiveConnectorState(config.memoryDir, connectorName);
8950
+ runResult = await pollOnce({
8951
+ connectorId: connectorName,
8952
+ priorState: state,
8953
+ syncFn: (cursor) => connector.syncIncremental({
8954
+ cursor,
8955
+ config: validatedCfg
8956
+ }),
8957
+ ingestFn: sharedIngestFn,
8958
+ writeCursorFn: makeWriteCursorFn(connectorName)
8959
+ });
8960
+ } else if (connectorName === NOTION_ID) {
8961
+ if (!cfg?.notion?.enabled) {
8962
+ process.stderr.write(
8963
+ `connectors run: connector "${connectorName}" is disabled. Set connectors.notion.enabled=true in config.
8964
+ `
8965
+ );
8966
+ process.exitCode = 1;
8967
+ return;
8968
+ }
8969
+ let validatedCfg;
8970
+ try {
8971
+ validatedCfg = validateNotionCfg(cfg.notion);
8972
+ } catch (err) {
8973
+ process.stderr.write(
8974
+ `connectors run: invalid config for "${connectorName}": ${err instanceof Error ? err.message : String(err)}
8975
+ `
8976
+ );
8977
+ process.exitCode = 1;
8978
+ return;
8979
+ }
8980
+ const connector = makeNotionConnector();
8981
+ const state = await readLiveConnectorState(config.memoryDir, connectorName);
8982
+ runResult = await pollOnce({
8983
+ connectorId: connectorName,
8984
+ priorState: state,
8985
+ syncFn: (cursor) => connector.syncIncremental({
8986
+ cursor,
8987
+ config: validatedCfg
8988
+ }),
8989
+ ingestFn: sharedIngestFn,
8990
+ writeCursorFn: makeWriteCursorFn(connectorName)
8991
+ });
8992
+ } else {
8743
8993
  process.stderr.write(
8744
- `connectors run: connector "${connectorName}" is disabled. Set connectors.notion.enabled=true in config.
8994
+ `connectors run: unknown connector "${connectorName}". Known connectors: ${GDRIVE_ID}, ${NOTION_ID}.
8745
8995
  `
8746
8996
  );
8747
8997
  process.exitCode = 1;
8748
8998
  return;
8749
8999
  }
8750
- let validatedCfg;
8751
- try {
8752
- validatedCfg = validateNotionCfg(cfg.notion);
8753
- } catch (err) {
8754
- process.stderr.write(
8755
- `connectors run: invalid config for "${connectorName}": ${err instanceof Error ? err.message : String(err)}
8756
- `
8757
- );
9000
+ const output = renderRunResult(connectorName, runResult, format);
9001
+ if (runResult.error !== void 0 || runResult.stateWriteError !== void 0) {
9002
+ process.stderr.write(output + "\n");
8758
9003
  process.exitCode = 1;
8759
- return;
9004
+ } else {
9005
+ console.log(output);
8760
9006
  }
8761
- const connector = makeNotionConnector();
8762
- const state = await readLiveConnectorState(config.memoryDir, connectorName);
8763
- runResult = await pollOnce({
8764
- connectorId: connectorName,
8765
- priorState: state,
8766
- syncFn: (cursor) => connector.syncIncremental({
8767
- cursor,
8768
- config: validatedCfg
8769
- }),
8770
- ingestFn: sharedIngestFn,
8771
- writeCursorFn: makeWriteCursorFn(connectorName)
8772
- });
8773
- } else {
8774
- process.stderr.write(
8775
- `connectors run: unknown connector "${connectorName}". Known connectors: ${GDRIVE_ID}, ${NOTION_ID}.
8776
- `
8777
- );
8778
- process.exitCode = 1;
8779
- return;
8780
- }
8781
- const output = renderRunResult(connectorName, runResult, format);
8782
- if (runResult.error !== void 0 || runResult.stateWriteError !== void 0) {
8783
- process.stderr.write(output + "\n");
8784
- process.exitCode = 1;
8785
- } else {
8786
- console.log(output);
9007
+ } finally {
9008
+ await orchestrator.destroy();
8787
9009
  }
8788
9010
  } else {
8789
9011
  console.log("Usage: remnic connectors <list|install|remove|doctor|marketplace|status|run> [id]");
@@ -9091,7 +9313,7 @@ async function cmdLegacyBenchmark(action, rest, json) {
9091
9313
  } else if (action === "report") {
9092
9314
  const reportPath = benchConfig.reportPath;
9093
9315
  const suite = await runBenchSuite(service, { ...benchConfig, reportPath });
9094
- console.log(`Report saved to ${reportPath ?? "benchmarks/report.json"}`);
9316
+ printBenchStatusLine(json, `Report saved to ${reportPath ?? "benchmarks/report.json"}`);
9095
9317
  if (json) {
9096
9318
  console.log(JSON.stringify(suite.report, null, 2));
9097
9319
  }
@@ -9218,9 +9440,9 @@ async function cmdBench(rest) {
9218
9440
  }
9219
9441
  const completeCount = prevStatus.benchmarks.filter((b) => b.status === "complete").length;
9220
9442
  const failedCount = prevStatus.benchmarks.filter((b) => b.status === "failed").length;
9221
- console.log(`Resuming from: ${path11.basename(latestStatusPath)}`);
9222
- console.log(` Previous run: ${prevStatus.startedAt}`);
9223
- console.log(` Benchmarks: ${prevStatus.benchmarks.length} total, ${completeCount} complete, ${failedCount} failed`);
9443
+ printBenchStatusLine(parsed.json, `Resuming from: ${path11.basename(latestStatusPath)}`);
9444
+ printBenchStatusLine(parsed.json, ` Previous run: ${prevStatus.startedAt}`);
9445
+ printBenchStatusLine(parsed.json, ` Benchmarks: ${prevStatus.benchmarks.length} total, ${completeCount} complete, ${failedCount} failed`);
9224
9446
  const before = selectedBenchmarks.length;
9225
9447
  if (parsed.resume) {
9226
9448
  selectedWorkItems = filterBenchWorkItemsForPreviousStatus(
@@ -9229,7 +9451,7 @@ async function cmdBench(rest) {
9229
9451
  "resume"
9230
9452
  );
9231
9453
  selectedBenchmarks = [...new Set(selectedWorkItems.map((item) => item.benchmarkId))];
9232
- console.log(` Resuming: ${selectedBenchmarks.length} of ${before} benchmarks to re-run`);
9454
+ printBenchStatusLine(parsed.json, ` Resuming: ${selectedBenchmarks.length} of ${before} benchmarks to re-run`);
9233
9455
  } else {
9234
9456
  selectedWorkItems = filterBenchWorkItemsForPreviousStatus(
9235
9457
  selectedWorkItems,
@@ -9237,13 +9459,14 @@ async function cmdBench(rest) {
9237
9459
  "retry-failed"
9238
9460
  );
9239
9461
  selectedBenchmarks = [...new Set(selectedWorkItems.map((item) => item.benchmarkId))];
9240
- console.log(` Retrying: ${selectedBenchmarks.length} of ${before} selected benchmarks had failures`);
9462
+ printBenchStatusLine(parsed.json, ` Retrying: ${selectedBenchmarks.length} of ${before} selected benchmarks had failures`);
9241
9463
  }
9242
9464
  if (selectedWorkItems.length === 0) {
9243
9465
  if (parsed.retryFailed) {
9244
- console.log("Nothing to re-run \u2014 no selected benchmarks had failures.");
9466
+ printBenchStatusLine(parsed.json, "Nothing to re-run \u2014 no selected benchmarks had failures.");
9245
9467
  } else {
9246
- console.log(
9468
+ printBenchStatusLine(
9469
+ parsed.json,
9247
9470
  "Nothing to re-run \u2014 all selected benchmarks completed successfully in the previous run."
9248
9471
  );
9249
9472
  }
@@ -9289,6 +9512,7 @@ async function cmdBench(rest) {
9289
9512
  }
9290
9513
  } else {
9291
9514
  const fallbackResultPath = await runBenchViaFallback(parsed, benchmarkId, runtimeProfile);
9515
+ writtenPaths.push(fallbackResultPath);
9292
9516
  try {
9293
9517
  await updateBenchmarkCompleted(benchStatusPath, statusId, fallbackResultPath);
9294
9518
  } catch {
@@ -9404,13 +9628,10 @@ var [LAUNCHD_PLIST_PATH] = LAUNCHD_PLIST_PATHS;
9404
9628
  var SYSTEMD_UNIT_PATHS = systemdUnitPaths(resolveHomeDir());
9405
9629
  var [SYSTEMD_UNIT_PATH] = SYSTEMD_UNIT_PATHS;
9406
9630
  function readPid() {
9407
- for (const file of [PID_FILE, LEGACY_PID_FILE]) {
9408
- try {
9409
- return parseInt(fs7.readFileSync(file, "utf8").trim(), 10);
9410
- } catch {
9411
- }
9412
- }
9413
- return void 0;
9631
+ return readVerifiedDaemonPid({
9632
+ pidFiles: [PID_FILE, LEGACY_PID_FILE],
9633
+ expectedServerBin: resolveServerBin()
9634
+ });
9414
9635
  }
9415
9636
  function inferPort() {
9416
9637
  try {
@@ -9442,6 +9663,36 @@ function isStandaloneServiceInstalled() {
9442
9663
  if (isLinux()) return anyFileExists(SYSTEMD_UNIT_PATHS);
9443
9664
  return false;
9444
9665
  }
9666
+ function commandFailureDetail(error) {
9667
+ if (error && typeof error === "object") {
9668
+ const maybe = error;
9669
+ const stderr = maybe.stderr ? String(maybe.stderr).trim() : "";
9670
+ if (stderr) return stderr;
9671
+ const stdout = maybe.stdout ? String(maybe.stdout).trim() : "";
9672
+ if (stdout) return stdout;
9673
+ if (maybe.message) return maybe.message;
9674
+ }
9675
+ return String(error);
9676
+ }
9677
+ function failDaemonInstall(command, error) {
9678
+ console.error(`Error: daemon install failed while running ${command}.`);
9679
+ console.error(` ${commandFailureDetail(error)}`);
9680
+ process.exit(1);
9681
+ }
9682
+ function isLaunchdLabelLoaded(label) {
9683
+ return firstSuccessfulResult([label], (candidate) => {
9684
+ childProcess2.execSync(`launchctl list ${candidate} 2>/dev/null`, { stdio: "pipe" });
9685
+ return true;
9686
+ }) === true;
9687
+ }
9688
+ function isSystemdServiceActive() {
9689
+ return firstSuccessfulResult(SYSTEMD_SERVICE_CANDIDATES, (serviceName) => {
9690
+ const out = childProcess2.execSync(`systemctl --user is-active ${serviceName} 2>/dev/null`, {
9691
+ encoding: "utf8"
9692
+ }).trim();
9693
+ return out === "active" ? true : void 0;
9694
+ }) === true;
9695
+ }
9445
9696
  function selectLaunchdInspection(openclawPluginModeConfigured) {
9446
9697
  const canonical = inspectLaunchdPlist(LAUNCHD_PLIST_PATH);
9447
9698
  if (canonical.installed) return canonical;
@@ -9489,7 +9740,13 @@ function daemonInstall() {
9489
9740
  fs7.writeFileSync(LAUNCHD_PLIST_PATH, plist);
9490
9741
  try {
9491
9742
  launchdLoadPlist(LAUNCHD_PLIST_PATH);
9492
- } catch {
9743
+ } catch (err) {
9744
+ if (!isLaunchdLabelLoaded(LAUNCHD_LABEL)) {
9745
+ failDaemonInstall(`launchctl load -w ${LAUNCHD_PLIST_PATH}`, err);
9746
+ }
9747
+ }
9748
+ if (!isLaunchdLabelLoaded(LAUNCHD_LABEL)) {
9749
+ failDaemonInstall(`launchctl list ${LAUNCHD_LABEL}`, new Error("service was not loaded after install"));
9493
9750
  }
9494
9751
  console.log(`Installed launchd service: ${LAUNCHD_PLIST_PATH}`);
9495
9752
  console.log(` Label: ${LAUNCHD_LABEL}`);
@@ -9503,9 +9760,21 @@ function daemonInstall() {
9503
9760
  fs7.writeFileSync(SYSTEMD_UNIT_PATH, unit);
9504
9761
  try {
9505
9762
  childProcess2.execSync("systemctl --user daemon-reload", { stdio: "pipe" });
9763
+ } catch (err) {
9764
+ failDaemonInstall("systemctl --user daemon-reload", err);
9765
+ }
9766
+ try {
9506
9767
  childProcess2.execSync(`systemctl --user enable ${SYSTEMD_SERVICE}`, { stdio: "pipe" });
9768
+ } catch (err) {
9769
+ failDaemonInstall(`systemctl --user enable ${SYSTEMD_SERVICE}`, err);
9770
+ }
9771
+ try {
9507
9772
  childProcess2.execSync(`systemctl --user start ${SYSTEMD_SERVICE}`, { stdio: "pipe" });
9508
- } catch {
9773
+ } catch (err) {
9774
+ failDaemonInstall(`systemctl --user start ${SYSTEMD_SERVICE}`, err);
9775
+ }
9776
+ if (!isSystemdServiceActive()) {
9777
+ failDaemonInstall(`systemctl --user is-active ${SYSTEMD_SERVICE}`, new Error("service is not active after install"));
9509
9778
  }
9510
9779
  console.log(`Installed systemd user service: ${SYSTEMD_UNIT_PATH}`);
9511
9780
  console.log(` Restart: on-failure, WantedBy: default.target`);
@@ -11273,6 +11542,8 @@ export {
11273
11542
  OFFLINE_SYNC_DIRECT_PUSH_MIN_BYTES,
11274
11543
  OFFLINE_SYNC_FILE_CONTENT_UPLOAD_CHUNK_BYTES,
11275
11544
  OFFLINE_SYNC_REQUEST_TIMEOUT_DEFAULT_MS,
11545
+ OFFLINE_SYNC_SNAPSHOT_BASE_POST_MAX_FILES,
11546
+ OFFLINE_SYNC_SNAPSHOT_BASE_POST_PREFERRED_MAX_BODY_BYTES,
11276
11547
  TAXONOMY_RESOLVE_BOOLEAN_FLAGS,
11277
11548
  TAXONOMY_RESOLVE_VALUE_FLAGS,
11278
11549
  __benchDatasetTestHooks,
@@ -11284,6 +11555,7 @@ export {
11284
11555
  chunkOfflineFileContentBatches,
11285
11556
  directHydrateLargeOfflineFiles,
11286
11557
  extractXrayRawArgs,
11558
+ fetchOfflineSnapshot,
11287
11559
  formatOfflineLargeFilePushFailureMessage,
11288
11560
  formatOfflineRequestForError,
11289
11561
  getBenchUsageText,
@@ -11293,6 +11565,7 @@ export {
11293
11565
  offlinePartialHydrationForPaths,
11294
11566
  offlineSnapshotBasePostBody,
11295
11567
  offlineSnapshotBasePostBodyFits,
11568
+ offlineSnapshotBasePostRequest,
11296
11569
  offlineSnapshotContentFilesForApply,
11297
11570
  parseBenchArgs,
11298
11571
  parseCapsuleForkArgs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/cli",
3
- "version": "1.0.24",
3
+ "version": "9.3.515",
4
4
  "description": "CLI for Remnic memory — init, query, doctor, daemon management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,20 +26,20 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "yaml": "^2.4.2",
29
- "@remnic/server": "^1.0.5",
30
- "@remnic/plugin-pi": "^1.0.10",
31
- "@remnic/core": "^1.1.30"
29
+ "@remnic/plugin-pi": "^9.3.515",
30
+ "@remnic/server": "^9.3.515",
31
+ "@remnic/core": "^9.3.515"
32
32
  },
33
33
  "peerDependencies": {
34
- "@remnic/bench": "^1.0.0",
35
- "@remnic/export-weclone": "^1.0.0",
36
- "@remnic/import-weclone": "^1.0.0",
37
- "@remnic/import-chatgpt": "^0.1.0",
38
- "@remnic/import-claude": "^0.1.0",
39
- "@remnic/import-gemini": "^0.1.0",
40
- "@remnic/import-lossless-claw": "^0.1.1",
41
- "@remnic/import-mem0": "^0.1.0",
42
- "@remnic/import-supermemory": "^0.1.1"
34
+ "@remnic/bench": "^9.3.515",
35
+ "@remnic/export-weclone": "^9.3.515",
36
+ "@remnic/import-weclone": "^9.3.515",
37
+ "@remnic/import-chatgpt": "^9.3.515",
38
+ "@remnic/import-claude": "^9.3.515",
39
+ "@remnic/import-gemini": "^9.3.515",
40
+ "@remnic/import-lossless-claw": "^9.3.515",
41
+ "@remnic/import-mem0": "^9.3.515",
42
+ "@remnic/import-supermemory": "^9.3.515"
43
43
  },
44
44
  "peerDependenciesMeta": {
45
45
  "@remnic/bench": {
@@ -73,15 +73,15 @@
73
73
  "devDependencies": {
74
74
  "tsup": "^8.5.1",
75
75
  "typescript": "^5.9.3",
76
- "@remnic/export-weclone": "1.0.1",
77
- "@remnic/bench": "1.0.1",
78
- "@remnic/import-weclone": "1.0.1",
79
- "@remnic/import-chatgpt": "0.1.0",
80
- "@remnic/import-claude": "0.1.0",
81
- "@remnic/import-gemini": "0.1.0",
82
- "@remnic/import-lossless-claw": "0.1.1",
83
- "@remnic/import-mem0": "0.1.0",
84
- "@remnic/import-supermemory": "0.1.2"
76
+ "@remnic/bench": "9.3.515",
77
+ "@remnic/export-weclone": "9.3.515",
78
+ "@remnic/import-weclone": "9.3.515",
79
+ "@remnic/import-claude": "9.3.515",
80
+ "@remnic/import-gemini": "9.3.515",
81
+ "@remnic/import-mem0": "9.3.515",
82
+ "@remnic/import-lossless-claw": "9.3.515",
83
+ "@remnic/import-chatgpt": "9.3.515",
84
+ "@remnic/import-supermemory": "9.3.515"
85
85
  },
86
86
  "license": "MIT",
87
87
  "repository": {