chat-recall 0.5.22 → 0.5.24

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
@@ -7266,7 +7266,7 @@ async function archiveRawSession(store, sessionId) {
7266
7266
  }
7267
7267
  function detectForkPredecessor(sessionPath) {
7268
7268
  const { readFileSync: readFileSync47, readdirSync: readdirSync34 } = requireFs();
7269
- const { dirname: dirname26, join: join56, basename: basename27 } = requirePath();
7269
+ const { dirname: dirname26, join: join56, basename: basename28 } = requirePath();
7270
7270
  let text;
7271
7271
  try {
7272
7272
  text = readFileSync47(sessionPath, "utf-8");
@@ -7292,7 +7292,7 @@ function detectForkPredecessor(sessionPath) {
7292
7292
  if (text.includes(`"uuid":"${headParent}"`))
7293
7293
  return null;
7294
7294
  const dir = dirname26(sessionPath);
7295
- const self = basename27(sessionPath);
7295
+ const self = basename28(sessionPath);
7296
7296
  let entries;
7297
7297
  try {
7298
7298
  entries = readdirSync34(dir);
@@ -7304,7 +7304,7 @@ function detectForkPredecessor(sessionPath) {
7304
7304
  continue;
7305
7305
  try {
7306
7306
  if (readFileSync47(join56(dir, f), "utf-8").includes(`"uuid":"${headParent}"`)) {
7307
- return basename27(f, ".jsonl");
7307
+ return basename28(f, ".jsonl");
7308
7308
  }
7309
7309
  } catch {
7310
7310
  }
@@ -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.22";
19216
+ if (true) CLI_VERSION = "0.5.24";
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.22" : "dev";
19724
+ return true ? "0.5.24" : "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.22";
21568
+ if (true) ownVersion = "0.5.24";
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;
@@ -21440,7 +21592,7 @@ var init_sync_client = __esm({
21440
21592
 
21441
21593
  // ../engine/dist/core/artifact-codec.js
21442
21594
  import { readFileSync as readFileSync38 } from "fs";
21443
- import { join as join45 } from "path";
21595
+ import { basename as basename23, join as join45 } from "path";
21444
21596
  import { homedir as homedir15 } from "os";
21445
21597
  function parseCommandText(content, format, fallbackName) {
21446
21598
  if (format === "toml") {
@@ -21568,8 +21720,7 @@ function emit(type, art, toTool, projectPath) {
21568
21720
  };
21569
21721
  }
21570
21722
  function base(filePath) {
21571
- const b = filePath.split("/").pop() || filePath;
21572
- return b.replace(/\.(md|toml)$/, "");
21723
+ return basename23(filePath).replace(/\.(md|toml)$/, "");
21573
21724
  }
21574
21725
  var init_artifact_codec = __esm({
21575
21726
  "../engine/dist/core/artifact-codec.js"() {
@@ -21586,7 +21737,7 @@ var init_artifact_codec = __esm({
21586
21737
 
21587
21738
  // ../engine/dist/core/toolkit-sync.js
21588
21739
  import { existsSync as existsSync43, mkdirSync as mkdirSync10, readFileSync as readFileSync39, writeFileSync as writeFileSync10, cpSync } from "fs";
21589
- import { dirname as dirname20, join as join46, basename as basename23 } from "path";
21740
+ import { dirname as dirname20, join as join46, basename as basename24 } from "path";
21590
21741
  import { homedir as homedir16 } from "os";
21591
21742
  function rowFromMemoryItem(type, item) {
21592
21743
  const extra = item.extra || {};
@@ -21623,7 +21774,7 @@ function copySkill(row, toTool) {
21623
21774
  const skillDir = row.extra.skillDir || dirname20(row.filePath);
21624
21775
  if (!existsSync43(skillDir))
21625
21776
  return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
21626
- const name = row.extra.skillName || basename23(skillDir);
21777
+ const name = row.extra.skillName || basename24(skillDir);
21627
21778
  const targetDir = join46(skillsDirFor(toTool), name);
21628
21779
  if (existsSync43(targetDir))
21629
21780
  return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
@@ -22012,6 +22163,65 @@ var init_toolkit_sync = __esm({
22012
22163
  }
22013
22164
  });
22014
22165
 
22166
+ // ../engine/dist/core/which.js
22167
+ import { existsSync as existsSync45, statSync as statSync40, accessSync, constants } from "node:fs";
22168
+ import { join as join48, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep2 } from "node:path";
22169
+ function executable(p) {
22170
+ try {
22171
+ if (!statSync40(p).isFile())
22172
+ return false;
22173
+ } catch {
22174
+ return false;
22175
+ }
22176
+ if (isWindows)
22177
+ return true;
22178
+ try {
22179
+ accessSync(p, constants.X_OK);
22180
+ return true;
22181
+ } catch {
22182
+ return false;
22183
+ }
22184
+ }
22185
+ function candidates(name) {
22186
+ if (!isWindows)
22187
+ return [name];
22188
+ const exts = (process.env.PATHEXT || ".COM;.EXE;.BAT;.CMD").split(";").map((e) => e.trim()).filter(Boolean);
22189
+ if (exts.some((e) => name.toLowerCase().endsWith(e.toLowerCase())))
22190
+ return [name];
22191
+ return exts.map((e) => name + e);
22192
+ }
22193
+ function resolveOnPath(name) {
22194
+ if (!name)
22195
+ return null;
22196
+ if (name.includes("/") || isWindows && name.includes(sep2) || isAbsolute2(name)) {
22197
+ for (const c of candidates(name))
22198
+ if (executable(c))
22199
+ return c;
22200
+ return null;
22201
+ }
22202
+ for (const raw of (process.env.PATH || "").split(delimiter2)) {
22203
+ const dir = raw.replace(/^"(.*)"$/, "$1");
22204
+ if (!dir)
22205
+ continue;
22206
+ for (const c of candidates(name)) {
22207
+ const full = join48(dir, c);
22208
+ if (existsSync45(full) && executable(full))
22209
+ return full;
22210
+ }
22211
+ }
22212
+ return null;
22213
+ }
22214
+ function isOnPath(name) {
22215
+ return resolveOnPath(name) !== null;
22216
+ }
22217
+ var isWindows;
22218
+ var init_which = __esm({
22219
+ "../engine/dist/core/which.js"() {
22220
+ "use strict";
22221
+ isWindows = process.platform === "win32";
22222
+ }
22223
+ });
22224
+
22015
22225
  // ../engine/dist/core/toolkit-pull.js
22016
22226
  var toolkit_pull_exports = {};
22017
22227
  __export(toolkit_pull_exports, {
@@ -22020,31 +22230,25 @@ __export(toolkit_pull_exports, {
22020
22230
  planPull: () => planPull,
22021
22231
  portableCommand: () => portableCommand
22022
22232
  });
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";
22233
+ import { existsSync as existsSync46, mkdirSync as mkdirSync12, statSync as statSync41, writeFileSync as writeFileSync12 } from "node:fs";
22234
+ import { dirname as dirname22, join as join49, basename as basename25, isAbsolute as isAbsolute3 } from "node:path";
22025
22235
  function isExecutableFile(p) {
22026
22236
  try {
22027
- return statSync40(p).isFile();
22237
+ return statSync41(p).isFile();
22028
22238
  } catch {
22029
22239
  return false;
22030
22240
  }
22031
22241
  }
22032
22242
  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;
22243
+ return resolveOnPath(name);
22040
22244
  }
22041
22245
  function portableCommand(cmd) {
22042
- if (!isAbsolute2(cmd)) {
22246
+ if (!isAbsolute3(cmd)) {
22043
22247
  return onPath(cmd) ? { command: cmd, rewritten: false } : { missing: cmd };
22044
22248
  }
22045
22249
  if (isExecutableFile(cmd))
22046
22250
  return { command: cmd, rewritten: false };
22047
- const base2 = basename24(cmd);
22251
+ const base2 = basename25(cmd);
22048
22252
  if (onPath(base2))
22049
22253
  return { command: base2, rewritten: true };
22050
22254
  return { missing: cmd };
@@ -22177,9 +22381,9 @@ function executePull(rows, opts = {}) {
22177
22381
  const outcomes = [];
22178
22382
  for (const { name, body, truncated, redacted, tools } of skills) {
22179
22383
  for (const tool of tools) {
22180
- const dir = join48(skillsDirFor(tool), name);
22181
- const file = join48(dir, "SKILL.md");
22182
- if (existsSync45(file)) {
22384
+ const dir = join49(skillsDirFor(tool), name);
22385
+ const file = join49(dir, "SKILL.md");
22386
+ if (existsSync46(file)) {
22183
22387
  outcomes.push({ type: "skill", name, tool, status: "present" });
22184
22388
  continue;
22185
22389
  }
@@ -22224,7 +22428,7 @@ function executePull(rows, opts = {}) {
22224
22428
  outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "emit failed" });
22225
22429
  continue;
22226
22430
  }
22227
- if (existsSync45(out.path)) {
22431
+ if (existsSync46(out.path)) {
22228
22432
  outcomes.push({ type, name, tool, status: "present" });
22229
22433
  continue;
22230
22434
  }
@@ -22298,6 +22502,7 @@ var NOT_REBUILDABLE;
22298
22502
  var init_toolkit_pull = __esm({
22299
22503
  "../engine/dist/core/toolkit-pull.js"() {
22300
22504
  "use strict";
22505
+ init_which();
22301
22506
  init_toolkit_sync();
22302
22507
  init_artifact_codec();
22303
22508
  NOT_REBUILDABLE = {
@@ -22523,8 +22728,8 @@ __export(shadow_prune_exports, {
22523
22728
  DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
22524
22729
  pruneShadow: () => pruneShadow
22525
22730
  });
22526
- import { readdirSync as readdirSync33, statSync as statSync42, unlinkSync as unlinkSync3 } from "fs";
22527
- import { join as join51 } from "path";
22731
+ import { readdirSync as readdirSync33, statSync as statSync43, unlinkSync as unlinkSync3 } from "fs";
22732
+ import { join as join52 } from "path";
22528
22733
  function listShadows(isFullyAcked) {
22529
22734
  const out = [];
22530
22735
  const root = shadowRoot();
@@ -22535,7 +22740,7 @@ function listShadows(isFullyAcked) {
22535
22740
  return out;
22536
22741
  }
22537
22742
  for (const tool of tools) {
22538
- const dir = join51(root, tool);
22743
+ const dir = join52(root, tool);
22539
22744
  let names;
22540
22745
  try {
22541
22746
  names = readdirSync33(dir);
@@ -22545,10 +22750,10 @@ function listShadows(isFullyAcked) {
22545
22750
  for (const name of names) {
22546
22751
  if (!name.endsWith(".gz"))
22547
22752
  continue;
22548
- const path = join51(dir, name);
22753
+ const path = join52(dir, name);
22549
22754
  let st;
22550
22755
  try {
22551
- st = statSync42(path);
22756
+ st = statSync43(path);
22552
22757
  } catch {
22553
22758
  continue;
22554
22759
  }
@@ -22662,65 +22867,6 @@ var init_code_intel = __esm({
22662
22867
  }
22663
22868
  });
22664
22869
 
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
22870
  // ../engine/dist/core/companions.js
22725
22871
  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
22872
  import { homedir as homedir19 } from "node:os";
@@ -22986,7 +23132,7 @@ __export(collector_exports, {
22986
23132
  import { spawn as spawn2 } from "node:child_process";
22987
23133
  import { execSync as execSync4 } from "node:child_process";
22988
23134
  import { readFileSync as readFileSync45 } from "node:fs";
22989
- import { join as join54, basename as basename25 } from "node:path";
23135
+ import { join as join54, basename as basename26 } from "node:path";
22990
23136
  async function resolveCodeindexBin(autoInstall = true) {
22991
23137
  let st = checkCodeindexStatus();
22992
23138
  if (!st.installed && autoInstall)
@@ -23364,7 +23510,7 @@ async function collectCode(opts) {
23364
23510
  file,
23365
23511
  line: null,
23366
23512
  rule: "god_module",
23367
- title: `God module ${basename25(file)}`,
23513
+ title: `God module ${basename26(file)}`,
23368
23514
  snippet: `fan-in ${m.fan_in}, fan-out ${m.fan_out}`,
23369
23515
  why: FINDING_WHY.coupling,
23370
23516
  agentPrompt: couplingPrompt(file, m.fan_in ?? 0, m.fan_out ?? 0, Math.round((m.instability ?? 0) * 100) / 100)
@@ -23532,7 +23678,7 @@ async function collectCode(opts) {
23532
23678
  file,
23533
23679
  line: v.line ?? null,
23534
23680
  rule: v.violation_type ?? "manifest_violation",
23535
- title: `${v.violation_type} in ${basename25(file)}`,
23681
+ title: `${v.violation_type} in ${basename26(file)}`,
23536
23682
  snippet: v.description ?? "",
23537
23683
  why: FINDING_WHY.manifest,
23538
23684
  agentPrompt: manifestPrompt(v.violation_type ?? "", file, v.line ?? null, v.description ?? "")
@@ -23922,15 +24068,15 @@ init_settings();
23922
24068
  init_sync_client();
23923
24069
  init_http();
23924
24070
  import chokidar from "chokidar";
23925
- import { dirname as dirname25, basename as basename26, join as join55, resolve as resolve2, sep as sep3 } from "path";
24071
+ import { dirname as dirname25, basename as basename27, join as join55, resolve as resolve2, sep as sep3 } from "path";
23926
24072
  import { homedir as homedir20 } from "os";
23927
24073
 
23928
24074
  // src/intent-drain.ts
23929
24075
  init_http();
23930
24076
  init_sync_client();
23931
24077
  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";
24078
+ import { existsSync as existsSync47, readFileSync as readFileSync41, writeFileSync as writeFileSync13, appendFileSync, mkdirSync as mkdirSync13 } from "node:fs";
24079
+ import { join as join50 } from "node:path";
23934
24080
  import { homedir as homedir18 } from "node:os";
23935
24081
 
23936
24082
  // src/project-tasks.ts
@@ -24090,7 +24236,7 @@ function applyCodeRecommendation(intent) {
24090
24236
  const meta = JSON.parse(intent.name || "{}");
24091
24237
  if (intent.artifact_type === "write_tasks_file") {
24092
24238
  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");
24239
+ const file = join50(meta.rootPath, meta.filename || "CODE_TASKS.md");
24094
24240
  writeFileSync13(file, meta.content);
24095
24241
  return { status: "done", result: JSON.stringify({ wrote: file }) };
24096
24242
  }
@@ -24100,17 +24246,17 @@ function applyCodeRecommendation(intent) {
24100
24246
  if (!text) return { status: "error", result: JSON.stringify({ error: "missing text" }) };
24101
24247
  let file;
24102
24248
  if (isGlobal) {
24103
- const dir = join49(homedir18(), ".claude");
24249
+ const dir = join50(homedir18(), ".claude");
24104
24250
  try {
24105
24251
  mkdirSync13(dir, { recursive: true });
24106
24252
  } catch {
24107
24253
  }
24108
- file = join49(dir, "CLAUDE.md");
24254
+ file = join50(dir, "CLAUDE.md");
24109
24255
  } else {
24110
24256
  if (!meta.rootPath) return { status: "error", result: JSON.stringify({ error: "missing rootPath" }) };
24111
- file = join49(meta.rootPath, "CLAUDE.md");
24257
+ file = join50(meta.rootPath, "CLAUDE.md");
24112
24258
  }
24113
- const existing = existsSync46(file) ? readFileSync41(file, "utf8") : "";
24259
+ const existing = existsSync47(file) ? readFileSync41(file, "utf8") : "";
24114
24260
  if (existing.includes(text)) return { status: "done", result: JSON.stringify({ skipped: "rule already present", file }) };
24115
24261
  const block = `${existing && !existing.endsWith("\n") ? "\n" : ""}
24116
24262
  ## Rule (added by chat-recall recommendation)
@@ -24204,10 +24350,10 @@ async function runIntent(intent, ctx) {
24204
24350
  var ownVersion2 = "0.0.0";
24205
24351
  try {
24206
24352
  const dir = dirname23(fileURLToPath4(import.meta.url));
24207
- ownVersion2 = JSON.parse(readFileSync41(join49(dir, "../package.json"), "utf-8")).version || ownVersion2;
24353
+ ownVersion2 = JSON.parse(readFileSync41(join50(dir, "../package.json"), "utf-8")).version || ownVersion2;
24208
24354
  } catch {
24209
24355
  try {
24210
- if (true) ownVersion2 = "0.5.22";
24356
+ if (true) ownVersion2 = "0.5.24";
24211
24357
  } catch {
24212
24358
  }
24213
24359
  }
@@ -24272,8 +24418,8 @@ init_auto_update();
24272
24418
  // src/code-index-cursor.ts
24273
24419
  init_paths();
24274
24420
  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");
24421
+ import { join as join51, dirname as dirname24 } from "path";
24422
+ var cursorPath = () => join51(getDataDir(), "code-index-cursor.json");
24277
24423
  function readCursor() {
24278
24424
  try {
24279
24425
  const raw = JSON.parse(readFileSync42(cursorPath(), "utf-8"));
@@ -24491,11 +24637,11 @@ function checkSelfRestart(opts) {
24491
24637
  }
24492
24638
 
24493
24639
  // src/log-rotate.ts
24494
- import { statSync as statSync41, copyFileSync as copyFileSync3, truncateSync } from "fs";
24640
+ import { statSync as statSync42, copyFileSync as copyFileSync3, truncateSync } from "fs";
24495
24641
  var LOG_MAX_BYTES = 32 * 1024 * 1024;
24496
24642
  function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24497
24643
  try {
24498
- const size = statSync41(logPath).size;
24644
+ const size = statSync42(logPath).size;
24499
24645
  if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
24500
24646
  copyFileSync3(logPath, `${logPath}.1`);
24501
24647
  truncateSync(logPath, 0);
@@ -24507,8 +24653,8 @@ function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
24507
24653
 
24508
24654
  // src/collector-migrate.ts
24509
24655
  init_http();
24510
- import { existsSync as existsSync47 } from "node:fs";
24511
- function selectProjectsToReindex(projects, current, existsFn = existsSync47) {
24656
+ import { existsSync as existsSync48 } from "node:fs";
24657
+ function selectProjectsToReindex(projects, current, existsFn = existsSync48) {
24512
24658
  const reindex = [];
24513
24659
  const missing = [];
24514
24660
  for (const p of projects) {
@@ -24551,7 +24697,7 @@ async function runCollectorMigration(opts) {
24551
24697
  init_sync_ledger();
24552
24698
  init_collector_health();
24553
24699
  import { existsSync as existsSync50, readFileSync as readFileSync46 } from "fs";
24554
- var CLI_VERSION3 = true ? "0.5.22" : "0.0.0";
24700
+ var CLI_VERSION3 = true ? "0.5.24" : "0.0.0";
24555
24701
  var DEBOUNCE_MS = 5e3;
24556
24702
  var CLAUDE_DIR = claudeBackend.projectsDir();
24557
24703
  var PLANS_DIR = claudeBackend.plansDir();
@@ -24652,7 +24798,7 @@ function watchWithFallback(name, pattern, t) {
24652
24798
  return w;
24653
24799
  }
24654
24800
  var sessionWatcher = watchWithFallback("sessions", `${CLAUDE_DIR}/**/*.jsonl`, {
24655
- ignored: (p) => /agent-/.test(p) || /^\./.test(basename26(p)),
24801
+ ignored: (p) => /agent-/.test(p) || /^\./.test(basename27(p)),
24656
24802
  interval: 5e3
24657
24803
  });
24658
24804
  var plansWatcher = chokidar.watch(`${PLANS_DIR}/*.md`, {