chat-recall 0.5.21 → 0.5.23

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.
package/dist/watch.js CHANGED
@@ -14306,8 +14306,11 @@ function isInside(child, parent) {
14306
14306
  return c.startsWith(p);
14307
14307
  }
14308
14308
  function globMatch(pattern, path) {
14309
- const re = new RegExp("^" + globToRegex(pattern) + "$");
14310
- return re.test(path);
14309
+ const re = new RegExp("^" + globToRegex(toPosix(pattern)) + "$");
14310
+ return re.test(toPosix(path));
14311
+ }
14312
+ function toPosix(p) {
14313
+ return p.replace(/\\/g, "/");
14311
14314
  }
14312
14315
  function globToRegex(glob) {
14313
14316
  let out = "";
@@ -19210,7 +19213,7 @@ var init_http = __esm({
19210
19213
  CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
19211
19214
  } catch {
19212
19215
  try {
19213
- if (true) CLI_VERSION = "0.5.21";
19216
+ if (true) CLI_VERSION = "0.5.23";
19214
19217
  } catch {
19215
19218
  }
19216
19219
  }
@@ -19718,7 +19721,7 @@ var init_telemetry = __esm({
19718
19721
  init_sync_client();
19719
19722
  cliVersion = () => {
19720
19723
  try {
19721
- return true ? "0.5.21" : "dev";
19724
+ return true ? "0.5.23" : "dev";
19722
19725
  } catch {
19723
19726
  return "dev";
19724
19727
  }
@@ -19782,6 +19785,143 @@ var init_collector_health = __esm({
19782
19785
  }
19783
19786
  });
19784
19787
 
19788
+ // src/server-probe.ts
19789
+ var server_probe_exports = {};
19790
+ __export(server_probe_exports, {
19791
+ classifyUnreachable: () => classifyUnreachable,
19792
+ describeCause: () => describeCause,
19793
+ describeUnreachable: () => describeUnreachable,
19794
+ probeAdvice: () => probeAdvice,
19795
+ probeOk: () => probeOk,
19796
+ probeServer: () => probeServer
19797
+ });
19798
+ function probeOk(r) {
19799
+ return r.kind === "ok" && r.apiVersion >= 2;
19800
+ }
19801
+ async function probeServer(base2, opts = {}) {
19802
+ const f = opts.fetchImpl || fetch;
19803
+ let res;
19804
+ try {
19805
+ res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
19806
+ signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
19807
+ });
19808
+ } catch (err) {
19809
+ return {
19810
+ kind: "unreachable",
19811
+ error: describeCause(err),
19812
+ reason: classifyUnreachable(err)
19813
+ };
19814
+ }
19815
+ if (res.status === 401 || res.status === 403) return { kind: "unauthorized", status: res.status };
19816
+ if (res.status === 404 || res.status === 410) return { kind: "moved", status: res.status };
19817
+ if (res.status >= 500) return { kind: "server_error", status: res.status };
19818
+ if (!res.ok) return { kind: "moved", status: res.status };
19819
+ let body;
19820
+ try {
19821
+ body = await res.text();
19822
+ } catch (err) {
19823
+ return { kind: "unreachable", error: describeCause(err), reason: classifyUnreachable(err) };
19824
+ }
19825
+ let parsed;
19826
+ try {
19827
+ parsed = JSON.parse(body);
19828
+ } catch {
19829
+ return { kind: "not_api", status: res.status, snippet: body.trim().slice(0, 60) };
19830
+ }
19831
+ if (typeof parsed?.apiVersion !== "number") {
19832
+ return { kind: "not_api", status: res.status, snippet: body.trim().slice(0, 60) };
19833
+ }
19834
+ return {
19835
+ kind: "ok",
19836
+ apiVersion: parsed.apiVersion,
19837
+ edition: parsed.edition,
19838
+ cliVersion: parsed.cli?.version,
19839
+ raw: parsed
19840
+ };
19841
+ }
19842
+ function probeAdvice(r, base2) {
19843
+ switch (r.kind) {
19844
+ case "ok":
19845
+ return r.apiVersion >= 2 ? `apiVersion ${r.apiVersion}${r.edition ? `, edition ${r.edition}` : ""}` : `apiVersion ${r.apiVersion} is too old for this CLI \u2014 upgrade the server`;
19846
+ case "moved":
19847
+ return `HTTP ${r.status} \u2014 nothing is served at ${base2}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
19848
+ case "unauthorized":
19849
+ return `HTTP ${r.status} \u2014 ${base2} rejected the credential. Re-login: \`chat-recall login ` + base2 + "`";
19850
+ case "server_error":
19851
+ return `HTTP ${r.status} \u2014 ${base2} is up but failing. Nothing to fix locally; check the server.`;
19852
+ case "not_api":
19853
+ return `${base2} answered ${r.status} with something that is not the chat-recall API (${JSON.stringify(r.snippet)}) \u2014 check the URL, a proxy or a captive portal`;
19854
+ case "unreachable":
19855
+ switch (r.reason) {
19856
+ case "dns":
19857
+ return `cannot resolve the host in ${base2} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
19858
+ case "refused":
19859
+ return `${base2} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
19860
+ case "tls":
19861
+ return `the TLS certificate at ${base2} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
19862
+ case "timeout":
19863
+ return `${base2} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
19864
+ case "reset":
19865
+ return `the connection to ${base2} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
19866
+ case "bad_port":
19867
+ return `${base2} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
19868
+ default:
19869
+ return `no HTTP response from ${base2} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
19870
+ }
19871
+ }
19872
+ }
19873
+ function classifyUnreachable(err) {
19874
+ if (err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError")) return "timeout";
19875
+ for (const e of walkErrorChain(err)) {
19876
+ const code = String(e.code ?? "");
19877
+ const msg = String(e.message ?? "");
19878
+ if (code === "ENOTFOUND" || code === "EAI_AGAIN") return "dns";
19879
+ if (code === "ECONNREFUSED") return "refused";
19880
+ if (code === "ECONNRESET" || code === "EPIPE") return "reset";
19881
+ if (code === "ETIMEDOUT" || code === "UND_ERR_CONNECT_TIMEOUT" || code === "UND_ERR_HEADERS_TIMEOUT") return "timeout";
19882
+ if (code.startsWith("CERT_") || code.startsWith("ERR_TLS") || code === "DEPTH_ZERO_SELF_SIGNED_CERT" || code === "SELF_SIGNED_CERT_IN_CHAIN" || code === "UNABLE_TO_VERIFY_LEAF_SIGNATURE" || /certificate/i.test(msg)) return "tls";
19883
+ if (/^bad port$/i.test(msg)) return "bad_port";
19884
+ }
19885
+ return "unknown";
19886
+ }
19887
+ function* walkErrorChain(err, depth = 0) {
19888
+ if (!err || typeof err !== "object" || depth > 5) return;
19889
+ yield err;
19890
+ const members = err.errors;
19891
+ if (Array.isArray(members)) {
19892
+ for (const m of members) yield* walkErrorChain(m, depth + 1);
19893
+ }
19894
+ yield* walkErrorChain(err.cause, depth + 1);
19895
+ }
19896
+ function describeCause(err) {
19897
+ const parts = [];
19898
+ for (const e of walkErrorChain(err)) {
19899
+ const code = e.code;
19900
+ if (typeof code === "string" && code && !parts.includes(code)) parts.push(code);
19901
+ }
19902
+ const base2 = err instanceof Error ? err.message : String(err);
19903
+ return parts.length ? `${base2}: ${parts.join(" \u2192 ")}` : base2;
19904
+ }
19905
+ function describeUnreachable(err) {
19906
+ const reason = classifyUnreachable(err);
19907
+ const detail = describeCause(err);
19908
+ const phrase = {
19909
+ dns: "the host name does not resolve",
19910
+ refused: "the connection was refused \u2014 nothing is listening there",
19911
+ tls: "the TLS certificate was rejected",
19912
+ timeout: "no answer before the timeout",
19913
+ reset: "the connection was cut mid-request",
19914
+ bad_port: "that port is one Node and every browser refuse to open",
19915
+ unknown: "no HTTP response"
19916
+ };
19917
+ return `${phrase[reason]} (${detail})`;
19918
+ }
19919
+ var init_server_probe = __esm({
19920
+ "src/server-probe.ts"() {
19921
+ "use strict";
19922
+ }
19923
+ });
19924
+
19785
19925
  // src/client-events.ts
19786
19926
  var client_events_exports = {};
19787
19927
  __export(client_events_exports, {
@@ -20143,6 +20283,7 @@ async function fetchTenantSyncConfig(cred) {
20143
20283
  persistSyncConfig(base2, config);
20144
20284
  return config;
20145
20285
  } catch (err) {
20286
+ if (isSyncRulesRefusal(err)) throw err;
20146
20287
  return lastKnownSyncConfig(base2, err instanceof Error ? err.message : "request failed");
20147
20288
  }
20148
20289
  }
@@ -20152,9 +20293,14 @@ function lastKnownSyncConfig(base2, reason) {
20152
20293
  console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
20153
20294
  return remembered.config;
20154
20295
  }
20155
- throw new Error(
20296
+ const refusal = new Error(
20156
20297
  `Cannot read the server-side sync rules from ${base2} (${reason}), and this machine has never successfully read them. Refusing to sync: uploading without knowing your exclusions could ship a project you told the dashboard to hold back. Fix the server or retry.`
20157
20298
  );
20299
+ refusal[SYNC_RULES_REFUSAL] = true;
20300
+ throw refusal;
20301
+ }
20302
+ function isSyncRulesRefusal(err) {
20303
+ return !!err && typeof err === "object" && err[SYNC_RULES_REFUSAL] === true;
20158
20304
  }
20159
20305
  function deviceLabel() {
20160
20306
  try {
@@ -20378,7 +20524,12 @@ async function verifyServerApi(serverUrl, minApi) {
20378
20524
  const base2 = serverUrl.replace(/\/$/, "");
20379
20525
  const seen = capsOk.get(base2);
20380
20526
  if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
20381
- const caps = await fetchWithTimeout(`${base2}/api/capabilities`).then((r) => r.json());
20527
+ const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
20528
+ const probe = await probeServer2(base2, {
20529
+ fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
20530
+ });
20531
+ if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base2));
20532
+ const caps = probe.raw;
20382
20533
  if ((caps.apiVersion ?? 0) < minApi) {
20383
20534
  throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
20384
20535
  }
@@ -21368,7 +21519,7 @@ async function syncIncremental(opts = {}) {
21368
21519
  lock.release();
21369
21520
  }
21370
21521
  }
21371
- var ownVersion, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
21522
+ var ownVersion, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, SYNC_RULES_REFUSAL, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
21372
21523
  var init_sync_client = __esm({
21373
21524
  "src/sync-client.ts"() {
21374
21525
  "use strict";
@@ -21414,7 +21565,7 @@ var init_sync_client = __esm({
21414
21565
  ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
21415
21566
  } catch {
21416
21567
  try {
21417
- if (true) ownVersion = "0.5.21";
21568
+ if (true) ownVersion = "0.5.23";
21418
21569
  } catch {
21419
21570
  }
21420
21571
  }
@@ -21425,6 +21576,7 @@ var init_sync_client = __esm({
21425
21576
  SECURITY_CONFIG_TTL_MS = 5 * 60 * 1e3;
21426
21577
  _syncConfigCache = /* @__PURE__ */ new Map();
21427
21578
  EMPTY_SYNC_CONFIG = { excludeTools: [], excludeProjects: [], excludeSources: [], approveSources: [] };
21579
+ SYNC_RULES_REFUSAL = /* @__PURE__ */ Symbol.for("chat-recall.syncRulesRefusal");
21428
21580
  hashPath = (p) => p ? "p_" + createHash12("sha256").update(p).digest("hex").slice(0, 12) : "";
21429
21581
  MAX_DERIVED_ROW_BYTES = 2 * 1024 * 1024;
21430
21582
  isLocalHost = isPrivateHost;
@@ -22012,6 +22164,65 @@ var init_toolkit_sync = __esm({
22012
22164
  }
22013
22165
  });
22014
22166
 
22167
+ // ../engine/dist/core/which.js
22168
+ import { existsSync as existsSync45, statSync as statSync40, accessSync, constants } from "node:fs";
22169
+ import { join as join48, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep2 } from "node:path";
22170
+ function executable(p) {
22171
+ try {
22172
+ if (!statSync40(p).isFile())
22173
+ return false;
22174
+ } catch {
22175
+ return false;
22176
+ }
22177
+ if (isWindows)
22178
+ return true;
22179
+ try {
22180
+ accessSync(p, constants.X_OK);
22181
+ return true;
22182
+ } catch {
22183
+ return false;
22184
+ }
22185
+ }
22186
+ function candidates(name) {
22187
+ if (!isWindows)
22188
+ return [name];
22189
+ const exts = (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
22190
+ if (exts.some((e) => name.toLowerCase().endsWith(e.toLowerCase())))
22191
+ return [name];
22192
+ return exts.map((e) => name + e);
22193
+ }
22194
+ function resolveOnPath(name) {
22195
+ if (!name)
22196
+ return null;
22197
+ if (name.includes("/") || isWindows && name.includes(sep2) || isAbsolute2(name)) {
22198
+ for (const c of candidates(name))
22199
+ if (executable(c))
22200
+ return c;
22201
+ return null;
22202
+ }
22203
+ for (const raw of (process.env.PATH || "").split(delimiter2)) {
22204
+ const dir = raw.replace(/^"(.*)"$/, "$1");
22205
+ if (!dir)
22206
+ continue;
22207
+ for (const c of candidates(name)) {
22208
+ const full = join48(dir, c);
22209
+ if (existsSync45(full) && executable(full))
22210
+ return full;
22211
+ }
22212
+ }
22213
+ return null;
22214
+ }
22215
+ function isOnPath(name) {
22216
+ return resolveOnPath(name) !== null;
22217
+ }
22218
+ var isWindows;
22219
+ var init_which = __esm({
22220
+ "../engine/dist/core/which.js"() {
22221
+ "use strict";
22222
+ isWindows = process.platform === "win32";
22223
+ }
22224
+ });
22225
+
22015
22226
  // ../engine/dist/core/toolkit-pull.js
22016
22227
  var toolkit_pull_exports = {};
22017
22228
  __export(toolkit_pull_exports, {
@@ -22020,26 +22231,20 @@ __export(toolkit_pull_exports, {
22020
22231
  planPull: () => planPull,
22021
22232
  portableCommand: () => portableCommand
22022
22233
  });
22023
- import { existsSync as existsSync45, mkdirSync as mkdirSync12, statSync as statSync40, writeFileSync as writeFileSync12 } from "node:fs";
22024
- import { delimiter as delimiter2, dirname as dirname22, join as join48, basename as basename24, isAbsolute as isAbsolute2 } from "node:path";
22234
+ import { existsSync as existsSync46, mkdirSync as mkdirSync12, statSync as statSync41, writeFileSync as writeFileSync12 } from "node:fs";
22235
+ import { dirname as dirname22, join as join49, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
22025
22236
  function isExecutableFile(p) {
22026
22237
  try {
22027
- return statSync40(p).isFile();
22238
+ return statSync41(p).isFile();
22028
22239
  } catch {
22029
22240
  return false;
22030
22241
  }
22031
22242
  }
22032
22243
  function onPath(name) {
22033
- const dirs = (process.env.PATH || "").split(delimiter2).filter(Boolean);
22034
- for (const d of dirs) {
22035
- const candidate = join48(d, name);
22036
- if (isExecutableFile(candidate))
22037
- return candidate;
22038
- }
22039
- return null;
22244
+ return resolveOnPath(name);
22040
22245
  }
22041
22246
  function portableCommand(cmd) {
22042
- if (!isAbsolute2(cmd)) {
22247
+ if (!isAbsolute3(cmd)) {
22043
22248
  return onPath(cmd) ? { command: cmd, rewritten: false } : { missing: cmd };
22044
22249
  }
22045
22250
  if (isExecutableFile(cmd))
@@ -22177,9 +22382,9 @@ function executePull(rows, opts = {}) {
22177
22382
  const outcomes = [];
22178
22383
  for (const { name, body, truncated, redacted, tools } of skills) {
22179
22384
  for (const tool of tools) {
22180
- const dir = join48(skillsDirFor(tool), name);
22181
- const file = join48(dir, "SKILL.md");
22182
- if (existsSync45(file)) {
22385
+ const dir = join49(skillsDirFor(tool), name);
22386
+ const file = join49(dir, "SKILL.md");
22387
+ if (existsSync46(file)) {
22183
22388
  outcomes.push({ type: "skill", name, tool, status: "present" });
22184
22389
  continue;
22185
22390
  }
@@ -22224,7 +22429,7 @@ function executePull(rows, opts = {}) {
22224
22429
  outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "emit failed" });
22225
22430
  continue;
22226
22431
  }
22227
- if (existsSync45(out.path)) {
22432
+ if (existsSync46(out.path)) {
22228
22433
  outcomes.push({ type, name, tool, status: "present" });
22229
22434
  continue;
22230
22435
  }
@@ -22298,6 +22503,7 @@ var NOT_REBUILDABLE;
22298
22503
  var init_toolkit_pull = __esm({
22299
22504
  "../engine/dist/core/toolkit-pull.js"() {
22300
22505
  "use strict";
22506
+ init_which();
22301
22507
  init_toolkit_sync();
22302
22508
  init_artifact_codec();
22303
22509
  NOT_REBUILDABLE = {
@@ -22523,8 +22729,8 @@ __export(shadow_prune_exports, {
22523
22729
  DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
22524
22730
  pruneShadow: () => pruneShadow
22525
22731
  });
22526
- import { readdirSync as readdirSync33, statSync as statSync42, unlinkSync as unlinkSync3 } from "fs";
22527
- import { join as join51 } from "path";
22732
+ import { readdirSync as readdirSync33, statSync as statSync43, unlinkSync as unlinkSync3 } from "fs";
22733
+ import { join as join52 } from "path";
22528
22734
  function listShadows(isFullyAcked) {
22529
22735
  const out = [];
22530
22736
  const root = shadowRoot();
@@ -22535,7 +22741,7 @@ function listShadows(isFullyAcked) {
22535
22741
  return out;
22536
22742
  }
22537
22743
  for (const tool of tools) {
22538
- const dir = join51(root, tool);
22744
+ const dir = join52(root, tool);
22539
22745
  let names;
22540
22746
  try {
22541
22747
  names = readdirSync33(dir);
@@ -22545,10 +22751,10 @@ function listShadows(isFullyAcked) {
22545
22751
  for (const name of names) {
22546
22752
  if (!name.endsWith(".gz"))
22547
22753
  continue;
22548
- const path = join51(dir, name);
22754
+ const path = join52(dir, name);
22549
22755
  let st;
22550
22756
  try {
22551
- st = statSync42(path);
22757
+ st = statSync43(path);
22552
22758
  } catch {
22553
22759
  continue;
22554
22760
  }
@@ -22662,65 +22868,6 @@ var init_code_intel = __esm({
22662
22868
  }
22663
22869
  });
22664
22870
 
22665
- // ../engine/dist/core/which.js
22666
- import { existsSync as existsSync48, statSync as statSync43, accessSync, constants } from "node:fs";
22667
- import { join as join52, isAbsolute as isAbsolute3, delimiter as delimiter3, sep as sep2 } from "node:path";
22668
- function executable(p) {
22669
- try {
22670
- if (!statSync43(p).isFile())
22671
- return false;
22672
- } catch {
22673
- return false;
22674
- }
22675
- if (isWindows)
22676
- return true;
22677
- try {
22678
- accessSync(p, constants.X_OK);
22679
- return true;
22680
- } catch {
22681
- return false;
22682
- }
22683
- }
22684
- function candidates(name) {
22685
- if (!isWindows)
22686
- return [name];
22687
- const exts = (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
22688
- if (exts.some((e) => name.toLowerCase().endsWith(e.toLowerCase())))
22689
- return [name];
22690
- return exts.map((e) => name + e);
22691
- }
22692
- function resolveOnPath(name) {
22693
- if (!name)
22694
- return null;
22695
- if (name.includes("/") || isWindows && name.includes(sep2) || isAbsolute3(name)) {
22696
- for (const c of candidates(name))
22697
- if (executable(c))
22698
- return c;
22699
- return null;
22700
- }
22701
- for (const raw of (process.env.PATH || "").split(delimiter3)) {
22702
- const dir = raw.replace(/^"(.*)"$/, "$1");
22703
- if (!dir)
22704
- continue;
22705
- for (const c of candidates(name)) {
22706
- const full = join52(dir, c);
22707
- if (existsSync48(full) && executable(full))
22708
- return full;
22709
- }
22710
- }
22711
- return null;
22712
- }
22713
- function isOnPath(name) {
22714
- return resolveOnPath(name) !== null;
22715
- }
22716
- var isWindows;
22717
- var init_which = __esm({
22718
- "../engine/dist/core/which.js"() {
22719
- "use strict";
22720
- isWindows = process.platform === "win32";
22721
- }
22722
- });
22723
-
22724
22871
  // ../engine/dist/core/companions.js
22725
22872
  import { existsSync as existsSync49, mkdirSync as mkdirSync15, statSync as statSync44, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync44, writeFileSync as writeFileSync15 } from "node:fs";
22726
22873
  import { homedir as homedir19 } from "node:os";
@@ -23929,8 +24076,8 @@ import { homedir as homedir20 } from "os";
23929
24076
  init_http();
23930
24077
  init_sync_client();
23931
24078
  init_toolkit_sync();
23932
- import { existsSync as existsSync46, readFileSync as readFileSync41, writeFileSync as writeFileSync13, appendFileSync, mkdirSync as mkdirSync13 } from "node:fs";
23933
- import { join as join49 } from "node:path";
24079
+ import { existsSync as existsSync47, readFileSync as readFileSync41, writeFileSync as writeFileSync13, appendFileSync, mkdirSync as mkdirSync13 } from "node:fs";
24080
+ import { join as join50 } from "node:path";
23934
24081
  import { homedir as homedir18 } from "node:os";
23935
24082
 
23936
24083
  // src/project-tasks.ts
@@ -24090,7 +24237,7 @@ function applyCodeRecommendation(intent) {
24090
24237
  const meta = JSON.parse(intent.name || "{}");
24091
24238
  if (intent.artifact_type === "write_tasks_file") {
24092
24239
  if (!meta.rootPath || !meta.content) return { status: "error", result: JSON.stringify({ error: "missing rootPath or content" }) };
24093
- const file = join49(meta.rootPath, meta.filename || "CODE_TASKS.md");
24240
+ const file = join50(meta.rootPath, meta.filename || "CODE_TASKS.md");
24094
24241
  writeFileSync13(file, meta.content);
24095
24242
  return { status: "done", result: JSON.stringify({ wrote: file }) };
24096
24243
  }
@@ -24100,17 +24247,17 @@ function applyCodeRecommendation(intent) {
24100
24247
  if (!text) return { status: "error", result: JSON.stringify({ error: "missing text" }) };
24101
24248
  let file;
24102
24249
  if (isGlobal) {
24103
- const dir = join49(homedir18(), ".claude");
24250
+ const dir = join50(homedir18(), ".claude");
24104
24251
  try {
24105
24252
  mkdirSync13(dir, { recursive: true });
24106
24253
  } catch {
24107
24254
  }
24108
- file = join49(dir, "CLAUDE.md");
24255
+ file = join50(dir, "CLAUDE.md");
24109
24256
  } else {
24110
24257
  if (!meta.rootPath) return { status: "error", result: JSON.stringify({ error: "missing rootPath" }) };
24111
- file = join49(meta.rootPath, "CLAUDE.md");
24258
+ file = join50(meta.rootPath, "CLAUDE.md");
24112
24259
  }
24113
- const existing = existsSync46(file) ? readFileSync41(file, "utf8") : "";
24260
+ const existing = existsSync47(file) ? readFileSync41(file, "utf8") : "";
24114
24261
  if (existing.includes(text)) return { status: "done", result: JSON.stringify({ skipped: "rule already present", file }) };
24115
24262
  const block = `${existing && !existing.endsWith("\n") ? "\n" : ""}
24116
24263
  ## Rule (added by chat-recall recommendation)
@@ -24204,10 +24351,10 @@ async function runIntent(intent, ctx) {
24204
24351
  var ownVersion2 = "0.0.0";
24205
24352
  try {
24206
24353
  const dir = dirname23(fileURLToPath4(import.meta.url));
24207
- ownVersion2 = JSON.parse(readFileSync41(join49(dir, "../package.json"), "utf-8")).version || ownVersion2;
24354
+ ownVersion2 = JSON.parse(readFileSync41(join50(dir, "../package.json"), "utf-8")).version || ownVersion2;
24208
24355
  } catch {
24209
24356
  try {
24210
- if (true) ownVersion2 = "0.5.21";
24357
+ if (true) ownVersion2 = "0.5.23";
24211
24358
  } catch {
24212
24359
  }
24213
24360
  }
@@ -24272,8 +24419,8 @@ init_auto_update();
24272
24419
  // src/code-index-cursor.ts
24273
24420
  init_paths();
24274
24421
  import { readFileSync as readFileSync42, writeFileSync as writeFileSync14, mkdirSync as mkdirSync14 } from "fs";
24275
- import { join as join50, dirname as dirname24 } from "path";
24276
- var cursorPath = () => join50(getDataDir(), "code-index-cursor.json");
24422
+ import { join as join51, dirname as dirname24 } from "path";
24423
+ var cursorPath = () => join51(getDataDir(), "code-index-cursor.json");
24277
24424
  function readCursor() {
24278
24425
  try {
24279
24426
  const raw = JSON.parse(readFileSync42(cursorPath(), "utf-8"));
@@ -24491,11 +24638,11 @@ function checkSelfRestart(opts) {
24491
24638
  }
24492
24639
 
24493
24640
  // src/log-rotate.ts
24494
- import { statSync as statSync41, copyFileSync as copyFileSync3, truncateSync } from "fs";
24641
+ import { statSync as statSync42, copyFileSync as copyFileSync3, truncateSync } from "fs";
24495
24642
  var LOG_MAX_BYTES = 32 * 1024 * 1024;
24496
24643
  function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24497
24644
  try {
24498
- const size = statSync41(logPath).size;
24645
+ const size = statSync42(logPath).size;
24499
24646
  if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
24500
24647
  copyFileSync3(logPath, `${logPath}.1`);
24501
24648
  truncateSync(logPath, 0);
@@ -24507,8 +24654,8 @@ function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24507
24654
 
24508
24655
  // src/collector-migrate.ts
24509
24656
  init_http();
24510
- import { existsSync as existsSync47 } from "node:fs";
24511
- function selectProjectsToReindex(projects, current, existsFn = existsSync47) {
24657
+ import { existsSync as existsSync48 } from "node:fs";
24658
+ function selectProjectsToReindex(projects, current, existsFn = existsSync48) {
24512
24659
  const reindex = [];
24513
24660
  const missing = [];
24514
24661
  for (const p of projects) {
@@ -24551,7 +24698,7 @@ async function runCollectorMigration(opts) {
24551
24698
  init_sync_ledger();
24552
24699
  init_collector_health();
24553
24700
  import { existsSync as existsSync50, readFileSync as readFileSync46 } from "fs";
24554
- var CLI_VERSION3 = true ? "0.5.21" : "0.0.0";
24701
+ var CLI_VERSION3 = true ? "0.5.23" : "0.0.0";
24555
24702
  var DEBOUNCE_MS = 5e3;
24556
24703
  var CLAUDE_DIR = claudeBackend.projectsDir();
24557
24704
  var PLANS_DIR = claudeBackend.plansDir();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chat-recall",
3
- "version": "0.5.21",
3
+ "version": "0.5.23",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/munhq/chat-recall.git"
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/munhq/chat-recall/issues"
11
11
  },
12
- "description": "One memory across every AI coding tool \u2014 indexes Claude Code, Gemini CLI, Codex, OpenCode, Antigravity and Cursor sessions, redacts secrets, and exposes them to your agent over MCP.",
12
+ "description": "One memory across every AI coding tool — indexes Claude Code, Gemini CLI, Codex, OpenCode, Antigravity and Cursor sessions, redacts secrets, and exposes them to your agent over MCP.",
13
13
  "keywords": [
14
14
  "mcp",
15
15
  "mcp-server",