chat-recall 0.7.15 → 0.7.16

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
@@ -7973,7 +7973,64 @@ var init_first_prompt = __esm({
7973
7973
  });
7974
7974
 
7975
7975
  // ../engine/dist/core/backends/tail-read.js
7976
- import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync6 } from "node:fs";
7976
+ import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync6, fstatSync } from "node:fs";
7977
+ function readAt(fd, pos, len) {
7978
+ const buf = Buffer.alloc(len);
7979
+ let got = 0;
7980
+ while (got < len) {
7981
+ const n = readSync5(fd, buf, got, len - got, pos + got);
7982
+ if (n <= 0)
7983
+ break;
7984
+ got += n;
7985
+ }
7986
+ return buf.subarray(0, got);
7987
+ }
7988
+ function linesBeforeOffset(path, offset) {
7989
+ if (offset <= 0)
7990
+ return 0;
7991
+ let fd = null;
7992
+ try {
7993
+ fd = openSync5(path, "r");
7994
+ const ino = fstatSync(fd).ino;
7995
+ const known = lineCounts.get(path);
7996
+ let pos = 0;
7997
+ let lines = 0;
7998
+ if (known && known.ino === ino && known.offset <= offset) {
7999
+ const edgeStart2 = Math.max(0, known.offset - EDGE_BYTES);
8000
+ if (readAt(fd, edgeStart2, known.offset - edgeStart2).equals(known.edge)) {
8001
+ pos = known.offset;
8002
+ lines = known.lines;
8003
+ }
8004
+ }
8005
+ const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
8006
+ while (pos < offset) {
8007
+ const n = readSync5(fd, block, 0, Math.min(SKIP_SCAN_BYTES, offset - pos), pos);
8008
+ if (n <= 0)
8009
+ return void 0;
8010
+ for (let i = block.indexOf(10, 0); i >= 0 && i < n; i = block.indexOf(10, i + 1))
8011
+ lines++;
8012
+ pos += n;
8013
+ }
8014
+ const edgeStart = Math.max(0, offset - EDGE_BYTES);
8015
+ const edge = readAt(fd, edgeStart, offset - edgeStart);
8016
+ if (lineCounts.size >= LINE_COUNT_CACHE_MAX && !lineCounts.has(path)) {
8017
+ const oldest = lineCounts.keys().next().value;
8018
+ if (oldest !== void 0)
8019
+ lineCounts.delete(oldest);
8020
+ }
8021
+ lineCounts.set(path, { offset, lines, ino, edge });
8022
+ return lines;
8023
+ } catch {
8024
+ return void 0;
8025
+ } finally {
8026
+ if (fd !== null) {
8027
+ try {
8028
+ closeSync5(fd);
8029
+ } catch {
8030
+ }
8031
+ }
8032
+ }
8033
+ }
7977
8034
  function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
7978
8035
  let size = 0;
7979
8036
  try {
@@ -8001,7 +8058,7 @@ function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
8001
8058
  const lastNl = slice.lastIndexOf(10);
8002
8059
  if (lastNl >= 0) {
8003
8060
  const text = slice.subarray(0, lastNl + 1).toString("utf-8");
8004
- return { text, newOffset: offset + lastNl + 1 };
8061
+ return { text, newOffset: offset + lastNl + 1, baseLine: linesBeforeOffset(path, offset) };
8005
8062
  }
8006
8063
  if (offset + got >= size)
8007
8064
  return { text: "", newOffset: offset };
@@ -8034,12 +8091,15 @@ function findNewline(fd, from, size) {
8034
8091
  }
8035
8092
  return -1;
8036
8093
  }
8037
- var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES;
8094
+ var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES, lineCounts, LINE_COUNT_CACHE_MAX, EDGE_BYTES;
8038
8095
  var init_tail_read = __esm({
8039
8096
  "../engine/dist/core/backends/tail-read.js"() {
8040
8097
  "use strict";
8041
8098
  TAIL_READ_MAX_BYTES = 16 * 1024 * 1024;
8042
8099
  SKIP_SCAN_BYTES = 1024 * 1024;
8100
+ lineCounts = /* @__PURE__ */ new Map();
8101
+ LINE_COUNT_CACHE_MAX = 2048;
8102
+ EDGE_BYTES = 64;
8043
8103
  }
8044
8104
  });
8045
8105
 
@@ -18269,6 +18329,7 @@ function persistLedgerData(server, serverData) {
18269
18329
  const data = load();
18270
18330
  data[server] = serverData;
18271
18331
  persist(data);
18332
+ flushLedger();
18272
18333
  }
18273
18334
  function unackedCursorAttemptCount() {
18274
18335
  return unackedCursorAttempts;
@@ -18551,7 +18612,7 @@ var init_http = __esm({
18551
18612
  CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18552
18613
  } catch {
18553
18614
  try {
18554
- if (true) CLI_VERSION = "0.7.15";
18615
+ if (true) CLI_VERSION = "0.7.16";
18555
18616
  } catch {
18556
18617
  }
18557
18618
  }
@@ -19045,7 +19106,7 @@ var init_telemetry = __esm({
19045
19106
  init_sync_client();
19046
19107
  cliVersion = () => {
19047
19108
  try {
19048
- return true ? "0.7.15" : "dev";
19109
+ return true ? "0.7.16" : "dev";
19049
19110
  } catch {
19050
19111
  return "dev";
19051
19112
  }
@@ -20284,7 +20345,8 @@ async function syncToTargetInScope(cred, opts = {}) {
20284
20345
  clearTimeout(timer);
20285
20346
  }
20286
20347
  };
20287
- const postChunkedHead = async (conv, fileSize) => {
20348
+ const postChunkedHead = async (head, fileSize) => {
20349
+ const conv = { ...head, chunk_head: true };
20288
20350
  const headers = { "content-type": "application/json" };
20289
20351
  if (cred.token) headers.authorization = `Bearer ${cred.token}`;
20290
20352
  const ac = new AbortController();
@@ -20300,9 +20362,10 @@ async function syncToTargetInScope(cred, opts = {}) {
20300
20362
  const body = await res.json().catch(() => ({}));
20301
20363
  const id = conv.session_id;
20302
20364
  const guarded = (body.shrink_guarded ?? []).find((g) => g.session_id === id);
20365
+ const staged = (body.rebuild_staged ?? []).includes(id);
20303
20366
  const mtime = conv.mtime;
20304
20367
  try {
20305
- if (!guarded) {
20368
+ if (staged || !guarded) {
20306
20369
  markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
20307
20370
  } else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
20308
20371
  markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
@@ -21035,8 +21098,13 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
21035
21098
  const backend = getBackendForId(ref.prefixedId);
21036
21099
  if (!backend?.readFromOffset) return null;
21037
21100
  const mapPath = opts.mapPath ?? ((p) => p);
21038
- const { text: tailText, newOffset, skippedBytes } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
21101
+ const { text: tailText, newOffset, skippedBytes, baseLine } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
21039
21102
  if (newOffset <= fromOffset) return null;
21103
+ const fileSize = backend.fileSize?.(ref.prefixedId) ?? 0;
21104
+ const position = {
21105
+ ...typeof baseLine === "number" ? { base_line: baseLine } : {},
21106
+ final: fileSize > 0 && newOffset >= fileSize
21107
+ };
21040
21108
  const messages = skippedBytes ? [] : parseTailMessages(ref.toolId, tailText);
21041
21109
  const textMessages = messages.filter((m) => m.role !== "summary" && m.content?.trim());
21042
21110
  const hasContent = textMessages.length > 0 || messages.some((m) => m.toolCalls?.length);
@@ -21049,6 +21117,7 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
21049
21117
  append: true,
21050
21118
  base_offset: fromOffset,
21051
21119
  from_offset: newOffset,
21120
+ ...position,
21052
21121
  redacted_text: "",
21053
21122
  envelope: { v: TRANSCRIPT_VERSION, messages: [], subagents: [] },
21054
21123
  mtime: Math.floor(ref.mtime) || 0
@@ -21095,6 +21164,7 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
21095
21164
  // equals its stored synced-through offset.
21096
21165
  from_offset: newOffset,
21097
21166
  // where it ends → new synced-through offset.
21167
+ ...position,
21098
21168
  redacted_text: redactedText,
21099
21169
  envelope,
21100
21170
  mtime: Math.floor(ref.mtime) || 0
@@ -21178,7 +21248,7 @@ var init_sync_client = __esm({
21178
21248
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21179
21249
  } catch {
21180
21250
  try {
21181
- if (true) ownVersion = "0.7.15";
21251
+ if (true) ownVersion = "0.7.16";
21182
21252
  } catch {
21183
21253
  }
21184
21254
  }
@@ -24315,7 +24385,7 @@ try {
24315
24385
  ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
24316
24386
  } catch {
24317
24387
  try {
24318
- if (true) ownVersion2 = "0.7.15";
24388
+ if (true) ownVersion2 = "0.7.16";
24319
24389
  } catch {
24320
24390
  }
24321
24391
  }
@@ -24700,7 +24770,7 @@ async function runCollectorMigration(opts) {
24700
24770
  init_sync_ledger();
24701
24771
  init_collector_health();
24702
24772
  import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync46 } from "fs";
24703
- var CLI_VERSION3 = true ? "0.7.15" : "0.0.0";
24773
+ var CLI_VERSION3 = true ? "0.7.16" : "0.0.0";
24704
24774
  var DEBOUNCE_MS = 5e3;
24705
24775
  var PLANS_DIR = claudeBackend.plansDir();
24706
24776
  var TASKS_DIR = claudeBackend.tasksDir();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chat-recall",
3
- "version": "0.7.15",
3
+ "version": "0.7.16",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/munhq/chat-recall.git"