agent-remnote 0.4.0 → 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 +14 -0
  2. package/dist/main.js +606 -207
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
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
+
11
+ ## 0.4.1
12
+
13
+ ### Patch Changes
14
+
15
+ - 53aad14: Fix Host API write endpoints so remote markdown and op writes no longer fail from a missing status-line runtime service.
16
+
3
17
  ## 0.4.0
4
18
 
5
19
  ### Minor Changes
package/dist/main.js CHANGED
@@ -48355,6 +48355,7 @@ var sleep4 = sleep3;
48355
48355
  var timeout2 = timeout;
48356
48356
  var timeoutOption2 = timeoutOption;
48357
48357
  var timeoutFail2 = timeoutFail;
48358
+ var timeoutTo2 = timeoutTo;
48358
48359
  var withConfigProvider2 = withConfigProvider;
48359
48360
  var context3 = context;
48360
48361
  var contextWithEffect2 = contextWithEffect;
@@ -89910,35 +89911,97 @@ var QueueLive = succeed10(Queue, {
89910
89911
  })
89911
89912
  });
89912
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
+
89913
89951
  // src/services/RemDb.ts
89914
89952
  class RemDb extends Tag2("RemDb")() {
89915
89953
  }
89916
89954
  var RemDbLive = succeed10(RemDb, {
89917
- withDb: (dbPath, fn) => tryPromise2({
89918
- try: async () => await withResolvedDatabase(dbPath, fn),
89919
- catch: (error4) => {
89920
- if (isCliError(error4))
89921
- return error4;
89922
- return new CliError({
89923
- code: "DB_UNAVAILABLE",
89924
- message: String(error4?.message || error4 || "RemNote DB is unavailable"),
89925
- exitCode: 1,
89926
- details: { db_path: dbPath }
89927
- });
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
+ }));
89928
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
+ });
89929
89981
  }),
89930
- backups: (basePath) => tryPromise2({
89931
- try: async () => await discoverBackups(basePath),
89932
- catch: (error4) => {
89933
- if (isCliError(error4))
89934
- return error4;
89935
- return new CliError({
89936
- code: "DB_UNAVAILABLE",
89937
- message: String(error4?.message || error4 || "Failed to read RemNote backup directory"),
89938
- exitCode: 1,
89939
- details: { base_path: basePath }
89940
- });
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
+ }));
89941
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
+ });
89942
90005
  })
89943
90006
  });
89944
90007
 
@@ -90635,6 +90698,18 @@ function unsafeKillAny(child, signal) {
90635
90698
  child.kill(signal);
90636
90699
  } catch {}
90637
90700
  }
90701
+ function drainReadable(stream11) {
90702
+ if (!stream11 || typeof stream11.read !== "function")
90703
+ return "";
90704
+ let out = "";
90705
+ while (true) {
90706
+ const chunk4 = stream11.read();
90707
+ if (chunk4 === null)
90708
+ break;
90709
+ out += String(chunk4);
90710
+ }
90711
+ return out;
90712
+ }
90638
90713
  var SubprocessLive = succeed10(Subprocess, {
90639
90714
  run: ({ command, args: args2, timeoutMs, cwd, env: env2, killSignal }) => scoped2(acquireRelease2(gen2(function* () {
90640
90715
  const stdout2 = { text: "" };
@@ -90701,9 +90776,18 @@ var SubprocessLive = succeed10(Subprocess, {
90701
90776
  yield* sync3(() => unsafeKill(state.child, state.killSignal));
90702
90777
  }
90703
90778
  yield* sync3(state.cleanup);
90704
- })).pipe(flatMap9((state) => _await3(state.exit).pipe(timeoutFail2({
90779
+ })).pipe(flatMap9((state) => _await3(state.exit).pipe(timeoutTo2({
90705
90780
  duration: sanitizeTimeoutMs(timeoutMs),
90706
- onTimeout: () => timeoutCliError({
90781
+ onSuccess: (result) => right2(result),
90782
+ onTimeout: () => left2(undefined)
90783
+ }), flatMap9((result) => isRight2(result) ? succeed8(result.right) : gen2(function* () {
90784
+ yield* sync3(() => unsafeKill(state.child, state.killSignal));
90785
+ yield* sleep4(millis(50));
90786
+ yield* sync3(() => {
90787
+ state.stdout.text += drainReadable(state.child.stdout);
90788
+ state.stderr.text += drainReadable(state.child.stderr);
90789
+ });
90790
+ return yield* fail8(timeoutCliError({
90707
90791
  command,
90708
90792
  args: args2,
90709
90793
  timeoutMs: sanitizeTimeoutMs(timeoutMs),
@@ -90711,8 +90795,8 @@ var SubprocessLive = succeed10(Subprocess, {
90711
90795
  killSignal: state.killSignal,
90712
90796
  stdout: state.stdout.text,
90713
90797
  stderr: state.stderr.text
90714
- })
90715
- }))))),
90798
+ }));
90799
+ })))))),
90716
90800
  runInherit: ({ command, args: args2, cwd, env: env2, killSignal }) => scoped2(acquireRelease2(gen2(function* () {
90717
90801
  const done11 = { value: false };
90718
90802
  const exit3 = yield* make40();
@@ -91464,6 +91548,7 @@ var StatusLineControllerLive = scoped3(StatusLineController, gen2(function* () {
91464
91548
  const cfg = yield* AppConfig;
91465
91549
  const updater = yield* StatusLineUpdater;
91466
91550
  const state = yield* make25(INITIAL_STATE);
91551
+ const runLoopScope = yield* acquireRelease2(make38(), (scope5) => close(scope5, void_3));
91467
91552
  const runLoop2 = gen2(function* () {
91468
91553
  while (true) {
91469
91554
  const snapBefore = yield* get11(state);
@@ -91515,7 +91600,7 @@ var StatusLineControllerLive = scoped3(StatusLineController, gen2(function* () {
91515
91600
  return [s.scheduled === false, next4];
91516
91601
  });
91517
91602
  if (shouldStart) {
91518
- yield* fork3(runLoop2.pipe(catchAll2(() => _void)));
91603
+ yield* forkIn2(runLoopScope)(runLoop2.pipe(catchAll2(() => _void)));
91519
91604
  }
91520
91605
  yield* _await3(waiter);
91521
91606
  })
@@ -92655,6 +92740,10 @@ var days2 = integer7("days").pipe(optional5, map34(optionToUndefined9));
92655
92740
  var maxLines = integer7("max-lines").pipe(optional5, map34(optionToUndefined9));
92656
92741
  var dailySummaryCommand = exports_Command.make("summary", { days: days2, maxLines }, ({ days: days3, maxLines: maxLines2 }) => gen2(function* () {
92657
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
+ });
92658
92747
  const result = yield* tryPromise2({
92659
92748
  try: async () => await executeSummarizeDailyNotes({
92660
92749
  dbPath: cfg.remnoteDb,
@@ -92666,6 +92755,180 @@ var dailySummaryCommand = exports_Command.make("summary", { days: days2, maxLine
92666
92755
  yield* writeSuccess({ data: result, md: result.markdown ?? "" });
92667
92756
  }).pipe(catchAll2(writeFailure)));
92668
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
+
92669
92932
  // src/services/RefResolver.ts
92670
92933
  class RefResolver extends Tag2("RefResolver")() {
92671
92934
  }
@@ -92749,6 +93012,17 @@ var RefResolverLive = succeed10(RefResolver, {
92749
93012
  try: () => parseRef(ref),
92750
93013
  catch: (e) => e && typeof e === "object" && e._tag === "CliError" ? e : new CliError({ code: "INVALID_ARGS", message: `Invalid ref: ${ref}`, exitCode: 2 })
92751
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
+ }
92752
93026
  if (parsed.kind === "id")
92753
93027
  return parsed.value;
92754
93028
  const dailyOffset = parsed.kind === "daily" ? yield* try_3({
@@ -92793,10 +93067,15 @@ function optionToUndefined10(opt) {
92793
93067
  return isSome2(opt) ? opt.value : undefined;
92794
93068
  }
92795
93069
  function parseDateInput(raw4) {
92796
- 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);
92797
93073
  if (Number.isNaN(value8.getTime())) {
92798
93074
  throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
92799
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
+ }
92800
93079
  return value8;
92801
93080
  }
92802
93081
  var date6 = text9("date").pipe(optional5, map34(optionToUndefined10));
@@ -92806,8 +93085,25 @@ var dailyRemIdCommand = exports_Command.make("rem-id", { date: date6, offsetDays
92806
93085
  return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Choose only one of --date or --offset-days", exitCode: 2 }));
92807
93086
  }
92808
93087
  const cfg = yield* AppConfig;
93088
+ const hostApi = yield* HostApiClient;
92809
93089
  const refs = yield* RefResolver;
92810
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
+ }
92811
93107
  let ref = `daily:${offsetDays2 ?? 0}`;
92812
93108
  let remId = "";
92813
93109
  let dateString;
@@ -93443,10 +93739,15 @@ var bundleTitle = readOptionalText("bundle-title");
93443
93739
  var BULK_THRESHOLD_LINES = 80;
93444
93740
  var BULK_THRESHOLD_CHARS = 5000;
93445
93741
  function parseDateInput2(raw4) {
93446
- 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);
93447
93745
  if (isNaN(d.getTime())) {
93448
93746
  throw new CliError({ code: "INVALID_ARGS", message: `Invalid date: ${raw4}`, exitCode: 2 });
93449
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
+ }
93450
93751
  return d;
93451
93752
  }
93452
93753
  function todayAtMidnight() {
@@ -93540,6 +93841,11 @@ var dailyWriteCommand = exports_Command.make("write", {
93540
93841
  }));
93541
93842
  }
93542
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
+ });
93543
93849
  const fileInput = yield* FileInput;
93544
93850
  const payloadSvc = yield* Payload;
93545
93851
  const remDb = yield* RemDb;
@@ -93566,7 +93872,11 @@ var dailyWriteCommand = exports_Command.make("write", {
93566
93872
  const target2 = date8 ? yield* try_3({
93567
93873
  try: () => parseDateInput2(date8),
93568
93874
  catch: (e) => isCliError(e) ? e : new CliError({ code: "INVALID_ARGS", message: "Invalid date", exitCode: 2 })
93569
- }) : 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
+ })();
93570
93880
  const dateString = yield* remDb.withDb(cfg.remnoteDb, async (db) => {
93571
93881
  const fmt = await getDateFormatting(db) ?? "yyyy/MM/dd";
93572
93882
  return formatDateWithPattern(target2, fmt);
@@ -93645,21 +93955,27 @@ function optionToUndefined12(opt) {
93645
93955
  }
93646
93956
  var basePath = text9("base-path").pipe(optional5, map34(optionToUndefined12));
93647
93957
  var limit = integer7("limit").pipe(withDefault5(50));
93648
- var dbBackupsCommand = exports_Command.make("backups", { basePath, limit }, ({ basePath: basePath2, limit: limit2 }) => tryPromise2({
93649
- try: async () => await executeListRemBackups({
93650
- basePath: basePath2 ? resolveUserFilePath(basePath2) : undefined,
93651
- limit: limit2
93652
- }),
93653
- catch: (e) => cliErrorFromUnknown(e, { code: "DB_UNAVAILABLE" })
93654
- }).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
+ });
93655
93971
  const md = [
93656
93972
  `- base_path: ${result.basePath}`,
93657
93973
  `- total: ${result.total}`,
93658
93974
  ...Array.isArray(result.items) ? result.items.map((it) => `- ${it.path}`) : []
93659
93975
  ].join(`
93660
93976
  `);
93661
- return writeSuccess({ data: result, md });
93662
- }), catchAll2(writeFailure)));
93977
+ yield* writeSuccess({ data: result, md });
93978
+ }).pipe(catchAll2(writeFailure)));
93663
93979
 
93664
93980
  // src/commands/read/db/recent.ts
93665
93981
  function optionToUndefined13(opt) {
@@ -94233,173 +94549,6 @@ var wechatOutlineCommand = exports_Command.make("outline", {
94233
94549
  // src/commands/write/wechat/index.ts
94234
94550
  var writeWechatCommand = exports_Command.make("wechat", {}).pipe(exports_Command.withSubcommands([wechatOutlineCommand]));
94235
94551
 
94236
- // src/services/HostApiClient.ts
94237
- function normalizeBaseUrl(baseUrl) {
94238
- return baseUrl.trim().replace(/\/+$/, "");
94239
- }
94240
- function apiTimeoutError(params3) {
94241
- return new CliError({
94242
- code: "API_TIMEOUT",
94243
- message: `API timeout after ${params3.timeoutMs}ms`,
94244
- exitCode: 1,
94245
- details: { base_url: params3.baseUrl, path: params3.path, timeout_ms: params3.timeoutMs }
94246
- });
94247
- }
94248
- function apiUnavailableError(params3) {
94249
- return new CliError({
94250
- code: "API_UNAVAILABLE",
94251
- message: String(params3.error?.message || params3.error || "API request failed"),
94252
- exitCode: 1,
94253
- details: { base_url: params3.baseUrl, path: params3.path }
94254
- });
94255
- }
94256
- function exitCodeFromRemoteCode(code2) {
94257
- return code2 === "INVALID_ARGS" ? 2 : 1;
94258
- }
94259
- function parseEnvelope(raw4) {
94260
- if (!raw4 || typeof raw4 !== "object") {
94261
- return { ok: false, error: { code: "INTERNAL", message: "Invalid API response envelope" } };
94262
- }
94263
- return raw4;
94264
- }
94265
- function buildQuery(params3) {
94266
- const sp = new URLSearchParams;
94267
- for (const [key, value8] of Object.entries(params3)) {
94268
- if (value8 === undefined || value8 === null)
94269
- continue;
94270
- if (typeof value8 === "string") {
94271
- if (!value8.trim())
94272
- continue;
94273
- sp.set(key, value8);
94274
- continue;
94275
- }
94276
- if (typeof value8 === "number" || typeof value8 === "boolean") {
94277
- sp.set(key, String(value8));
94278
- }
94279
- }
94280
- const query = sp.toString();
94281
- return query ? `?${query}` : "";
94282
- }
94283
- function requestJson(params3) {
94284
- const timeoutMs2 = Math.max(1, params3.timeoutMs ?? 15000);
94285
- const baseUrl = normalizeBaseUrl(params3.baseUrl);
94286
- const url2 = `${baseUrl}${params3.path}`;
94287
- return async((resume2) => {
94288
- const controller = new AbortController;
94289
- const timer2 = setTimeout(() => controller.abort(), timeoutMs2);
94290
- fetch(url2, {
94291
- method: params3.method,
94292
- headers: params3.method === "POST" ? { "content-type": "application/json" } : undefined,
94293
- body: params3.body === undefined ? undefined : JSON.stringify(params3.body),
94294
- signal: controller.signal
94295
- }).then(async (response) => {
94296
- clearTimeout(timer2);
94297
- let parsed;
94298
- try {
94299
- parsed = parseEnvelope(await response.json());
94300
- } catch (error4) {
94301
- resume2(fail8(new CliError({
94302
- code: "API_UNAVAILABLE",
94303
- message: "API returned a non-JSON response",
94304
- exitCode: 1,
94305
- details: { url: url2, status: response.status, error: String(error4?.message || error4) }
94306
- })));
94307
- return;
94308
- }
94309
- if (parsed.ok === true) {
94310
- resume2(succeed8(parsed.data));
94311
- return;
94312
- }
94313
- const code2 = typeof parsed.error?.code === "string" ? parsed.error.code : "INTERNAL";
94314
- const message2 = typeof parsed.error?.message === "string" ? parsed.error.message : "API request failed";
94315
- const hint = Array.isArray(parsed.hint) ? parsed.hint.map(String) : undefined;
94316
- resume2(fail8(new CliError({
94317
- code: code2,
94318
- message: message2,
94319
- exitCode: exitCodeFromRemoteCode(code2),
94320
- details: parsed.error?.details,
94321
- hint
94322
- })));
94323
- }).catch((error4) => {
94324
- clearTimeout(timer2);
94325
- if (error4?.name === "AbortError") {
94326
- resume2(fail8(apiTimeoutError({ baseUrl, path: params3.path, timeoutMs: timeoutMs2 })));
94327
- return;
94328
- }
94329
- resume2(fail8(apiUnavailableError({ baseUrl, path: params3.path, error: error4 })));
94330
- });
94331
- return sync3(() => {
94332
- clearTimeout(timer2);
94333
- controller.abort();
94334
- });
94335
- });
94336
- }
94337
-
94338
- class HostApiClient extends Tag2("HostApiClient")() {
94339
- }
94340
- var HostApiClientLive = succeed10(HostApiClient, {
94341
- health: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/health", method: "GET", timeoutMs: timeoutMs2 }),
94342
- status: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/status", method: "GET", timeoutMs: timeoutMs2 }),
94343
- uiContextSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94344
- baseUrl,
94345
- path: `/v1/plugin/ui-context/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94346
- method: "GET",
94347
- timeoutMs: timeoutMs2
94348
- }),
94349
- uiContextPage: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94350
- baseUrl,
94351
- path: `/v1/plugin/ui-context/page${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94352
- method: "GET",
94353
- timeoutMs: timeoutMs2
94354
- }),
94355
- uiContextFocusedRem: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94356
- baseUrl,
94357
- path: `/v1/plugin/ui-context/focused-rem${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94358
- method: "GET",
94359
- timeoutMs: timeoutMs2
94360
- }),
94361
- uiContextDescribe: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs: timeoutMs2 }) => requestJson({
94362
- baseUrl,
94363
- path: `/v1/plugin/ui-context/describe${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
94364
- method: "GET",
94365
- timeoutMs: timeoutMs2
94366
- }),
94367
- selectionSnapshot: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94368
- baseUrl,
94369
- path: `/v1/plugin/selection/snapshot${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94370
- method: "GET",
94371
- timeoutMs: timeoutMs2
94372
- }),
94373
- selectionRoots: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94374
- baseUrl,
94375
- path: `/v1/plugin/selection/roots${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94376
- method: "GET",
94377
- timeoutMs: timeoutMs2
94378
- }),
94379
- selectionCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, timeoutMs: timeoutMs2 }) => requestJson({
94380
- baseUrl,
94381
- path: `/v1/plugin/selection/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2 })}`,
94382
- method: "GET",
94383
- timeoutMs: timeoutMs2
94384
- }),
94385
- pluginCurrent: ({ baseUrl, stateFile: stateFile3, staleMs: staleMs2, selectionLimit, timeoutMs: timeoutMs2 }) => requestJson({
94386
- baseUrl,
94387
- path: `/v1/plugin/current${buildQuery({ stateFile: stateFile3, staleMs: staleMs2, selectionLimit })}`,
94388
- method: "GET",
94389
- timeoutMs: timeoutMs2
94390
- }),
94391
- selectionOutline: ({ baseUrl, body, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/plugin/selection/outline", method: "POST", body, timeoutMs: timeoutMs2 }),
94392
- uiContext: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/ui-context", method: "GET", timeoutMs: timeoutMs2 }),
94393
- selection: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/selection", method: "GET", timeoutMs: timeoutMs2 }),
94394
- searchDb: ({ baseUrl, ...body }) => requestJson({ baseUrl, path: "/v1/search/db", method: "POST", body }),
94395
- searchPlugin: ({ baseUrl, ...body }) => requestJson({ baseUrl, path: "/v1/search/plugin", method: "POST", body }),
94396
- writeOps: ({ baseUrl, body, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/write/ops", method: "POST", body, timeoutMs: timeoutMs2 }),
94397
- writeMarkdown: ({ baseUrl, body, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/write/markdown", method: "POST", body, timeoutMs: timeoutMs2 }),
94398
- queueWait: ({ baseUrl, txnId, timeoutMs: timeoutMs2, pollMs: pollMs2 }) => requestJson({ baseUrl, path: "/v1/queue/wait", method: "POST", body: { txnId, timeoutMs: timeoutMs2, pollMs: pollMs2 } }),
94399
- queueTxn: ({ baseUrl, txnId, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: `/v1/queue/txns/${encodeURIComponent(txnId)}`, method: "GET", timeoutMs: timeoutMs2 }),
94400
- triggerSync: ({ baseUrl, timeoutMs: timeoutMs2 }) => requestJson({ baseUrl, path: "/v1/actions/trigger-sync", method: "POST", timeoutMs: timeoutMs2 })
94401
- });
94402
-
94403
94552
  // src/commands/import/markdown.ts
94404
94553
  function optionToUndefined15(opt) {
94405
94554
  return isSome2(opt) ? opt.value : undefined;
@@ -95551,6 +95700,22 @@ function clampInt5(value8, min5, max7) {
95551
95700
  return min5;
95552
95701
  return Math.max(min5, Math.min(max7, Math.floor(value8)));
95553
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
+ }
95554
95719
  function executeDbSearchUseCase(params3) {
95555
95720
  return gen2(function* () {
95556
95721
  const cfg = yield* AppConfig;
@@ -95606,6 +95771,87 @@ function executePluginSearchUseCase(params3) {
95606
95771
  });
95607
95772
  });
95608
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
+ }
95609
95855
  function executeWriteOpsUseCase(params3) {
95610
95856
  return gen2(function* () {
95611
95857
  const parsed = yield* try_3({
@@ -96166,18 +96412,23 @@ function readJsonBody(req) {
96166
96412
  function runHttpApiRuntime(params3) {
96167
96413
  return gen2(function* () {
96168
96414
  const cfg = yield* AppConfig;
96415
+ const runtimeCfg = { ...cfg, apiBaseUrl: undefined };
96169
96416
  const apiFiles = yield* ApiDaemonFiles;
96417
+ const daemonFiles = yield* DaemonFiles;
96170
96418
  const ws = yield* WsClient;
96171
96419
  const queue = yield* Queue;
96172
96420
  const payload = yield* Payload;
96173
96421
  const refs = yield* RefResolver;
96174
96422
  const hostApi = yield* HostApiClient;
96175
96423
  const remDb = yield* RemDb;
96424
+ const processSvc = yield* Process;
96425
+ const supervisorState = yield* SupervisorState;
96426
+ const statusLine = yield* StatusLineController;
96176
96427
  const host3 = params3?.host ?? cfg.apiHost ?? "0.0.0.0";
96177
96428
  const configuredPort = params3?.port ?? cfg.apiPort ?? 3000;
96178
96429
  const stateFilePath = params3?.stateFile ?? cfg.apiStateFile ?? apiFiles.defaultStateFile();
96179
96430
  const startedAt = Date.now();
96180
- 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));
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));
96181
96432
  const server = createServer((req, res) => {
96182
96433
  const url2 = new URL(req.url || "/", `http://${req.headers.host || "localhost"}`);
96183
96434
  const method = req.method || "GET";
@@ -96285,6 +96536,13 @@ function runHttpApiRuntime(params3) {
96285
96536
  }));
96286
96537
  return;
96287
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
+ }
96288
96546
  if (method === "POST" && url2.pathname === "/v1/plugin/selection/outline") {
96289
96547
  (async () => {
96290
96548
  try {
@@ -96338,6 +96596,35 @@ function runHttpApiRuntime(params3) {
96338
96596
  })();
96339
96597
  return;
96340
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
+ }
96341
96628
  if (method === "POST" && url2.pathname === "/v1/search/plugin") {
96342
96629
  (async () => {
96343
96630
  try {
@@ -98366,6 +98653,10 @@ var readPowerupSchemaCommand = exports_Command.make("schema", { powerup, id: id2
98366
98653
  }));
98367
98654
  }
98368
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
+ });
98369
98660
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
98370
98661
  const tagId = resolved ? resolved.id : normalizeRemIdInput(id3);
98371
98662
  const payload2 = yield* tryPromise2({
@@ -98719,6 +99010,10 @@ var writePowerupApplyCommand = exports_Command.make("apply", {
98719
99010
  }));
98720
99011
  }
98721
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
+ });
98722
99017
  const payloadSvc = yield* Payload;
98723
99018
  const remId = normalizeRemIdInput(rem);
98724
99019
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
@@ -99320,6 +99615,10 @@ var writePowerupRecordAddCommand = exports_Command.make("add", {
99320
99615
  }));
99321
99616
  }
99322
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
+ });
99323
99622
  const refs = yield* RefResolver;
99324
99623
  const payloadSvc = yield* Payload;
99325
99624
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
@@ -99524,6 +99823,10 @@ var writePowerupRecordDeleteCommand = exports_Command.make("delete", {
99524
99823
  }));
99525
99824
  }
99526
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
+ });
99527
99830
  const payloadSvc = yield* Payload;
99528
99831
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
99529
99832
  const tableTagId = resolved ? resolved.id : normalizeRemIdInput(tagId);
@@ -99691,6 +99994,10 @@ var writePowerupRecordUpdateCommand = exports_Command.make("update", {
99691
99994
  }));
99692
99995
  }
99693
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
+ });
99694
100001
  const payloadSvc = yield* Payload;
99695
100002
  const resolved = powerup2 ? yield* resolvePowerup(powerup2) : null;
99696
100003
  const tableTagId = resolved ? resolved.id : normalizeRemIdInput(tagId);
@@ -100002,6 +100309,10 @@ var sort2 = choice5("sort", ["rank", "updatedAt", "createdAt"]).pipe(optional5,
100002
100309
  var sortDirection = choice5("sort-direction", ["asc", "desc"]).pipe(optional5, map34(optionToUndefined38));
100003
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* () {
100004
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
+ });
100005
100316
  const payloadSvc = yield* Payload;
100006
100317
  const queryObj = {};
100007
100318
  if (payload3) {
@@ -100300,6 +100611,10 @@ var readByReferenceCommand = exports_Command.make("by-reference", { reference, t
100300
100611
  return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Provide at least one Rem ID via --reference", exitCode: 2 }));
100301
100612
  }
100302
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
+ });
100303
100618
  const result = yield* tryPromise2({
100304
100619
  try: async () => await executeFindRemsByReference({
100305
100620
  targetIds: reference2,
@@ -100317,6 +100632,10 @@ var readByReferenceCommand = exports_Command.make("by-reference", { reference, t
100317
100632
  // src/commands/read/connections.ts
100318
100633
  var readConnectionsCommand = exports_Command.make("connections", { id: text9("id") }, ({ id: id3 }) => gen2(function* () {
100319
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
+ });
100320
100639
  const payload3 = yield* tryPromise2({
100321
100640
  try: async () => await executeGetRemConnections({ id: id3, dbPath: cfg.remnoteDb }),
100322
100641
  catch: (e) => cliErrorFromUnknown(e, { code: "DB_UNAVAILABLE" })
@@ -100335,6 +100654,10 @@ var readInspectCommand = exports_Command.make("inspect", {
100335
100654
  maxReferenceDepth
100336
100655
  }, ({ id: id3, expandReferences, maxReferenceDepth: maxReferenceDepth2 }) => gen2(function* () {
100337
100656
  const cfg = yield* AppConfig;
100657
+ yield* failInRemoteMode({
100658
+ command: "rem inspect",
100659
+ reason: "this command still inspects the local RemNote database directly"
100660
+ });
100338
100661
  const result = yield* tryPromise2({
100339
100662
  try: async () => await executeInspectRemDoc({
100340
100663
  id: id3,
@@ -100391,10 +100714,34 @@ var readOutlineCommand = exports_Command.make("outline", {
100391
100714
  detail
100392
100715
  }) => gen2(function* () {
100393
100716
  const cfg = yield* AppConfig;
100717
+ const hostApi = yield* HostApiClient;
100394
100718
  const refs = yield* RefResolver;
100395
100719
  if (id4 && ref4) {
100396
100720
  return yield* fail8(new CliError({ code: "INVALID_ARGS", message: "Choose only one of --id or --ref", exitCode: 2 }));
100397
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
+ }
100398
100745
  const link3 = ref4 ? tryParseRemnoteLinkFromRef(ref4) : undefined;
100399
100746
  const resolvedId = ref4 ? link3?.remId ?? (yield* refs.resolve(ref4)) : id4;
100400
100747
  if (!resolvedId) {
@@ -100430,6 +100777,10 @@ var id4 = text9("id").pipe(repeated5);
100430
100777
  var maxHops = integer7("max-hops").pipe(optional5, map34(optionToUndefined44));
100431
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* () {
100432
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
+ });
100433
100784
  const refs = yield* RefResolver;
100434
100785
  const hasRef = typeof ref5 === "string" && ref5.trim().length > 0;
100435
100786
  const hasIds = Array.isArray(id5) && id5.length > 0;
@@ -100492,6 +100843,10 @@ var readReferencesCommand = exports_Command.make("references", {
100492
100843
  inboundMaxDepth
100493
100844
  }, ({ id: id5, includeDescendants, maxDepth: maxDepth5, includeOccurrences, resolveText, includeInbound, inboundMaxDepth: inboundMaxDepth2 }) => gen2(function* () {
100494
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
+ });
100495
100850
  const payload3 = yield* tryPromise2({
100496
100851
  try: async () => {
100497
100852
  const { payload: payload4 } = await executeListRemReferences({
@@ -100524,6 +100879,10 @@ var readResolveRefCommand = exports_Command.make("resolve-ref", {
100524
100879
  detail: boolean8("detail")
100525
100880
  }, ({ ids: ids4, expandReferences, maxReferenceDepth: maxReferenceDepth3, detail }) => gen2(function* () {
100526
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
+ });
100527
100886
  const result = yield* tryPromise2({
100528
100887
  try: async () => await executeResolveRemReference({
100529
100888
  ids: ids4,
@@ -101200,6 +101559,10 @@ var remCommand = exports_Command.make("rem", {}).pipe(exports_Command.withSubcom
101200
101559
  function resolveReplaceTarget(params3) {
101201
101560
  return gen2(function* () {
101202
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
+ });
101203
101566
  const refs = yield* RefResolver;
101204
101567
  const hasSelection = params3.selection === true;
101205
101568
  const hasRef = typeof params3.ref === "string" && params3.ref.trim().length > 0;
@@ -101244,6 +101607,10 @@ function resolveReplaceTarget(params3) {
101244
101607
  function expandTargetIds(params3) {
101245
101608
  return gen2(function* () {
101246
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
+ });
101247
101614
  if (params3.scope === "roots") {
101248
101615
  const unique2 = Array.from(new Set(params3.rootIds));
101249
101616
  return {
@@ -102432,6 +102799,10 @@ var writeTableRecordAddCommand = exports_Command.make("add", {
102432
102799
  }));
102433
102800
  }
102434
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
+ });
102435
102806
  const refs = yield* RefResolver;
102436
102807
  const payloadSvc = yield* Payload;
102437
102808
  const resolvedRef = ref7 ?? "daily:today";
@@ -102610,6 +102981,10 @@ var writeTableRecordDeleteCommand = exports_Command.make("delete", {
102610
102981
  }));
102611
102982
  }
102612
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
+ });
102613
102988
  const payloadSvc = yield* Payload;
102614
102989
  if (!dryRun) {
102615
102990
  const inspected = yield* tryPromise2({
@@ -102739,6 +103114,10 @@ var writeTableRecordUpdateCommand = exports_Command.make("update", {
102739
103114
  }));
102740
103115
  }
102741
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
+ });
102742
103121
  const payloadSvc = yield* Payload;
102743
103122
  if (!dryRun) {
102744
103123
  const inspected = yield* tryPromise2({
@@ -102877,6 +103256,10 @@ var tableShowCommand = exports_Command.make("show", {
102877
103256
  offset: offset7
102878
103257
  }, ({ id: id5, includeOptions, limit: limit9, offset: offset8 }) => gen2(function* () {
102879
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
+ });
102880
103263
  const payload3 = yield* tryPromise2({
102881
103264
  try: async () => await executeReadRemTable({
102882
103265
  tagId: id5,
@@ -102975,6 +103358,10 @@ function makeTodosListCommand() {
102975
103358
  offset: offset9
102976
103359
  }) => gen2(function* () {
102977
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
+ });
102978
103365
  const payload3 = yield* tryPromise2({
102979
103366
  try: async () => await executeListTodos({
102980
103367
  dbPath: cfg.remnoteDb,
@@ -103111,6 +103498,10 @@ function todoWriteEffect(params3) {
103111
103498
  }));
103112
103499
  }
103113
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
+ });
103114
103505
  const payloadSvc = yield* Payload;
103115
103506
  const remId = normalizeRemIdInput(rem);
103116
103507
  const normalizedTagId = tagId2 ? normalizeRemIdInput(tagId2) : undefined;
@@ -103387,6 +103778,10 @@ var writePowerupTodoRemoveCommand = exports_Command.make("remove", {
103387
103778
  }));
103388
103779
  }
103389
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
+ });
103390
103785
  const payloadSvc = yield* Payload;
103391
103786
  const remId = normalizeRemIdInput(rem);
103392
103787
  const normalizedTagId = tagId2 ? normalizeRemIdInput(tagId2) : undefined;
@@ -103542,6 +103937,10 @@ var maxNodesPerResult = integer7("max-nodes").pipe(optional5, map34(optionToUnde
103542
103937
  var groupBy2 = choice5("group-by", ["none", "parent", "date"]).pipe(optional5, map34(optionToUndefined51));
103543
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* () {
103544
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
+ });
103545
103944
  const keywordList = keywords2 ? keywords2.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
103546
103945
  const queryText = query3?.trim() || undefined;
103547
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.0",
3
+ "version": "0.4.2",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "agent-remnote": "./cli.js"