chat-recall 0.7.1 → 0.7.3

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
@@ -8199,12 +8199,12 @@ var init_claude2 = __esm({
8199
8199
  const seen = /* @__PURE__ */ new Set();
8200
8200
  const out = [];
8201
8201
  for (const root of claudeProjectDirs()) {
8202
- this.collectSessionsFromRoot(root, cutoff, filter, seen, out);
8202
+ this.collectSessionsFromRoot(root, cutoff, filter, seen, out, opts.previews !== false);
8203
8203
  }
8204
8204
  out.sort((a, b) => b.mtime - a.mtime);
8205
8205
  return opts.limit ? out.slice(0, opts.limit) : out;
8206
8206
  }
8207
- collectSessionsFromRoot(root, cutoff, filter, seen, out) {
8207
+ collectSessionsFromRoot(root, cutoff, filter, seen, out, previews) {
8208
8208
  if (!existsSync10(root))
8209
8209
  return;
8210
8210
  for (const proj of readdirSync7(root, { withFileTypes: true })) {
@@ -8263,7 +8263,7 @@ var init_claude2 = __esm({
8263
8263
  }
8264
8264
  if (stat3.mtimeMs < cutoff)
8265
8265
  continue;
8266
- const firstPrompt = extractFirstUserPromptSync(fullPath, { maxLength: 200 });
8266
+ const firstPrompt = previews ? extractFirstUserPromptSync(fullPath, { maxLength: 200 }) : "";
8267
8267
  out.push({
8268
8268
  toolId: "claude",
8269
8269
  rawId: sessionId,
@@ -8861,23 +8861,8 @@ var init_opencode = __esm({
8861
8861
  const projectPath = row.project_path || row.directory || "";
8862
8862
  if (filter && !projectPath.toLowerCase().includes(filter))
8863
8863
  continue;
8864
- const firstUser = db.prepare(`
8865
- SELECT p.data
8866
- FROM part p JOIN message m ON m.id = p.message_id
8867
- WHERE p.session_id = ?
8868
- AND p.data LIKE '%"type":"text"%'
8869
- AND m.data LIKE '%"role":"user"%'
8870
- ORDER BY p.time_created ASC LIMIT 1
8871
- `).get(row.id);
8872
- let firstPrompt = "";
8873
- if (firstUser) {
8874
- try {
8875
- const parsed = JSON.parse(firstUser.data);
8876
- firstPrompt = flatString(String(parsed?.text || "").slice(0, 200));
8877
- } catch {
8878
- }
8879
- }
8880
- const messageCount = db.prepare("SELECT COUNT(*) as c FROM message WHERE session_id = ?").get(row.id)?.c ?? 0;
8864
+ const firstPrompt = opts.previews === false ? "" : this.firstUserPrompt(db, row.id);
8865
+ const messageCount = opts.previews === false ? 0 : db.prepare("SELECT COUNT(*) as c FROM message WHERE session_id = ?").get(row.id)?.c ?? 0;
8881
8866
  const created = new Date(row.time_created || row.time_updated).toISOString();
8882
8867
  const modified = new Date(row.time_updated).toISOString();
8883
8868
  out.push({
@@ -8901,6 +8886,45 @@ var init_opencode = __esm({
8901
8886
  db.close();
8902
8887
  }
8903
8888
  }
8889
+ /**
8890
+ * The first user text part of a session.
8891
+ *
8892
+ * Walks the session's user messages oldest first through the
8893
+ * (session_id, time_created, id) index and stops at the first one with a
8894
+ * text part. The role and the text are read by SQLite: a first message can
8895
+ * carry whole diffs in `summary` (107 MB on one row), and parsing that in JS
8896
+ * to read one field took the process to 510 MB. The earlier query filtered
8897
+ * every part and message with LIKE and then sorted, so it read all of a
8898
+ * session's data: 423 MB for a 236-session listing.
8899
+ */
8900
+ firstUserPrompt(db, sessionId) {
8901
+ try {
8902
+ const has = (table, col) => !!db.prepare(`SELECT 1 FROM pragma_table_info(?) WHERE name = ?`).get(table, col);
8903
+ const msgOrder = has("message", "time_created") ? "time_created, id" : "rowid";
8904
+ const partOrder = has("part", "time_created") ? "time_created, id" : "rowid";
8905
+ const nextUser = db.prepare(`SELECT id, ${msgOrder === "rowid" ? "rowid AS k1, 0 AS k2" : "time_created AS k1, id AS k2"} FROM message
8906
+ WHERE session_id = ? AND (${msgOrder === "rowid" ? "rowid, 0" : "time_created, id"}) > (?, ?)
8907
+ AND json_extract(data, '$.role') = 'user'
8908
+ ORDER BY ${msgOrder} LIMIT 1`);
8909
+ const firstText = db.prepare(`SELECT substr(json_extract(data, '$.text'), 1, 400) AS text FROM part
8910
+ WHERE message_id = ? AND json_extract(data, '$.type') = 'text'
8911
+ AND length(trim(json_extract(data, '$.text'))) > 0
8912
+ ORDER BY ${partOrder} LIMIT 1`);
8913
+ let k1 = Number.MIN_SAFE_INTEGER, k2 = msgOrder === "rowid" ? 0 : "";
8914
+ for (; ; ) {
8915
+ const m = nextUser.get(sessionId, k1, k2);
8916
+ if (!m)
8917
+ return "";
8918
+ k1 = m.k1;
8919
+ k2 = m.k2;
8920
+ const t = firstText.get(m.id);
8921
+ if (t?.text)
8922
+ return flatString(t.text.slice(0, 200));
8923
+ }
8924
+ } catch {
8925
+ return "";
8926
+ }
8927
+ }
8904
8928
  /** OpenCode auto-generates a session title (model-written, distinct from the
8905
8929
  * first prompt — e.g. "Replacing Claude with Gemini CLI"). It's a plain
8906
8930
  * column on the session row. */
@@ -9463,28 +9487,29 @@ var init_codex2 = __esm({
9463
9487
  continue;
9464
9488
  let firstPrompt = "";
9465
9489
  let messageCount = 0;
9466
- try {
9467
- const lines = readFileSync6(filePath, "utf-8").split("\n");
9468
- for (const line of lines) {
9469
- if (!line.trim())
9470
- continue;
9471
- let ev;
9472
- try {
9473
- ev = JSON.parse(line);
9474
- } catch {
9475
- continue;
9476
- }
9477
- if (ev.type === "event_msg" && ev.payload?.type === "user_message") {
9478
- messageCount++;
9479
- if (!firstPrompt && ev.payload.message) {
9480
- firstPrompt = flatString(String(ev.payload.message).slice(0, 200));
9490
+ if (opts.previews !== false)
9491
+ try {
9492
+ const lines = readFileSync6(filePath, "utf-8").split("\n");
9493
+ for (const line of lines) {
9494
+ if (!line.trim())
9495
+ continue;
9496
+ let ev;
9497
+ try {
9498
+ ev = JSON.parse(line);
9499
+ } catch {
9500
+ continue;
9501
+ }
9502
+ if (ev.type === "event_msg" && ev.payload?.type === "user_message") {
9503
+ messageCount++;
9504
+ if (!firstPrompt && ev.payload.message) {
9505
+ firstPrompt = flatString(String(ev.payload.message).slice(0, 200));
9506
+ }
9507
+ } else if (ev.type === "response_item" && ev.payload?.type === "message") {
9508
+ messageCount++;
9481
9509
  }
9482
- } else if (ev.type === "response_item" && ev.payload?.type === "message") {
9483
- messageCount++;
9484
9510
  }
9511
+ } catch {
9485
9512
  }
9486
- } catch {
9487
- }
9488
9513
  const prior = seen.get(rawId);
9489
9514
  if (prior) {
9490
9515
  if (stat3.mtimeMs > prior.mtime) {
@@ -10174,21 +10199,22 @@ var init_agy = __esm({
10174
10199
  const projectDir = projectPath ? basename10(projectPath) : "";
10175
10200
  let firstPrompt = "";
10176
10201
  let messageCount = 0;
10177
- try {
10178
- const lines = readFileSync7(filePath, "utf-8").split("\n").filter(Boolean);
10179
- messageCount = lines.length;
10180
- for (const line of lines) {
10181
- const obj = JSON.parse(line);
10182
- if (obj.source === "USER_EXPLICIT" && obj.type === "USER_INPUT" && typeof obj.content === "string") {
10183
- const content = obj.content;
10184
- const match = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
10185
- const rawText = match ? match[1].trim() : content.trim();
10186
- firstPrompt = flatString(rawText.slice(0, 200));
10187
- break;
10202
+ if (opts.previews !== false)
10203
+ try {
10204
+ const lines = readFileSync7(filePath, "utf-8").split("\n").filter(Boolean);
10205
+ messageCount = lines.length;
10206
+ for (const line of lines) {
10207
+ const obj = JSON.parse(line);
10208
+ if (obj.source === "USER_EXPLICIT" && obj.type === "USER_INPUT" && typeof obj.content === "string") {
10209
+ const content = obj.content;
10210
+ const match = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
10211
+ const rawText = match ? match[1].trim() : content.trim();
10212
+ firstPrompt = flatString(rawText.slice(0, 200));
10213
+ break;
10214
+ }
10188
10215
  }
10216
+ } catch {
10189
10217
  }
10190
- } catch {
10191
- }
10192
10218
  if (seenIds.has(rawId))
10193
10219
  continue;
10194
10220
  seenIds.add(rawId);
@@ -13256,12 +13282,13 @@ function resolveProjectId(inputPath) {
13256
13282
  if (!isAbsolute(inputPath)) {
13257
13283
  return { id: `path:${inputPath}`, displayName: inputPath, source: "path" };
13258
13284
  }
13285
+ const known = inputCache.get(inputPath);
13286
+ if (known)
13287
+ return known;
13259
13288
  const realPath = safeRealpath(inputPath);
13260
- const cached = resolveCache.get(realPath);
13261
- if (cached)
13262
- return cached;
13263
- const result = doResolve(realPath);
13289
+ const result = resolveCache.get(realPath) ?? doResolve(realPath);
13264
13290
  resolveCache.set(realPath, result);
13291
+ inputCache.set(inputPath, result);
13265
13292
  return result;
13266
13293
  }
13267
13294
  function doResolve(realPath) {
@@ -13540,7 +13567,7 @@ function globToRegex(glob) {
13540
13567
  function escapeRe(s) {
13541
13568
  return s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
13542
13569
  }
13543
- var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
13570
+ var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, inputCache, gitCache, workspaceCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
13544
13571
  var init_project_resolver = __esm({
13545
13572
  "../engine/dist/core/project-resolver.js"() {
13546
13573
  "use strict";
@@ -13548,6 +13575,7 @@ var init_project_resolver = __esm({
13548
13575
  DEFAULT_AUTO_WORKSPACE_MIN_REPOS = 3;
13549
13576
  BOT_WORKTREE_MARKERS = [".claude-pr-bot"];
13550
13577
  resolveCache = /* @__PURE__ */ new Map();
13578
+ inputCache = /* @__PURE__ */ new Map();
13551
13579
  gitCache = /* @__PURE__ */ new Map();
13552
13580
  workspaceCache = /* @__PURE__ */ new Map();
13553
13581
  cachedConfig = null;
@@ -18043,7 +18071,7 @@ var init_http = __esm({
18043
18071
  CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18044
18072
  } catch {
18045
18073
  try {
18046
- if (true) CLI_VERSION = "0.7.1";
18074
+ if (true) CLI_VERSION = "0.7.3";
18047
18075
  } catch {
18048
18076
  }
18049
18077
  }
@@ -18515,16 +18543,16 @@ async function flush() {
18515
18543
  }
18516
18544
  function stableMark(value) {
18517
18545
  try {
18518
- const { createHash: createHash13 } = __require("node:crypto");
18519
- return createHash13("sha256").update(value).digest("hex").slice(0, 12);
18546
+ const { createHash: createHash14 } = __require("node:crypto");
18547
+ return createHash14("sha256").update(value).digest("hex").slice(0, 12);
18520
18548
  } catch {
18521
18549
  return "";
18522
18550
  }
18523
18551
  }
18524
18552
  function hashHost() {
18525
18553
  try {
18526
- const { createHash: createHash13 } = __require("node:crypto");
18527
- return createHash13("sha256").update(hostname()).digest("hex").slice(0, 12);
18554
+ const { createHash: createHash14 } = __require("node:crypto");
18555
+ return createHash14("sha256").update(hostname()).digest("hex").slice(0, 12);
18528
18556
  } catch {
18529
18557
  return "";
18530
18558
  }
@@ -18538,7 +18566,7 @@ var init_telemetry = __esm({
18538
18566
  init_sync_client();
18539
18567
  cliVersion = () => {
18540
18568
  try {
18541
- return true ? "0.7.1" : "dev";
18569
+ return true ? "0.7.3" : "dev";
18542
18570
  } catch {
18543
18571
  return "dev";
18544
18572
  }
@@ -19511,7 +19539,7 @@ async function syncToTargetInScope(cred, opts = {}) {
19511
19539
  const listSinceMs = changedWalk ? Math.max(0, (opts.sinceMs ?? 0) - CHANGED_WALK_OVERLAP_MS) : opts.useLedger ? void 0 : opts.sinceMs;
19512
19540
  const refs = listAvailableBackends().flatMap((b) => {
19513
19541
  try {
19514
- return b.listSessions({ sinceMs: listSinceMs });
19542
+ return b.listSessions({ sinceMs: listSinceMs, previews: false });
19515
19543
  } catch {
19516
19544
  return [];
19517
19545
  }
@@ -19826,7 +19854,7 @@ async function syncToTargetInScope(cred, opts = {}) {
19826
19854
  cred,
19827
19855
  () => listAvailableBackends().flatMap((b) => {
19828
19856
  try {
19829
- return b.listSessions({});
19857
+ return b.listSessions({ previews: false });
19830
19858
  } catch {
19831
19859
  return [];
19832
19860
  }
@@ -20593,7 +20621,7 @@ var init_sync_client = __esm({
20593
20621
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
20594
20622
  } catch {
20595
20623
  try {
20596
- if (true) ownVersion = "0.7.1";
20624
+ if (true) ownVersion = "0.7.3";
20597
20625
  } catch {
20598
20626
  }
20599
20627
  }
@@ -21770,7 +21798,7 @@ __export(shadow_prune_exports, {
21770
21798
  DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
21771
21799
  pruneShadow: () => pruneShadow
21772
21800
  });
21773
- import { readdirSync as readdirSync33, statSync as statSync42, unlinkSync as unlinkSync3 } from "fs";
21801
+ import { readdirSync as readdirSync33, statSync as statSync43, unlinkSync as unlinkSync3 } from "fs";
21774
21802
  import { join as join50 } from "path";
21775
21803
  function listShadows(isFullyAcked) {
21776
21804
  const out = [];
@@ -21795,7 +21823,7 @@ function listShadows(isFullyAcked) {
21795
21823
  const path = join50(dir, name);
21796
21824
  let st;
21797
21825
  try {
21798
- st = statSync42(path);
21826
+ st = statSync43(path);
21799
21827
  } catch {
21800
21828
  continue;
21801
21829
  }
@@ -21867,9 +21895,9 @@ var init_shadow_prune = __esm({
21867
21895
  });
21868
21896
 
21869
21897
  // ../engine/dist/types/code-intel.js
21870
- import { createHash as createHash11 } from "crypto";
21898
+ import { createHash as createHash12 } from "crypto";
21871
21899
  function shortHash(s) {
21872
- return createHash11("sha256").update(s).digest("hex").slice(0, 16);
21900
+ return createHash12("sha256").update(s).digest("hex").slice(0, 16);
21873
21901
  }
21874
21902
  function snippetKey(snippet) {
21875
21903
  return (snippet ?? "").replace(/\s+/g, " ").trim().slice(0, 200);
@@ -21910,11 +21938,11 @@ var init_code_intel = __esm({
21910
21938
  });
21911
21939
 
21912
21940
  // ../engine/dist/core/companions.js
21913
- import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync43, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync42, writeFileSync as writeFileSync15 } from "node:fs";
21941
+ import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync44, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync42, writeFileSync as writeFileSync15 } from "node:fs";
21914
21942
  import { homedir as homedir19 } from "node:os";
21915
21943
  import { join as join51 } from "node:path";
21916
21944
  import { execSync as execSync3 } from "node:child_process";
21917
- import { createHash as createHash12 } from "node:crypto";
21945
+ import { createHash as createHash13 } from "node:crypto";
21918
21946
  function expectedCodeindexSha256(artifact) {
21919
21947
  return CODEINDEX_SHA256[artifact.replace(/^codeindex-/, "").replace(/\.exe$/, "")] ?? null;
21920
21948
  }
@@ -21961,7 +21989,7 @@ function checkCodeindexStatus() {
21961
21989
  status.installed = true;
21962
21990
  status.path = foundPath;
21963
21991
  try {
21964
- status.size = statSync43(foundPath).size;
21992
+ status.size = statSync44(foundPath).size;
21965
21993
  } catch {
21966
21994
  }
21967
21995
  try {
@@ -22022,7 +22050,7 @@ async function installCodeindex(opts = {}) {
22022
22050
  if (!expected) {
22023
22051
  throw new Error(`No pinned checksum for ${status.artifactName} \u2014 refusing to install an unverified binary. Add its sha256 to CODEINDEX_SHA256 in companions.ts.`);
22024
22052
  }
22025
- const actual = createHash12("sha256").update(readFileSync42(tmpPath)).digest("hex");
22053
+ const actual = createHash13("sha256").update(readFileSync42(tmpPath)).digest("hex");
22026
22054
  if (actual !== expected) {
22027
22055
  throw new Error(`Checksum mismatch for ${status.artifactName}.
22028
22056
  expected ${expected}
@@ -22186,7 +22214,10 @@ async function resolveCodeindexBin(autoInstall = true) {
22186
22214
  }
22187
22215
  function runMcp(binPath, workspace, calls, timeoutMs = 18e4) {
22188
22216
  return new Promise((resolve3, reject) => {
22189
- const p = spawn2(binPath, ["--mcp", "--workspace", workspace], { stdio: ["pipe", "pipe", "ignore"] });
22217
+ const p = spawn2(binPath, ["--mcp", "--workspace", workspace], {
22218
+ stdio: ["pipe", "pipe", "ignore"],
22219
+ env: { ...process.env, CODEINDEX_NO_DAEMON: "1" }
22220
+ });
22190
22221
  const res = /* @__PURE__ */ new Map();
22191
22222
  let pending = "";
22192
22223
  let failed = false;
@@ -23699,7 +23730,7 @@ try {
23699
23730
  ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
23700
23731
  } catch {
23701
23732
  try {
23702
- if (true) ownVersion2 = "0.7.1";
23733
+ if (true) ownVersion2 = "0.7.3";
23703
23734
  } catch {
23704
23735
  }
23705
23736
  }
@@ -23764,7 +23795,9 @@ init_auto_update();
23764
23795
 
23765
23796
  // src/code-index-cursor.ts
23766
23797
  init_paths();
23767
- import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15 } from "fs";
23798
+ import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync41 } from "fs";
23799
+ import { execFileSync as execFileSync4 } from "child_process";
23800
+ import { createHash as createHash10 } from "crypto";
23768
23801
  import { join as join49, dirname as dirname24 } from "path";
23769
23802
  var cursorPath = () => join49(getDataDir(), "code-index-cursor.json");
23770
23803
  function readCursor() {
@@ -23773,7 +23806,11 @@ function readCursor() {
23773
23806
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
23774
23807
  const out = {};
23775
23808
  for (const [k, v] of Object.entries(raw)) {
23776
- if (typeof v === "number" && Number.isFinite(v)) out[k] = v;
23809
+ if (typeof v === "number" && Number.isFinite(v)) out[k] = { at: v };
23810
+ else if (v && typeof v === "object" && typeof v.at === "number" && Number.isFinite(v.at)) {
23811
+ const fp = v.fp;
23812
+ out[k] = typeof fp === "string" ? { at: v.at, fp } : { at: v.at };
23813
+ }
23777
23814
  }
23778
23815
  return out;
23779
23816
  }
@@ -23789,13 +23826,44 @@ function writeCursor(c) {
23789
23826
  } catch {
23790
23827
  }
23791
23828
  }
23792
- function noteIndexed(workspace, now = Date.now()) {
23829
+ function noteIndexed(workspace, now = Date.now(), fp) {
23793
23830
  const c = readCursor();
23794
- c[workspace] = now;
23831
+ c[workspace] = fp ? { at: now, fp } : { at: now };
23795
23832
  writeCursor(c);
23796
23833
  }
23834
+ function workspaceFingerprint(workspace, collectorVersion) {
23835
+ try {
23836
+ const git2 = (args) => execFileSync4(
23837
+ "git",
23838
+ ["-C", workspace, ...args],
23839
+ { encoding: "utf-8", timeout: 1e4, maxBuffer: 16 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] }
23840
+ );
23841
+ const head = git2(["rev-parse", "HEAD"]).trim();
23842
+ const status = git2(["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
23843
+ const h = createHash10("sha256").update(`v${collectorVersion}\0${head}\0`);
23844
+ for (const entry of status.split("\0")) {
23845
+ if (entry.length < 4) continue;
23846
+ const rel = entry.slice(3);
23847
+ let stamp2 = "gone";
23848
+ try {
23849
+ const s = statSync41(join49(workspace, rel));
23850
+ stamp2 = `${s.size}:${Math.floor(s.mtimeMs)}`;
23851
+ } catch {
23852
+ }
23853
+ h.update(`${entry.slice(0, 2)}\0${rel}\0${stamp2}\0`);
23854
+ }
23855
+ return h.digest("hex");
23856
+ } catch {
23857
+ return null;
23858
+ }
23859
+ }
23860
+ var UNCHANGED_RESEND_MS = 7 * 24 * 3600 * 1e3;
23861
+ function isUnchangedSinceIndexed(workspace, fp, cursor, now = Date.now()) {
23862
+ const e = cursor[workspace];
23863
+ return !!fp && !!e && e.fp === fp && now - e.at < UNCHANGED_RESEND_MS;
23864
+ }
23797
23865
  function orderByStaleness(workspaces, cursor = readCursor()) {
23798
- return workspaces.map((w, i) => ({ w, i, at: cursor[w] ?? -1 })).sort((a, b) => a.at - b.at || a.i - b.i).map((e) => e.w);
23866
+ return workspaces.map((w, i) => ({ w, i, at: cursor[w]?.at ?? -1 })).sort((a, b) => a.at - b.at || a.i - b.i).map((e) => e.w);
23799
23867
  }
23800
23868
  function pruneCursor(known) {
23801
23869
  const keep = new Set(known);
@@ -23915,7 +23983,7 @@ init_telemetry();
23915
23983
  // src/self-restart.ts
23916
23984
  import { spawn } from "child_process";
23917
23985
  import { readFileSync as readFileSync41 } from "fs";
23918
- import { createHash as createHash10 } from "crypto";
23986
+ import { createHash as createHash11 } from "crypto";
23919
23987
  var EXIT_CODE_CODE_CHANGED = 75;
23920
23988
  function codeFingerprint(entry = process.argv[1]) {
23921
23989
  if (!entry) return null;
@@ -23924,7 +23992,7 @@ function codeFingerprint(entry = process.argv[1]) {
23924
23992
  return {
23925
23993
  path: entry,
23926
23994
  size: buf.byteLength,
23927
- hash: createHash10("sha256").update(buf).digest("hex")
23995
+ hash: createHash11("sha256").update(buf).digest("hex")
23928
23996
  };
23929
23997
  } catch {
23930
23998
  return null;
@@ -23987,11 +24055,11 @@ function checkSelfRestart(opts) {
23987
24055
  }
23988
24056
 
23989
24057
  // src/log-rotate.ts
23990
- import { statSync as statSync41, copyFileSync as copyFileSync3, truncateSync } from "fs";
24058
+ import { statSync as statSync42, copyFileSync as copyFileSync3, truncateSync } from "fs";
23991
24059
  var LOG_MAX_BYTES = 32 * 1024 * 1024;
23992
24060
  function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
23993
24061
  try {
23994
- const size = statSync41(logPath).size;
24062
+ const size = statSync42(logPath).size;
23995
24063
  if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
23996
24064
  copyFileSync3(logPath, `${logPath}.1`);
23997
24065
  truncateSync(logPath, 0);
@@ -24046,8 +24114,8 @@ async function runCollectorMigration(opts) {
24046
24114
  // auto-indexer/indexer.ts
24047
24115
  init_sync_ledger();
24048
24116
  init_collector_health();
24049
- import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync44 } from "fs";
24050
- var CLI_VERSION3 = true ? "0.7.1" : "0.0.0";
24117
+ import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync45 } from "fs";
24118
+ var CLI_VERSION3 = true ? "0.7.3" : "0.0.0";
24051
24119
  var DEBOUNCE_MS = 5e3;
24052
24120
  var CLAUDE_DIR = claudeBackend.projectsDir();
24053
24121
  var PLANS_DIR = claudeBackend.plansDir();
@@ -24152,7 +24220,7 @@ var WATCH_WINDOW_MS = Math.max(1, Number(process.env.CHAT_RECALL_WATCH_WINDOW_DA
24152
24220
  var sessionWatcher = watchWithFallback("sessions", `${CLAUDE_DIR}/**/*.jsonl`, {
24153
24221
  ignored: (p, stats) => {
24154
24222
  if (/agent-/.test(p) || /^\./.test(basename25(p))) return true;
24155
- const st = stats ?? statSync44(p, { throwIfNoEntry: false });
24223
+ const st = stats ?? statSync45(p, { throwIfNoEntry: false });
24156
24224
  if (!st || st.isDirectory()) return false;
24157
24225
  return st.mtimeMs < Date.now() - WATCH_WINDOW_MS;
24158
24226
  },
@@ -24432,7 +24500,7 @@ function discoverWorkspaces() {
24432
24500
  for (const b of listAvailableBackends()) {
24433
24501
  let refs = [];
24434
24502
  try {
24435
- refs = b.listSessions({ sinceMs });
24503
+ refs = b.listSessions({ sinceMs, previews: false });
24436
24504
  } catch {
24437
24505
  }
24438
24506
  for (const r of refs) {
@@ -24500,7 +24568,7 @@ async function codeIndexTick() {
24500
24568
  if (discovered.length === 0) return;
24501
24569
  pruneCursor(discovered);
24502
24570
  const workspaces = orderByStaleness(discovered);
24503
- const { collectCode: collectCode2, resolveCodeindexBin: resolveCodeindexBin2 } = await Promise.resolve().then(() => (init_collector(), collector_exports));
24571
+ const { collectCode: collectCode2, resolveCodeindexBin: resolveCodeindexBin2, COLLECTOR_VERSION: COLLECTOR_VERSION2 } = await Promise.resolve().then(() => (init_collector(), collector_exports));
24504
24572
  let bin;
24505
24573
  try {
24506
24574
  bin = await resolveCodeindexBin2(true);
@@ -24508,8 +24576,14 @@ async function codeIndexTick() {
24508
24576
  daemonLog.error(`code intelligence skipped \u2014 codeindex unavailable: ${e instanceof Error ? e.message : e}`);
24509
24577
  return;
24510
24578
  }
24511
- let ok = 0;
24579
+ let ok = 0, unchanged = 0;
24580
+ const cursor = readCursor();
24512
24581
  for (const ws of workspaces) {
24582
+ const fp = workspaceFingerprint(ws, COLLECTOR_VERSION2);
24583
+ if (isUnchangedSinceIndexed(ws, fp, cursor)) {
24584
+ unchanged++;
24585
+ continue;
24586
+ }
24513
24587
  const t0 = Date.now();
24514
24588
  daemonLog.info(`code intelligence: indexing ${ws} \u2026`);
24515
24589
  let result;
@@ -24527,10 +24601,10 @@ async function codeIndexTick() {
24527
24601
  } catch {
24528
24602
  }
24529
24603
  }
24530
- noteIndexed(ws);
24604
+ noteIndexed(ws, Date.now(), fp);
24531
24605
  ok++;
24532
24606
  }
24533
- if (ok > 0) daemonLog.info(`code intelligence: indexed ${ok}/${workspaces.length} workspace(s)`);
24607
+ if (ok > 0 || unchanged > 0) daemonLog.info(`code intelligence: indexed ${ok}/${workspaces.length} workspace(s), ${unchanged} unchanged`);
24534
24608
  } finally {
24535
24609
  codeIndexInFlight = false;
24536
24610
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chat-recall",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/munhq/chat-recall.git"