agent-remnote 0.4.1 → 0.4.2

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 (3) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/main.js +577 -202
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # agent-remnote
2
2
 
3
+ ## 0.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 1dfc8f0: Fix Host API write flows so requests using the default `ensureDaemon=true` path no longer fail from missing daemon runtime services.
8
+
9
+ Enable `rem outline` and `daily rem-id` over Host API, and make `apiBaseUrl` behave as a strict remote mode so local-only commands fail fast instead of silently reading local DB state.
10
+
3
11
  ## 0.4.1
4
12
 
5
13
  ### Patch Changes
package/dist/main.js CHANGED
@@ -89911,35 +89911,97 @@ var QueueLive = succeed10(Queue, {
89911
89911
  })
89912
89912
  });
89913
89913
 
89914
+ // src/commands/_remoteMode.ts
89915
+ function normalizeHints(hints) {
89916
+ if (!Array.isArray(hints))
89917
+ return;
89918
+ const out = hints.map((item) => String(item).trim()).filter(Boolean);
89919
+ return out.length > 0 ? out : undefined;
89920
+ }
89921
+ function remoteModeUnsupportedError(params3) {
89922
+ return new CliError({
89923
+ code: "INVALID_ARGS",
89924
+ message: `${params3.command} is unavailable when apiBaseUrl is configured: ${params3.reason}`,
89925
+ exitCode: 2,
89926
+ details: {
89927
+ command: params3.command,
89928
+ api_base_url: params3.apiBaseUrl,
89929
+ reason: params3.reason
89930
+ },
89931
+ hint: normalizeHints([
89932
+ "Run this command on the host if you need direct local DB access.",
89933
+ ...params3.hints ?? []
89934
+ ])
89935
+ });
89936
+ }
89937
+ function failInRemoteMode(params3) {
89938
+ return gen2(function* () {
89939
+ const cfg = yield* AppConfig;
89940
+ if (!cfg.apiBaseUrl)
89941
+ return;
89942
+ return yield* fail8(remoteModeUnsupportedError({
89943
+ command: params3.command,
89944
+ reason: params3.reason,
89945
+ hints: params3.hints,
89946
+ apiBaseUrl: cfg.apiBaseUrl
89947
+ }));
89948
+ });
89949
+ }
89950
+
89914
89951
  // src/services/RemDb.ts
89915
89952
  class RemDb extends Tag2("RemDb")() {
89916
89953
  }
89917
89954
  var RemDbLive = succeed10(RemDb, {
89918
- withDb: (dbPath, fn) => tryPromise2({
89919
- try: async () => await withResolvedDatabase(dbPath, fn),
89920
- catch: (error4) => {
89921
- if (isCliError(error4))
89922
- return error4;
89923
- return new CliError({
89924
- code: "DB_UNAVAILABLE",
89925
- message: String(error4?.message || error4 || "RemNote DB is unavailable"),
89926
- exitCode: 1,
89927
- details: { db_path: dbPath }
89928
- });
89955
+ withDb: (dbPath, fn) => gen2(function* () {
89956
+ const cfg = yield* AppConfig;
89957
+ if (cfg.apiBaseUrl) {
89958
+ return yield* fail8(remoteModeUnsupportedError({
89959
+ command: "local RemNote DB access",
89960
+ reason: "this path still reads the local RemNote database directly",
89961
+ hints: [
89962
+ "Use a Host API backed read command instead.",
89963
+ "If no remote endpoint exists yet, run the command on the host."
89964
+ ],
89965
+ apiBaseUrl: cfg.apiBaseUrl
89966
+ }));
89929
89967
  }
89968
+ return yield* tryPromise2({
89969
+ try: async () => await withResolvedDatabase(dbPath, fn),
89970
+ catch: (error4) => {
89971
+ if (isCliError(error4))
89972
+ return error4;
89973
+ return new CliError({
89974
+ code: "DB_UNAVAILABLE",
89975
+ message: String(error4?.message || error4 || "RemNote DB is unavailable"),
89976
+ exitCode: 1,
89977
+ details: { db_path: dbPath }
89978
+ });
89979
+ }
89980
+ });
89930
89981
  }),
89931
- backups: (basePath) => tryPromise2({
89932
- try: async () => await discoverBackups(basePath),
89933
- catch: (error4) => {
89934
- if (isCliError(error4))
89935
- return error4;
89936
- return new CliError({
89937
- code: "DB_UNAVAILABLE",
89938
- message: String(error4?.message || error4 || "Failed to read RemNote backup directory"),
89939
- exitCode: 1,
89940
- details: { base_path: basePath }
89941
- });
89982
+ backups: (basePath) => gen2(function* () {
89983
+ const cfg = yield* AppConfig;
89984
+ if (cfg.apiBaseUrl) {
89985
+ return yield* fail8(remoteModeUnsupportedError({
89986
+ command: "db backups",
89987
+ reason: "listing backup files requires direct local filesystem access",
89988
+ hints: ["Run this command on the host."],
89989
+ apiBaseUrl: cfg.apiBaseUrl
89990
+ }));
89942
89991
  }
89992
+ return yield* tryPromise2({
89993
+ try: async () => await discoverBackups(basePath),
89994
+ catch: (error4) => {
89995
+ if (isCliError(error4))
89996
+ return error4;
89997
+ return new CliError({
89998
+ code: "DB_UNAVAILABLE",
89999
+ message: String(error4?.message || error4 || "Failed to read RemNote backup directory"),
90000
+ exitCode: 1,
90001
+ details: { base_path: basePath }
90002
+ });
90003
+ }
90004
+ });
89943
90005
  })
89944
90006
  });
89945
90007
 
@@ -92678,6 +92740,10 @@ var days2 = integer7("days").pipe(optional5, map34(optionToUndefined9));
92678
92740
  var maxLines = integer7("max-lines").pipe(optional5, map34(optionToUndefined9));
92679
92741
  var dailySummaryCommand = exports_Command.make("summary", { days: days2, maxLines }, ({ days: days3, maxLines: maxLines2 }) => gen2(function* () {
92680
92742
  const cfg = yield* AppConfig;
92743
+ yield* failInRemoteMode({
92744
+ command: "daily summary",
92745
+ reason: "this command still summarizes Daily Notes from the local RemNote database"
92746
+ });
92681
92747
  const result = yield* tryPromise2({
92682
92748
  try: async () => await executeSummarizeDailyNotes({
92683
92749
  dbPath: cfg.remnoteDb,
@@ -92689,6 +92755,180 @@ var dailySummaryCommand = exports_Command.make("summary", { days: days2, maxLine
92689
92755
  yield* writeSuccess({ data: result, md: result.markdown ?? "" });
92690
92756
  }).pipe(catchAll2(writeFailure)));
92691
92757
 
92758
+ // src/services/HostApiClient.ts
92759
+ function normalizeBaseUrl(baseUrl) {
92760
+ return baseUrl.trim().replace(/\/+$/, "");
92761
+ }
92762
+ function apiTimeoutError(params3) {
92763
+ return new CliError({
92764
+ code: "API_TIMEOUT",
92765
+ message: `API timeout after ${params3.timeoutMs}ms`,
92766
+ exitCode: 1,
92767
+ details: { base_url: params3.baseUrl, path: params3.path, timeout_ms: params3.timeoutMs }
92768
+ });
92769
+ }
92770
+ function apiUnavailableError(params3) {
92771
+ return new CliError({
92772
+ code: "API_UNAVAILABLE",
92773
+ message: String(params3.error?.message || params3.error || "API request failed"),
92774
+ exitCode: 1,
92775
+ details: { base_url: params3.baseUrl, path: params3.path }
92776
+ });
92777
+ }
92778
+ function exitCodeFromRemoteCode(code2) {
92779
+ return code2 === "INVALID_ARGS" ? 2 : 1;
92780
+ }
92781
+ function parseEnvelope(raw4) {
92782
+ if (!raw4 || typeof raw4 !== "object") {
92783
+ return { ok: false, error: { code: "INTERNAL", message: "Invalid API response envelope" } };
92784
+ }
92785
+ return raw4;
92786
+ }
92787
+ function buildQuery(params3) {
92788
+ const sp = new URLSearchParams;
92789
+ for (const [key, value8] of Object.entries(params3)) {
92790
+ if (value8 === undefined || value8 === null)
92791
+ continue;
92792
+ if (typeof value8 === "string") {
92793
+ if (!value8.trim())
92794
+ continue;
92795
+ sp.set(key, value8);
92796
+ continue;
92797
+ }
92798
+ if (typeof value8 === "number" || typeof value8 === "boolean") {
92799
+ sp.set(key, String(value8));
92800
+ }
92801
+ }
92802
+ const query = sp.toString();
92803
+ return query ? `?${query}` : "";
92804
+ }
92805
+ function requestJson(params3) {
92806
+ const timeoutMs = Math.max(1, params3.timeoutMs ?? 15000);
92807
+ const baseUrl = normalizeBaseUrl(params3.baseUrl);
92808
+ const url2 = `${baseUrl}${params3.path}`;
92809
+ return async((resume2) => {
92810
+ const controller = new AbortController;
92811
+ const timer2 = setTimeout(() => controller.abort(), timeoutMs);
92812
+ fetch(url2, {
92813
+ method: params3.method,
92814
+ headers: params3.method === "POST" ? { "content-type": "application/json" } : undefined,
92815
+ body: params3.body === undefined ? undefined : JSON.stringify(params3.body),
92816
+ signal: controller.signal
92817
+ }).then(async (response) => {
92818
+ clearTimeout(timer2);
92819
+ let parsed;
92820
+ try {
92821
+ parsed = parseEnvelope(await response.json());
92822
+ } catch (error4) {
92823
+ resume2(fail8(new CliError({
92824
+ code: "API_UNAVAILABLE",
92825
+ message: "API returned a non-JSON response",
92826
+ exitCode: 1,
92827
+ details: { url: url2, status: response.status, error: String(error4?.message || error4) }
92828
+ })));
92829
+ return;
92830
+ }
92831
+ if (parsed.ok === true) {
92832
+ resume2(succeed8(parsed.data));
92833
+ return;
92834
+ }
92835
+ const code2 = typeof parsed.error?.code === "string" ? parsed.error.code : "INTERNAL";
92836
+ const message2 = typeof parsed.error?.message === "string" ? parsed.error.message : "API request failed";
92837
+ const hint = Array.isArray(parsed.hint) ? parsed.hint.map(String) : undefined;
92838
+ resume2(fail8(new CliError({
92839
+ code: code2,
92840
+ message: message2,
92841
+ exitCode: exitCodeFromRemoteCode(code2),
92842
+ details: parsed.error?.details,
92843
+ hint
92844
+ })));
92845
+ }).catch((error4) => {
92846
+ clearTimeout(timer2);
92847
+ if (error4?.name === "AbortError") {
92848
+ resume2(fail8(apiTimeoutError({ baseUrl, path: params3.path, timeoutMs })));
92849
+ return;
92850
+ }
92851
+ resume2(fail8(apiUnavailableError({ baseUrl, path: params3.path, error: error4 })));
92852
+ });
92853
+ return sync3(() => {
92854
+ clearTimeout(timer2);
92855
+ controller.abort();
92856
+ });
92857
+ });
92858
+ }
92859
+
92860
+ class HostApiClient extends Tag2("HostApiClient")() {
92861
+ }
92862
+ var HostApiClientLive = succeed10(HostApiClient, {
92863
+ health: ({ baseUrl, timeoutMs }) => requestJson({ baseUrl, path: "/v1/health", method: "GET", timeoutMs }),
92864
+ status: ({ baseUrl, timeoutMs }) => requestJson({ baseUrl, path: "/v1/status", method: "GET", timeoutMs }),
92865
+ uiContextSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => requestJson({
92866
+ baseUrl,
92867
+ path: `/v1/plugin/ui-context/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
92868
+ method: "GET",
92869
+ timeoutMs
92870
+ }),
92871
+ uiContextPage: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => requestJson({
92872
+ baseUrl,
92873
+ path: `/v1/plugin/ui-context/page${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
92874
+ method: "GET",
92875
+ timeoutMs
92876
+ }),
92877
+ uiContextFocusedRem: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => requestJson({
92878
+ baseUrl,
92879
+ path: `/v1/plugin/ui-context/focused-rem${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
92880
+ method: "GET",
92881
+ timeoutMs
92882
+ }),
92883
+ uiContextDescribe: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs }) => requestJson({
92884
+ baseUrl,
92885
+ path: `/v1/plugin/ui-context/describe${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
92886
+ method: "GET",
92887
+ timeoutMs
92888
+ }),
92889
+ selectionSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => requestJson({
92890
+ baseUrl,
92891
+ path: `/v1/plugin/selection/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
92892
+ method: "GET",
92893
+ timeoutMs
92894
+ }),
92895
+ selectionRoots: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => requestJson({
92896
+ baseUrl,
92897
+ path: `/v1/plugin/selection/roots${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
92898
+ method: "GET",
92899
+ timeoutMs
92900
+ }),
92901
+ selectionCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs }) => requestJson({
92902
+ baseUrl,
92903
+ path: `/v1/plugin/selection/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
92904
+ method: "GET",
92905
+ timeoutMs
92906
+ }),
92907
+ pluginCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs }) => requestJson({
92908
+ baseUrl,
92909
+ path: `/v1/plugin/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
92910
+ method: "GET",
92911
+ timeoutMs
92912
+ }),
92913
+ selectionOutline: ({ baseUrl, body, timeoutMs }) => requestJson({ baseUrl, path: "/v1/plugin/selection/outline", method: "POST", body, timeoutMs }),
92914
+ uiContext: ({ baseUrl, timeoutMs }) => requestJson({ baseUrl, path: "/v1/ui-context", method: "GET", timeoutMs }),
92915
+ selection: ({ baseUrl, timeoutMs }) => requestJson({ baseUrl, path: "/v1/selection", method: "GET", timeoutMs }),
92916
+ searchDb: ({ baseUrl, ...body }) => requestJson({ baseUrl, path: "/v1/search/db", method: "POST", body }),
92917
+ searchPlugin: ({ baseUrl, ...body }) => requestJson({ baseUrl, path: "/v1/search/plugin", method: "POST", body }),
92918
+ writeOps: ({ baseUrl, body, timeoutMs }) => requestJson({ baseUrl, path: "/v1/write/ops", method: "POST", body, timeoutMs }),
92919
+ writeMarkdown: ({ baseUrl, body, timeoutMs }) => requestJson({ baseUrl, path: "/v1/write/markdown", method: "POST", body, timeoutMs }),
92920
+ readOutline: ({ baseUrl, body, timeoutMs }) => requestJson({ baseUrl, path: "/v1/read/outline", method: "POST", body, timeoutMs }),
92921
+ dailyRemId: ({ baseUrl, date: date6, offsetDays, timeoutMs }) => requestJson({
92922
+ baseUrl,
92923
+ path: `/v1/daily/rem-id${buildQuery({ date: date6, offsetDays })}`,
92924
+ method: "GET",
92925
+ timeoutMs
92926
+ }),
92927
+ queueWait: ({ baseUrl, txnId, timeoutMs, pollMs }) => requestJson({ baseUrl, path: "/v1/queue/wait", method: "POST", body: { txnId, timeoutMs, pollMs } }),
92928
+ queueTxn: ({ baseUrl, txnId, timeoutMs }) => requestJson({ baseUrl, path: `/v1/queue/txns/${encodeURIComponent(txnId)}`, method: "GET", timeoutMs }),
92929
+ triggerSync: ({ baseUrl, timeoutMs }) => requestJson({ baseUrl, path: "/v1/actions/trigger-sync", method: "POST", timeoutMs })
92930
+ });
92931
+
92692
92932
  // src/services/RefResolver.ts
92693
92933
  class RefResolver extends Tag2("RefResolver")() {
92694
92934
  }
@@ -92772,6 +93012,17 @@ var RefResolverLive = succeed10(RefResolver, {
92772
93012
  try: () => parseRef(ref),
92773
93013
  catch: (e) => e && typeof e === "object" && e._tag === "CliError" ? e : new CliError({ code: "INVALID_ARGS", message: `Invalid ref: ${ref}`, exitCode: 2 })
92774
93014
  });
93015
+ if (cfg.apiBaseUrl && parsed.kind !== "id") {
93016
+ return yield* fail8(remoteModeUnsupportedError({
93017
+ command: `ref resolution (${ref})`,
93018
+ reason: "this path still resolves refs by reading the local RemNote database",
93019
+ hints: [
93020
+ "Use a remote-capable command that accepts --ref and forwards it to the host API.",
93021
+ "If no remote endpoint exists yet, run the command on the host."
93022
+ ],
93023
+ apiBaseUrl: cfg.apiBaseUrl
93024
+ }));
93025
+ }
92775
93026
  if (parsed.kind === "id")
92776
93027
  return parsed.value;
92777
93028
  const dailyOffset = parsed.kind === "daily" ? yield* try_3({
@@ -92816,10 +93067,15 @@ function optionToUndefined10(opt) {
92816
93067
  return isSome2(opt) ? opt.value : undefined;
92817
93068
  }
92818
93069
  function parseDateInput(raw4) {
92819
- const value8 = new Date(raw4);
93070
+ const trimmed2 = raw4.trim();
93071
+ const match24 = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed2);
93072
+ const value8 = match24 ? new Date(Number(match24[1]), Number(match24[2]) - 1, Number(match24[3])) : new Date(trimmed2);
92820
93073
  if (Number.isNaN(value8.getTime())) {
92821
93074
  throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
92822
93075
  }
93076
+ if (match24 && (value8.getFullYear() !== Number(match24[1]) || value8.getMonth() !== Number(match24[2]) - 1 || value8.getDate() !== Number(match24[3]))) {
93077
+ throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
93078
+ }
92823
93079
  return value8;
92824
93080
  }
92825
93081
  var date6 = text9("date").pipe(optional5, map34(optionToUndefined10));
@@ -92829,8 +93085,25 @@ var dailyRemIdCommand = exports_Command.make("rem-id", { date: date6, offsetDays
92829
93085
  return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Choose only one of --date or --offset-days", exitCode: 2 }));
92830
93086
  }
92831
93087
  const cfg = yield* AppConfig;
93088
+ const hostApi = yield* HostApiClient;
92832
93089
  const refs = yield* RefResolver;
92833
93090
  const remDb = yield* RemDb;
93091
+ if (cfg.apiBaseUrl) {
93092
+ const data = yield* hostApi.dailyRemId({
93093
+ baseUrl: cfg.apiBaseUrl,
93094
+ date: date7,
93095
+ offsetDays: offsetDays2
93096
+ });
93097
+ yield* writeSuccess({
93098
+ data,
93099
+ ids: [data.remId],
93100
+ md: `- ref: ${data.ref}
93101
+ - rem_id: ${data.remId}${data.dateString ? `
93102
+ - date_string: ${data.dateString}` : ""}
93103
+ `
93104
+ });
93105
+ return;
93106
+ }
92834
93107
  let ref = `daily:${offsetDays2 ?? 0}`;
92835
93108
  let remId = "";
92836
93109
  let dateString;
@@ -93466,10 +93739,15 @@ var bundleTitle = readOptionalText("bundle-title");
93466
93739
  var BULK_THRESHOLD_LINES = 80;
93467
93740
  var BULK_THRESHOLD_CHARS = 5000;
93468
93741
  function parseDateInput2(raw4) {
93469
- const d = new Date(raw4);
93742
+ const trimmed2 = raw4.trim();
93743
+ const match24 = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed2);
93744
+ const d = match24 ? new Date(Number(match24[1]), Number(match24[2]) - 1, Number(match24[3])) : new Date(trimmed2);
93470
93745
  if (isNaN(d.getTime())) {
93471
93746
  throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
93472
93747
  }
93748
+ if (match24 && (d.getFullYear() !== Number(match24[1]) || d.getMonth() !== Number(match24[2]) - 1 || d.getDate() !== Number(match24[3]))) {
93749
+ throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
93750
+ }
93473
93751
  return d;
93474
93752
  }
93475
93753
  function todayAtMidnight() {
@@ -93563,6 +93841,11 @@ var dailyWriteCommand = exports_Command.make("write", {
93563
93841
  }));
93564
93842
  }
93565
93843
  const cfg = yield* AppConfig;
93844
+ yield* failInRemoteMode({
93845
+ command: "daily write",
93846
+ reason: "this command still needs local Daily Note metadata before enqueueing writes",
93847
+ hints: ["Use `import markdown --ref daily:today ...` in remote mode."]
93848
+ });
93566
93849
  const fileInput = yield* FileInput;
93567
93850
  const payloadSvc = yield* Payload;
93568
93851
  const remDb = yield* RemDb;
@@ -93589,7 +93872,11 @@ var dailyWriteCommand = exports_Command.make("write", {
93589
93872
  const target2 = date8 ? yield* try_3({
93590
93873
  try: () => parseDateInput2(date8),
93591
93874
  catch: (e) => isCliError(e) ? e : new CliError({ code: "INVALID_ARGS", message: "Invalid date", exitCode: 2 })
93592
- }) : new Date(todayAtMidnight().getTime() + (offsetDays3 ?? 0) * 24 * 3600 * 1000);
93875
+ }) : (() => {
93876
+ const target3 = todayAtMidnight();
93877
+ target3.setDate(target3.getDate() + (offsetDays3 ?? 0));
93878
+ return target3;
93879
+ })();
93593
93880
  const dateString = yield* remDb.withDb(cfg.remnoteDb, async (db) => {
93594
93881
  const fmt = await getDateFormatting(db) ?? "yyyy/MM/dd";
93595
93882
  return formatDateWithPattern(target2, fmt);
@@ -93668,21 +93955,27 @@ function optionToUndefined12(opt) {
93668
93955
  }
93669
93956
  var basePath = text9("base-path").pipe(optional5, map34(optionToUndefined12));
93670
93957
  var limit = integer7("limit").pipe(withDefault5(50));
93671
- var dbBackupsCommand = exports_Command.make("backups", { basePath, limit }, ({ basePath: basePath2, limit: limit2 }) => tryPromise2({
93672
- try: async () => await executeListRemBackups({
93673
- basePath: basePath2 ? resolveUserFilePath(basePath2) : undefined,
93674
- limit: limit2
93675
- }),
93676
- catch: (e) => cliErrorFromUnknown(e, { code: "DB_UNAVAILABLE" })
93677
- }).pipe(flatMap9((result) => {
93958
+ var dbBackupsCommand = exports_Command.make("backups", { basePath, limit }, ({ basePath: basePath2, limit: limit2 }) => gen2(function* () {
93959
+ yield* AppConfig;
93960
+ yield* failInRemoteMode({
93961
+ command: "db backups",
93962
+ reason: "this command still lists local RemNote backup files from the filesystem"
93963
+ });
93964
+ const result = yield* tryPromise2({
93965
+ try: async () => await executeListRemBackups({
93966
+ basePath: basePath2 ? resolveUserFilePath(basePath2) : undefined,
93967
+ limit: limit2
93968
+ }),
93969
+ catch: (e) => cliErrorFromUnknown(e, { code: "DB_UNAVAILABLE" })
93970
+ });
93678
93971
  const md = [
93679
93972
  `- base_path: ${result.basePath}`,
93680
93973
  `- total: ${result.total}`,
93681
93974
  ...Array.isArray(result.items) ? result.items.map((it) => `- ${it.path}`) : []
93682
93975
  ].join(`
93683
93976
  `);
93684
- return writeSuccess({ data: result, md });
93685
- }), catchAll2(writeFailure)));
93977
+ yield* writeSuccess({ data: result, md });
93978
+ }).pipe(catchAll2(writeFailure)));
93686
93979
 
93687
93980
  // src/commands/read/db/recent.ts
93688
93981
  function optionToUndefined13(opt) {
@@ -94256,173 +94549,6 @@ var wechatOutlineCommand = exports_Command.make("outline", {
94256
94549
  // src/commands/write/wechat/index.ts
94257
94550
  var writeWechatCommand = exports_Command.make("wechat", {}).pipe(exports_Command.withSubcommands([wechatOutlineCommand]));
94258
94551
 
94259
- // src/services/HostApiClient.ts
94260
- function normalizeBaseUrl(baseUrl) {
94261
- return baseUrl.trim().replace(/\/+$/, "");
94262
- }
94263
- function apiTimeoutError(params3) {
94264
- return new CliError({
94265
- code: "API_TIMEOUT",
94266
- message: `API timeout after ${params3.timeoutMs}ms`,
94267
- exitCode: 1,
94268
- details: { base_url: params3.baseUrl, path: params3.path, timeout_ms: params3.timeoutMs }
94269
- });
94270
- }
94271
- function apiUnavailableError(params3) {
94272
- return new CliError({
94273
- code: "API_UNAVAILABLE",
94274
- message: String(params3.error?.message || params3.error || "API request failed"),
94275
- exitCode: 1,
94276
- details: { base_url: params3.baseUrl, path: params3.path }
94277
- });
94278
- }
94279
- function exitCodeFromRemoteCode(code2) {
94280
- return code2 === "INVALID_ARGS" ? 2 : 1;
94281
- }
94282
- function parseEnvelope(raw4) {
94283
- if (!raw4 || typeof raw4 !== "object") {
94284
- return { ok: false, error: { code: "INTERNAL", message: "Invalid API response envelope" } };
94285
- }
94286
- return raw4;
94287
- }
94288
- function buildQuery(params3) {
94289
- const sp = new URLSearchParams;
94290
- for (const [key, value8] of Object.entries(params3)) {
94291
- if (value8 === undefined || value8 === null)
94292
- continue;
94293
- if (typeof value8 === "string") {
94294
- if (!value8.trim())
94295
- continue;
94296
- sp.set(key, value8);
94297
- continue;
94298
- }
94299
- if (typeof value8 === "number" || typeof value8 === "boolean") {
94300
- sp.set(key, String(value8));
94301
- }
94302
- }
94303
- const query = sp.toString();
94304
- return query ? `?${query}` : "";
94305
- }
94306
- function requestJson(params3) {
94307
- const timeoutMs2 = Math.max(1, params3.timeoutMs ?? 15000);
94308
- const baseUrl = normalizeBaseUrl(params3.baseUrl);
94309
- const url2 = `${baseUrl}${params3.path}`;
94310
- return async((resume2) => {
94311
- const controller = new AbortController;
94312
- const timer2 = setTimeout(() => controller.abort(), timeoutMs2);
94313
- fetch(url2, {
94314
- method: params3.method,
94315
- headers: params3.method === "POST" ? { "content-type": "application/json" } : undefined,
94316
- body: params3.body === undefined ? undefined : JSON.stringify(params3.body),
94317
- signal: controller.signal
94318
- }).then(async (response) => {
94319
- clearTimeout(timer2);
94320
- let parsed;
94321
- try {
94322
- parsed = parseEnvelope(await response.json());
94323
- } catch (error4) {
94324
- resume2(fail8(new CliError({
94325
- code: "API_UNAVAILABLE",
94326
- message: "API returned a non-JSON response",
94327
- exitCode: 1,
94328
- details: { url: url2, status: response.status, error: String(error4?.message || error4) }
94329
- })));
94330
- return;
94331
- }
94332
- if (parsed.ok === true) {
94333
- resume2(succeed8(parsed.data));
94334
- return;
94335
- }
94336
- const code2 = typeof parsed.error?.code === "string" ? parsed.error.code : "INTERNAL";
94337
- const message2 = typeof parsed.error?.message === "string" ? parsed.error.message : "API request failed";
94338
- const hint = Array.isArray(parsed.hint) ? parsed.hint.map(String) : undefined;
94339
- resume2(fail8(new CliError({
94340
- code: code2,
94341
- message: message2,
94342
- exitCode: exitCodeFromRemoteCode(code2),
94343
- details: parsed.error?.details,
94344
- hint
94345
- })));
94346
- }).catch((error4) => {
94347
- clearTimeout(timer2);
94348
- if (error4?.name === "AbortError") {
94349
- resume2(fail8(apiTimeoutError({ baseUrl, path: params3.path, timeoutMs: timeoutMs2 })));
94350
- return;
94351
- }
94352
- resume2(fail8(apiUnavailableError({ baseUrl, path: params3.path, error: error4 })));
94353
- });
94354
- return sync3(() => {
94355
- clearTimeout(timer2);
94356
- controller.abort();
94357
- });
94358
- });
94359
- }
94360
-
94361
- class HostApiClient extends Tag2("HostApiClient")() {
94362
- }
94363
- var HostApiClientLive = succeed10(HostApiClient, {
94364
- health: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/health", method: "GET", timeoutMs: timeoutMs2 }),
94365
- status: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/status", method: "GET", timeoutMs: timeoutMs2 }),
94366
- uiContextSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94367
- baseUrl,
94368
- path: `/v1/plugin/ui-context/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94369
- method: "GET",
94370
- timeoutMs: timeoutMs2
94371
- }),
94372
- uiContextPage: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94373
- baseUrl,
94374
- path: `/v1/plugin/ui-context/page${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94375
- method: "GET",
94376
- timeoutMs: timeoutMs2
94377
- }),
94378
- uiContextFocusedRem: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94379
- baseUrl,
94380
- path: `/v1/plugin/ui-context/focused-rem${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94381
- method: "GET",
94382
- timeoutMs: timeoutMs2
94383
- }),
94384
- uiContextDescribe: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs: timeoutMs2 }) => requestJson({
94385
- baseUrl,
94386
- path: `/v1/plugin/ui-context/describe${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
94387
- method: "GET",
94388
- timeoutMs: timeoutMs2
94389
- }),
94390
- selectionSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94391
- baseUrl,
94392
- path: `/v1/plugin/selection/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94393
- method: "GET",
94394
- timeoutMs: timeoutMs2
94395
- }),
94396
- selectionRoots: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94397
- baseUrl,
94398
- path: `/v1/plugin/selection/roots${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94399
- method: "GET",
94400
- timeoutMs: timeoutMs2
94401
- }),
94402
- selectionCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94403
- baseUrl,
94404
- path: `/v1/plugin/selection/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94405
- method: "GET",
94406
- timeoutMs: timeoutMs2
94407
- }),
94408
- pluginCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs: timeoutMs2 }) => requestJson({
94409
- baseUrl,
94410
- path: `/v1/plugin/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
94411
- method: "GET",
94412
- timeoutMs: timeoutMs2
94413
- }),
94414
- selectionOutline: ({ baseUrl, body, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/plugin/selection/outline", method: "POST", body, timeoutMs: timeoutMs2 }),
94415
- uiContext: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/ui-context", method: "GET", timeoutMs: timeoutMs2 }),
94416
- selection: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/selection", method: "GET", timeoutMs: timeoutMs2 }),
94417
- searchDb: ({ baseUrl, ...body }) => requestJson({ baseUrl, path: "/v1/search/db", method: "POST", body }),
94418
- searchPlugin: ({ baseUrl, ...body }) => requestJson({ baseUrl, path: "/v1/search/plugin", method: "POST", body }),
94419
- writeOps: ({ baseUrl, body, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/write/ops", method: "POST", body, timeoutMs: timeoutMs2 }),
94420
- writeMarkdown: ({ baseUrl, body, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/write/markdown", method: "POST", body, timeoutMs: timeoutMs2 }),
94421
- queueWait: ({ baseUrl, txnId, timeoutMs: timeoutMs2, pollMs: pollMs2 }) => requestJson({ baseUrl, path: "/v1/queue/wait", method: "POST", body: { txnId, timeoutMs: timeoutMs2, pollMs: pollMs2 } }),
94422
- queueTxn: ({ baseUrl, txnId, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: `/v1/queue/txns/${encodeURIComponent(txnId)}`, method: "GET", timeoutMs: timeoutMs2 }),
94423
- triggerSync: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/actions/trigger-sync", method: "POST", timeoutMs: timeoutMs2 })
94424
- });
94425
-
94426
94552
  // src/commands/import/markdown.ts
94427
94553
  function optionToUndefined15(opt) {
94428
94554
  return isSome2(opt) ? opt.value : undefined;
@@ -95574,6 +95700,22 @@ function clampInt5(value8, min5, max7) {
95574
95700
  return min5;
95575
95701
  return Math.max(min5, Math.min(max7, Math.floor(value8)));
95576
95702
  }
95703
+ function parseDateInput3(raw4) {
95704
+ const trimmed2 = raw4.trim();
95705
+ const match24 = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed2);
95706
+ const value8 = match24 ? new Date(Number(match24[1]), Number(match24[2]) - 1, Number(match24[3])) : new Date(trimmed2);
95707
+ if (Number.isNaN(value8.getTime())) {
95708
+ throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
95709
+ }
95710
+ if (match24 && (value8.getFullYear() !== Number(match24[1]) || value8.getMonth() !== Number(match24[2]) - 1 || value8.getDate() !== Number(match24[3]))) {
95711
+ throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
95712
+ }
95713
+ return value8;
95714
+ }
95715
+ function todayAtMidnight2() {
95716
+ const now2 = new Date;
95717
+ return new Date(now2.getFullYear(), now2.getMonth(), now2.getDate());
95718
+ }
95577
95719
  function executeDbSearchUseCase(params3) {
95578
95720
  return gen2(function* () {
95579
95721
  const cfg = yield* AppConfig;
@@ -95629,6 +95771,87 @@ function executePluginSearchUseCase(params3) {
95629
95771
  });
95630
95772
  });
95631
95773
  }
95774
+ function executeReadOutlineUseCase(params3) {
95775
+ return gen2(function* () {
95776
+ const cfg = yield* AppConfig;
95777
+ const refs = yield* RefResolver;
95778
+ if (params3.id && params3.ref) {
95779
+ return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Choose only one of --id or --ref", exitCode: 2 }));
95780
+ }
95781
+ const resolvedId = params3.ref ? yield* refs.resolve(params3.ref) : params3.id;
95782
+ if (!resolvedId) {
95783
+ return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "You must provide --id or --ref", exitCode: 2 }));
95784
+ }
95785
+ return yield* tryPromise2({
95786
+ try: async () => await executeOutlineRemSubtree({
95787
+ id: resolvedId,
95788
+ dbPath: cfg.remnoteDb,
95789
+ maxDepth: params3.depth,
95790
+ startOffset: params3.offset,
95791
+ maxNodes: params3.nodes,
95792
+ format: params3.format === "json" ? "json" : "markdown",
95793
+ excludeProperties: params3.excludeProperties === true,
95794
+ includeEmpty: params3.includeEmpty === true,
95795
+ expandReferences: params3.expandReferences === false ? false : undefined,
95796
+ maxReferenceDepth: params3.maxReferenceDepth,
95797
+ detail: params3.detail === true
95798
+ }),
95799
+ catch: (error4) => cliErrorFromUnknown(error4, { code: "DB_UNAVAILABLE" })
95800
+ });
95801
+ });
95802
+ }
95803
+ function executeDailyRemIdUseCase(params3) {
95804
+ return gen2(function* () {
95805
+ if (params3.date && params3.offsetDays !== undefined) {
95806
+ return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Choose only one of --date or --offset-days", exitCode: 2 }));
95807
+ }
95808
+ const cfg = yield* AppConfig;
95809
+ const refs = yield* RefResolver;
95810
+ const remDb = yield* RemDb;
95811
+ let ref3 = `daily:${params3.offsetDays ?? 0}`;
95812
+ let remId = "";
95813
+ let dateString;
95814
+ if (params3.date) {
95815
+ const target2 = parseDateInput3(params3.date);
95816
+ dateString = yield* remDb.withDb(cfg.remnoteDb, async (db) => {
95817
+ const format9 = await getDateFormatting(db) ?? "yyyy/MM/dd";
95818
+ return formatDateWithPattern(target2, format9);
95819
+ }).pipe(map17((result2) => result2.result), catchAll2(() => succeed8(formatDateWithPattern(target2, "yyyy/MM/dd"))));
95820
+ const result = yield* tryPromise2({
95821
+ try: async () => await executeSearchRemOverview({
95822
+ query: dateString,
95823
+ dbPath: cfg.remnoteDb,
95824
+ limit: 1,
95825
+ preferExact: true,
95826
+ exactFirstSingle: true,
95827
+ excludePages: true
95828
+ }),
95829
+ catch: (error4) => cliErrorFromUnknown(error4, { code: "DB_UNAVAILABLE" })
95830
+ });
95831
+ const first3 = Array.isArray(result.matches) ? result.matches[0] : undefined;
95832
+ remId = first3?.id ? String(first3.id) : "";
95833
+ ref3 = `daily:${params3.date}`;
95834
+ if (!remId) {
95835
+ return yield* fail8(new CliError({
95836
+ code: "INVALID_ARGS",
95837
+ message: `No Daily Rem found for date: ${params3.date}`,
95838
+ exitCode: 2
95839
+ }));
95840
+ }
95841
+ } else {
95842
+ const offset = params3.offsetDays ?? 0;
95843
+ ref3 = `daily:${offset}`;
95844
+ remId = yield* refs.resolve(ref3);
95845
+ const target2 = todayAtMidnight2();
95846
+ target2.setDate(target2.getDate() + offset);
95847
+ dateString = yield* remDb.withDb(cfg.remnoteDb, async (db) => {
95848
+ const format9 = await getDateFormatting(db) ?? "yyyy/MM/dd";
95849
+ return formatDateWithPattern(target2, format9);
95850
+ }).pipe(map17((result) => result.result), catchAll2(() => succeed8(undefined)));
95851
+ }
95852
+ return { ref: ref3, remId, dateString };
95853
+ });
95854
+ }
95632
95855
  function executeWriteOpsUseCase(params3) {
95633
95856
  return gen2(function* () {
95634
95857
  const parsed = yield* try_3({
@@ -96189,19 +96412,23 @@ function readJsonBody(req) {
96189
96412
  function runHttpApiRuntime(params3) {
96190
96413
  return gen2(function* () {
96191
96414
  const cfg = yield* AppConfig;
96415
+ const runtimeCfg = { ...cfg, apiBaseUrl: undefined };
96192
96416
  const apiFiles = yield* ApiDaemonFiles;
96417
+ const daemonFiles = yield* DaemonFiles;
96193
96418
  const ws = yield* WsClient;
96194
96419
  const queue = yield* Queue;
96195
96420
  const payload = yield* Payload;
96196
96421
  const refs = yield* RefResolver;
96197
96422
  const hostApi = yield* HostApiClient;
96198
96423
  const remDb = yield* RemDb;
96424
+ const processSvc = yield* Process;
96425
+ const supervisorState = yield* SupervisorState;
96199
96426
  const statusLine = yield* StatusLineController;
96200
96427
  const host3 = params3?.host ?? cfg.apiHost ?? "0.0.0.0";
96201
96428
  const configuredPort = params3?.port ?? cfg.apiPort ?? 3000;
96202
96429
  const stateFilePath = params3?.stateFile ?? cfg.apiStateFile ?? apiFiles.defaultStateFile();
96203
96430
  const startedAt = Date.now();
96204
- const provide6 = (effect4) => effect4.pipe(provideService2(AppConfig, cfg), provideService2(ApiDaemonFiles, apiFiles), provideService2(WsClient, ws), provideService2(Queue, queue), provideService2(Payload, payload), provideService2(RefResolver, refs), provideService2(HostApiClient, hostApi), provideService2(RemDb, remDb), provideService2(StatusLineController, statusLine));
96431
+ const provide6 = (effect4) => effect4.pipe(provideService2(AppConfig, runtimeCfg), provideService2(ApiDaemonFiles, apiFiles), provideService2(DaemonFiles, daemonFiles), provideService2(WsClient, ws), provideService2(Queue, queue), provideService2(Payload, payload), provideService2(RefResolver, refs), provideService2(HostApiClient, hostApi), provideService2(RemDb, remDb), provideService2(Process, processSvc), provideService2(SupervisorState, supervisorState), provideService2(StatusLineController, statusLine));
96205
96432
  const server = createServer((req, res) => {
96206
96433
  const url2 = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
96207
96434
  const method = req.method || "GET";
@@ -96309,6 +96536,13 @@ function runHttpApiRuntime(params3) {
96309
96536
  }));
96310
96537
  return;
96311
96538
  }
96539
+ if (method === "GET" && url2.pathname === "/v1/daily/rem-id") {
96540
+ run12(executeDailyRemIdUseCase({
96541
+ date: url2.searchParams.get("date") ?? undefined,
96542
+ offsetDays: url2.searchParams.get("offsetDays") ? Number(url2.searchParams.get("offsetDays")) : undefined
96543
+ }));
96544
+ return;
96545
+ }
96312
96546
  if (method === "POST" && url2.pathname === "/v1/plugin/selection/outline") {
96313
96547
  (async () => {
96314
96548
  try {
@@ -96362,6 +96596,35 @@ function runHttpApiRuntime(params3) {
96362
96596
  })();
96363
96597
  return;
96364
96598
  }
96599
+ if (method === "POST" && url2.pathname === "/v1/read/outline") {
96600
+ (async () => {
96601
+ try {
96602
+ const body = await runPromise(readJsonBody(req));
96603
+ await run12(executeReadOutlineUseCase({
96604
+ id: typeof body?.id === "string" ? body.id : undefined,
96605
+ ref: typeof body?.ref === "string" ? body.ref : undefined,
96606
+ depth: typeof body?.depth === "number" ? body.depth : undefined,
96607
+ offset: typeof body?.offset === "number" ? body.offset : undefined,
96608
+ nodes: typeof body?.nodes === "number" ? body.nodes : undefined,
96609
+ format: body?.format === "json" ? "json" : body?.format === "md" ? "md" : undefined,
96610
+ excludeProperties: body?.excludeProperties === true,
96611
+ includeEmpty: body?.includeEmpty === true,
96612
+ expandReferences: body?.expandReferences === true ? true : body?.expandReferences === false ? false : undefined,
96613
+ maxReferenceDepth: typeof body?.maxReferenceDepth === "number" ? body.maxReferenceDepth : undefined,
96614
+ detail: body?.detail === true
96615
+ }));
96616
+ } catch (error4) {
96617
+ const cliError = isCliError(error4) ? error4 : new CliError({
96618
+ code: "INVALID_PAYLOAD",
96619
+ message: "Invalid JSON body",
96620
+ exitCode: 2,
96621
+ details: { error: String(error4?.message || error4) }
96622
+ });
96623
+ sendJson2(res, statusCodeFromCliError(cliError), fail21(toJsonError(cliError), cliError.hint));
96624
+ }
96625
+ })();
96626
+ return;
96627
+ }
96365
96628
  if (method === "POST" && url2.pathname === "/v1/search/plugin") {
96366
96629
  (async () => {
96367
96630
  try {
@@ -98390,6 +98653,10 @@ var readPowerupSchemaCommand = exports_Command.make("schema", { powerup, id: id2
98390
98653
  }));
98391
98654
  }
98392
98655
  const cfg = yield* AppConfig;
98656
+ yield* failInRemoteMode({
98657
+ command: "powerup schema",
98658
+ reason: "this command still reads local powerup/table metadata from the RemNote database"
98659
+ });
98393
98660
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
98394
98661
  const tagId = resolved ? resolved.id : normalizeRemIdInput(id3);
98395
98662
  const payload2 = yield* tryPromise2({
@@ -98743,6 +99010,10 @@ var writePowerupApplyCommand = exports_Command.make("apply", {
98743
99010
  }));
98744
99011
  }
98745
99012
  const cfg = yield* AppConfig;
99013
+ yield* failInRemoteMode({
99014
+ command: "powerup apply",
99015
+ reason: "this command still reads local powerup metadata before enqueueing writes"
99016
+ });
98746
99017
  const payloadSvc = yield* Payload;
98747
99018
  const remId = normalizeRemIdInput(rem);
98748
99019
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
@@ -99344,6 +99615,10 @@ var writePowerupRecordAddCommand = exports_Command.make("add", {
99344
99615
  }));
99345
99616
  }
99346
99617
  const cfg = yield* AppConfig;
99618
+ yield* failInRemoteMode({
99619
+ command: "powerup record add",
99620
+ reason: "this command still reads local table metadata before enqueueing writes"
99621
+ });
99347
99622
  const refs = yield* RefResolver;
99348
99623
  const payloadSvc = yield* Payload;
99349
99624
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
@@ -99548,6 +99823,10 @@ var writePowerupRecordDeleteCommand = exports_Command.make("delete", {
99548
99823
  }));
99549
99824
  }
99550
99825
  const cfg = yield* AppConfig;
99826
+ yield* failInRemoteMode({
99827
+ command: "powerup record delete",
99828
+ reason: "this command still validates local table membership before enqueueing writes"
99829
+ });
99551
99830
  const payloadSvc = yield* Payload;
99552
99831
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
99553
99832
  const tableTagId = resolved ? resolved.id : normalizeRemIdInput(tagId);
@@ -99715,6 +99994,10 @@ var writePowerupRecordUpdateCommand = exports_Command.make("update", {
99715
99994
  }));
99716
99995
  }
99717
99996
  const cfg = yield* AppConfig;
99997
+ yield* failInRemoteMode({
99998
+ command: "powerup record update",
99999
+ reason: "this command still reads local table membership and schema metadata before enqueueing writes"
100000
+ });
99718
100001
  const payloadSvc = yield* Payload;
99719
100002
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
99720
100003
  const tableTagId = resolved ? resolved.id : normalizeRemIdInput(tagId);
@@ -100026,6 +100309,10 @@ var sort2 = choice5("sort", ["rank", "updatedAt", "createdAt"]).pipe(optional5,
100026
100309
  var sortDirection = choice5("sort-direction", ["asc", "desc"]).pipe(optional5, map34(optionToUndefined38));
100027
100310
  var readQueryCommand = exports_Command.make("query", { payload: payload2, text: text15, tag: tag7, limit: limit5, offset: offset3, snippetLength, sort: sort2, sortDirection }, ({ payload: payload3, text: text16, tag: tag8, limit: limit6, offset: offset4, snippetLength: snippetLength2, sort: sort3, sortDirection: sortDirection2 }) => gen2(function* () {
100028
100311
  const cfg = yield* AppConfig;
100312
+ yield* failInRemoteMode({
100313
+ command: "query",
100314
+ reason: "this command still executes structured queries against the local RemNote database"
100315
+ });
100029
100316
  const payloadSvc = yield* Payload;
100030
100317
  const queryObj = {};
100031
100318
  if (payload3) {
@@ -100324,6 +100611,10 @@ var readByReferenceCommand = exports_Command.make("by-reference", { reference, t
100324
100611
  return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Provide at least one Rem ID via --reference", exitCode: 2 }));
100325
100612
  }
100326
100613
  const cfg = yield* AppConfig;
100614
+ yield* failInRemoteMode({
100615
+ command: "rem by-reference",
100616
+ reason: "this command still walks the local RemNote database to expand references"
100617
+ });
100327
100618
  const result = yield* tryPromise2({
100328
100619
  try: async () => await executeFindRemsByReference({
100329
100620
  targetIds: reference2,
@@ -100341,6 +100632,10 @@ var readByReferenceCommand = exports_Command.make("by-reference", { reference, t
100341
100632
  // src/commands/read/connections.ts
100342
100633
  var readConnectionsCommand = exports_Command.make("connections", { id: text9("id") }, ({ id: id3 }) => gen2(function* () {
100343
100634
  const cfg = yield* AppConfig;
100635
+ yield* failInRemoteMode({
100636
+ command: "rem connections",
100637
+ reason: "this command still reads local graph connections from the RemNote database"
100638
+ });
100344
100639
  const payload3 = yield* tryPromise2({
100345
100640
  try: async () => await executeGetRemConnections({ id: id3, dbPath: cfg.remnoteDb }),
100346
100641
  catch: (e) => cliErrorFromUnknown(e, { code: "DB_UNAVAILABLE" })
@@ -100359,6 +100654,10 @@ var readInspectCommand = exports_Command.make("inspect", {
100359
100654
  maxReferenceDepth
100360
100655
  }, ({ id: id3, expandReferences, maxReferenceDepth: maxReferenceDepth2 }) => gen2(function* () {
100361
100656
  const cfg = yield* AppConfig;
100657
+ yield* failInRemoteMode({
100658
+ command: "rem inspect",
100659
+ reason: "this command still inspects the local RemNote database directly"
100660
+ });
100362
100661
  const result = yield* tryPromise2({
100363
100662
  try: async () => await executeInspectRemDoc({
100364
100663
  id: id3,
@@ -100415,10 +100714,34 @@ var readOutlineCommand = exports_Command.make("outline", {
100415
100714
  detail
100416
100715
  }) => gen2(function* () {
100417
100716
  const cfg = yield* AppConfig;
100717
+ const hostApi = yield* HostApiClient;
100418
100718
  const refs = yield* RefResolver;
100419
100719
  if (id4 && ref4) {
100420
100720
  return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Choose only one of --id or --ref", exitCode: 2 }));
100421
100721
  }
100722
+ if (!id4 && !ref4) {
100723
+ return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "You must provide --id or --ref", exitCode: 2 }));
100724
+ }
100725
+ if (cfg.apiBaseUrl) {
100726
+ const data = yield* hostApi.readOutline({
100727
+ baseUrl: cfg.apiBaseUrl,
100728
+ body: {
100729
+ id: id4,
100730
+ ref: ref4,
100731
+ depth: depth2,
100732
+ offset: offset6,
100733
+ nodes: nodes2,
100734
+ format: format10 === "json" ? "json" : format10 === "md" ? "md" : undefined,
100735
+ excludeProperties,
100736
+ includeEmpty,
100737
+ expandReferences,
100738
+ maxReferenceDepth: maxReferenceDepth2,
100739
+ detail
100740
+ }
100741
+ });
100742
+ yield* writeSuccess({ data, md: data.markdown ?? "" });
100743
+ return;
100744
+ }
100422
100745
  const link3 = ref4 ? tryParseRemnoteLinkFromRef(ref4) : undefined;
100423
100746
  const resolvedId = ref4 ? link3?.remId ?? (yield* refs.resolve(ref4)) : id4;
100424
100747
  if (!resolvedId) {
@@ -100454,6 +100777,10 @@ var id4 = text9("id").pipe(repeated5);
100454
100777
  var maxHops = integer7("max-hops").pipe(optional5, map34(optionToUndefined44));
100455
100778
  var readPageIdCommand = exports_Command.make("page-id", { ref: ref4, id: id4, maxHops, detail: boolean8("detail") }, ({ ref: ref5, id: id5, maxHops: maxHops2, detail }) => gen2(function* () {
100456
100779
  const cfg = yield* AppConfig;
100780
+ yield* failInRemoteMode({
100781
+ command: "rem page-id",
100782
+ reason: "this command still resolves page ancestry from the local RemNote database"
100783
+ });
100457
100784
  const refs = yield* RefResolver;
100458
100785
  const hasRef = typeof ref5 === "string" && ref5.trim().length > 0;
100459
100786
  const hasIds = Array.isArray(id5) && id5.length > 0;
@@ -100516,6 +100843,10 @@ var readReferencesCommand = exports_Command.make("references", {
100516
100843
  inboundMaxDepth
100517
100844
  }, ({ id: id5, includeDescendants, maxDepth: maxDepth5, includeOccurrences, resolveText, includeInbound, inboundMaxDepth: inboundMaxDepth2 }) => gen2(function* () {
100518
100845
  const cfg = yield* AppConfig;
100846
+ yield* failInRemoteMode({
100847
+ command: "rem references",
100848
+ reason: "this command still reads local reference graphs from the RemNote database"
100849
+ });
100519
100850
  const payload3 = yield* tryPromise2({
100520
100851
  try: async () => {
100521
100852
  const { payload: payload4 } = await executeListRemReferences({
@@ -100548,6 +100879,10 @@ var readResolveRefCommand = exports_Command.make("resolve-ref", {
100548
100879
  detail: boolean8("detail")
100549
100880
  }, ({ ids: ids4, expandReferences, maxReferenceDepth: maxReferenceDepth3, detail }) => gen2(function* () {
100550
100881
  const cfg = yield* AppConfig;
100882
+ yield* failInRemoteMode({
100883
+ command: "rem resolve-ref",
100884
+ reason: "this command still resolves references from the local RemNote database"
100885
+ });
100551
100886
  const result = yield* tryPromise2({
100552
100887
  try: async () => await executeResolveRemReference({
100553
100888
  ids: ids4,
@@ -101224,6 +101559,10 @@ var remCommand = exports_Command.make("rem", {}).pipe(exports_Command.withSubcom
101224
101559
  function resolveReplaceTarget(params3) {
101225
101560
  return gen2(function* () {
101226
101561
  const _cfg = yield* AppConfig;
101562
+ yield* failInRemoteMode({
101563
+ command: "replace target resolution",
101564
+ reason: "replace commands still depend on local selection/ref resolution semantics"
101565
+ });
101227
101566
  const refs = yield* RefResolver;
101228
101567
  const hasSelection = params3.selection === true;
101229
101568
  const hasRef = typeof params3.ref === "string" && params3.ref.trim().length > 0;
@@ -101268,6 +101607,10 @@ function resolveReplaceTarget(params3) {
101268
101607
  function expandTargetIds(params3) {
101269
101608
  return gen2(function* () {
101270
101609
  const cfg = yield* AppConfig;
101610
+ yield* failInRemoteMode({
101611
+ command: "replace subtree expansion",
101612
+ reason: "replace commands still expand target subtrees from the local RemNote database"
101613
+ });
101271
101614
  if (params3.scope === "roots") {
101272
101615
  const unique2 = Array.from(new Set(params3.rootIds));
101273
101616
  return {
@@ -102456,6 +102799,10 @@ var writeTableRecordAddCommand = exports_Command.make("add", {
102456
102799
  }));
102457
102800
  }
102458
102801
  const cfg = yield* AppConfig;
102802
+ yield* failInRemoteMode({
102803
+ command: "table record add",
102804
+ reason: "this command still reads local table metadata before enqueueing writes"
102805
+ });
102459
102806
  const refs = yield* RefResolver;
102460
102807
  const payloadSvc = yield* Payload;
102461
102808
  const resolvedRef = ref7 ?? "daily:today";
@@ -102634,6 +102981,10 @@ var writeTableRecordDeleteCommand = exports_Command.make("delete", {
102634
102981
  }));
102635
102982
  }
102636
102983
  const cfg = yield* AppConfig;
102984
+ yield* failInRemoteMode({
102985
+ command: "table record delete",
102986
+ reason: "this command still validates local row membership before enqueueing writes"
102987
+ });
102637
102988
  const payloadSvc = yield* Payload;
102638
102989
  if (!dryRun) {
102639
102990
  const inspected = yield* tryPromise2({
@@ -102763,6 +103114,10 @@ var writeTableRecordUpdateCommand = exports_Command.make("update", {
102763
103114
  }));
102764
103115
  }
102765
103116
  const cfg = yield* AppConfig;
103117
+ yield* failInRemoteMode({
103118
+ command: "table record update",
103119
+ reason: "this command still reads local row membership and schema metadata before enqueueing writes"
103120
+ });
102766
103121
  const payloadSvc = yield* Payload;
102767
103122
  if (!dryRun) {
102768
103123
  const inspected = yield* tryPromise2({
@@ -102901,6 +103256,10 @@ var tableShowCommand = exports_Command.make("show", {
102901
103256
  offset: offset7
102902
103257
  }, ({ id: id5, includeOptions, limit: limit9, offset: offset8 }) => gen2(function* () {
102903
103258
  const cfg = yield* AppConfig;
103259
+ yield* failInRemoteMode({
103260
+ command: "table show",
103261
+ reason: "this command still reads local table metadata from the RemNote database"
103262
+ });
102904
103263
  const payload3 = yield* tryPromise2({
102905
103264
  try: async () => await executeReadRemTable({
102906
103265
  tagId: id5,
@@ -102999,6 +103358,10 @@ function makeTodosListCommand() {
102999
103358
  offset: offset9
103000
103359
  }) => gen2(function* () {
103001
103360
  const cfg = yield* AppConfig;
103361
+ yield* failInRemoteMode({
103362
+ command: "todos list",
103363
+ reason: "this command still derives todo state from the local RemNote database"
103364
+ });
103002
103365
  const payload3 = yield* tryPromise2({
103003
103366
  try: async () => await executeListTodos({
103004
103367
  dbPath: cfg.remnoteDb,
@@ -103135,6 +103498,10 @@ function todoWriteEffect(params3) {
103135
103498
  }));
103136
103499
  }
103137
103500
  const cfg = yield* AppConfig;
103501
+ yield* failInRemoteMode({
103502
+ command: "todo add",
103503
+ reason: "this command still reads local todo schema metadata before enqueueing writes"
103504
+ });
103138
103505
  const payloadSvc = yield* Payload;
103139
103506
  const remId = normalizeRemIdInput(rem);
103140
103507
  const normalizedTagId = tagId2 ? normalizeRemIdInput(tagId2) : undefined;
@@ -103411,6 +103778,10 @@ var writePowerupTodoRemoveCommand = exports_Command.make("remove", {
103411
103778
  }));
103412
103779
  }
103413
103780
  const cfg = yield* AppConfig;
103781
+ yield* failInRemoteMode({
103782
+ command: "todo remove",
103783
+ reason: "this command still reads local todo schema metadata before enqueueing writes"
103784
+ });
103414
103785
  const payloadSvc = yield* Payload;
103415
103786
  const remId = normalizeRemIdInput(rem);
103416
103787
  const normalizedTagId = tagId2 ? normalizeRemIdInput(tagId2) : undefined;
@@ -103566,6 +103937,10 @@ var maxNodesPerResult = integer7("max-nodes").pipe(optional5, map34(optionToUnde
103566
103937
  var groupBy2 = choice5("group-by", ["none", "parent", "date"]).pipe(optional5, map34(optionToUndefined51));
103567
103938
  var topicSummaryCommand = exports_Command.make("summary", { keywords, query: query2, timeRange: timeRange3, maxResults, maxNodesPerResult, groupBy: groupBy2 }, ({ keywords: keywords2, query: query3, timeRange: timeRange4, maxResults: maxResults2, maxNodesPerResult: maxNodesPerResult2, groupBy: groupBy3 }) => gen2(function* () {
103568
103939
  const cfg = yield* AppConfig;
103940
+ yield* failInRemoteMode({
103941
+ command: "topic summary",
103942
+ reason: "this command still summarizes topics from the local RemNote database"
103943
+ });
103569
103944
  const keywordList = keywords2 ? keywords2.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
103570
103945
  const queryText = query3?.trim() || undefined;
103571
103946
  if ((!keywordList || keywordList.length === 0) && !queryText) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-remnote",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "agent-remnote": "./cli.js"