chat-recall 0.7.11 → 0.7.12

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/cli.js CHANGED
@@ -4628,8 +4628,15 @@ var init_claude_prompt_origin = __esm({
4628
4628
  INJECTED_PREFIXES = [
4629
4629
  ["<task-notification", "task-notification"],
4630
4630
  ["<agent-message", "peer"],
4631
+ ["<cross-session-message", "peer"],
4632
+ ["[Cross-session delivery notice]", "peer"],
4631
4633
  ["Another Claude session sent a message:", "peer"],
4632
- ["Stop hook feedback:", "hook"]
4634
+ ["Stop hook feedback:", "hook"],
4635
+ ["<bash-stdout>", "command-output"],
4636
+ ["<bash-stderr>", "command-output"],
4637
+ ["<local-command-stdout>", "command-output"],
4638
+ ["<local-command-stderr>", "command-output"],
4639
+ ["<<autonomous-loop", "meta"]
4633
4640
  ];
4634
4641
  }
4635
4642
  });
@@ -6618,7 +6625,11 @@ __export(raw_exports, {
6618
6625
  gzipContainer: () => gzipContainer,
6619
6626
  mapContainerText: () => mapContainerText,
6620
6627
  parseOpenCodeDumpText: () => parseOpenCodeDumpText,
6621
- parseTranscriptFromContainer: () => parseTranscriptFromContainer
6628
+ parseTranscriptFromContainer: () => parseTranscriptFromContainer,
6629
+ redactContainer: () => redactContainer,
6630
+ redactJsonLine: () => redactJsonLine,
6631
+ repairContainer: () => repairContainer,
6632
+ repairRedactedJsonl: () => repairRedactedJsonl
6622
6633
  });
6623
6634
  import { gzipSync, gunzipSync } from "zlib";
6624
6635
  import { createHash } from "crypto";
@@ -6659,6 +6670,134 @@ function gunzipContainer(gz) {
6659
6670
  function mapContainerText(c, fn) {
6660
6671
  return { ...c, files: c.files.map((f) => ({ name: f.name, text: fn(f.text) })) };
6661
6672
  }
6673
+ function repairRedactedJsonl(text) {
6674
+ let repaired = 0;
6675
+ const parts = [];
6676
+ let copied = 0;
6677
+ let at = text.indexOf("[REDACTED:");
6678
+ while (at >= 0) {
6679
+ const start = text.lastIndexOf("\n", at) + 1;
6680
+ let end = text.indexOf("\n", at);
6681
+ if (end < 0)
6682
+ end = text.length;
6683
+ const fixed = repairLine(text.slice(start, end));
6684
+ if (fixed !== null) {
6685
+ parts.push(text.slice(copied, start), fixed);
6686
+ copied = end;
6687
+ repaired++;
6688
+ }
6689
+ at = text.indexOf("[REDACTED:", end);
6690
+ }
6691
+ if (repaired === 0)
6692
+ return { text, repaired: 0 };
6693
+ parts.push(text.slice(copied));
6694
+ return { text: parts.join(""), repaired };
6695
+ }
6696
+ function parseError(line) {
6697
+ try {
6698
+ JSON.parse(line);
6699
+ return null;
6700
+ } catch (e) {
6701
+ const m = /position (\d+)/.exec(e instanceof Error ? e.message : "");
6702
+ return m ? Number(m[1]) : line.length;
6703
+ }
6704
+ }
6705
+ function repairLine(line) {
6706
+ if (!line.includes("[REDACTED:") || parseError(line) === null)
6707
+ return null;
6708
+ let out = line.replace(/(?<!\\)((?:\\\\)*)\\(\[REDACTED:)/g, "$1$2");
6709
+ for (let attempt = 0; attempt < 64; attempt++) {
6710
+ const at = parseError(out);
6711
+ if (at === null)
6712
+ return out;
6713
+ let site = -1;
6714
+ for (const m of out.matchAll(MARKER_QUOTE)) {
6715
+ const q = m.index + m[0].length - 1;
6716
+ if (q < at)
6717
+ site = q;
6718
+ }
6719
+ if (site < 0)
6720
+ return null;
6721
+ out = out.slice(0, site) + "\\" + out.slice(site);
6722
+ }
6723
+ return null;
6724
+ }
6725
+ function redactJsonLine(line, redact) {
6726
+ if (!line.includes('"'))
6727
+ return redact(line);
6728
+ try {
6729
+ JSON.parse(line);
6730
+ } catch {
6731
+ return redact(line);
6732
+ }
6733
+ const decoded = mapJsonStrings(line, redact, true);
6734
+ const out = redact(decoded);
6735
+ try {
6736
+ JSON.parse(out);
6737
+ return out;
6738
+ } catch {
6739
+ return mapJsonStrings(decoded, redact, false);
6740
+ }
6741
+ }
6742
+ function mapJsonStrings(line, fn, escapedOnly) {
6743
+ let out = "";
6744
+ let i = 0;
6745
+ for (; ; ) {
6746
+ const q = line.indexOf('"', i);
6747
+ if (q < 0)
6748
+ return out + line.slice(i);
6749
+ let j = q + 1;
6750
+ while (j < line.length) {
6751
+ const c = line.charCodeAt(j);
6752
+ if (c === 92)
6753
+ j += 2;
6754
+ else if (c === 34)
6755
+ break;
6756
+ else
6757
+ j++;
6758
+ }
6759
+ const token = line.slice(q, j + 1);
6760
+ out += line.slice(i, q);
6761
+ i = j + 1;
6762
+ const body2 = token.slice(1, -1);
6763
+ const escaped = body2.includes("\\");
6764
+ if (escapedOnly && !escaped) {
6765
+ out += token;
6766
+ continue;
6767
+ }
6768
+ let value = body2;
6769
+ if (escaped) {
6770
+ try {
6771
+ value = JSON.parse(token);
6772
+ } catch {
6773
+ out += token;
6774
+ continue;
6775
+ }
6776
+ }
6777
+ const next = fn(value);
6778
+ out += next === value ? token : JSON.stringify(next);
6779
+ }
6780
+ }
6781
+ function redactContainer(c, redact) {
6782
+ return {
6783
+ ...c,
6784
+ files: c.files.map((f) => ({
6785
+ name: f.name,
6786
+ text: f.name.endsWith(".jsonl") ? f.text.split("\n").map((l) => l ? redactJsonLine(l, redact) : l).join("\n") : redact(f.text)
6787
+ }))
6788
+ };
6789
+ }
6790
+ function repairContainer(c) {
6791
+ let repaired = 0;
6792
+ const files = c.files.map((f) => {
6793
+ if (!f.name.endsWith(".jsonl"))
6794
+ return f;
6795
+ const r = repairRedactedJsonl(f.text);
6796
+ repaired += r.repaired;
6797
+ return r.repaired > 0 ? { name: f.name, text: r.text } : f;
6798
+ });
6799
+ return repaired > 0 ? { container: { ...c, files }, repaired } : { container: c, repaired: 0 };
6800
+ }
6662
6801
  function subagentKind(id) {
6663
6802
  return id.includes("acompact") ? "compact" : id.includes("aside_question") ? "aside" : id.includes("explore") || /^agent-a[0-9a-f]{16,}$/i.test(id) ? "explore" : "other";
6664
6803
  }
@@ -6829,6 +6968,7 @@ function requireFs() {
6829
6968
  function requirePath() {
6830
6969
  return pathMod;
6831
6970
  }
6971
+ var MARKER_QUOTE;
6832
6972
  var init_raw = __esm({
6833
6973
  "../engine/dist/transcript/raw.js"() {
6834
6974
  "use strict";
@@ -6836,6 +6976,7 @@ var init_raw = __esm({
6836
6976
  init_claude();
6837
6977
  init_codex();
6838
6978
  init_from_events();
6979
+ MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
6839
6980
  }
6840
6981
  });
6841
6982
 
@@ -6990,7 +7131,7 @@ var init_session_sentiment = __esm({
6990
7131
  DIRECTIVE_HEAD = /^(?:please\s+)?(?:use|implement|build|make|add|create|fix|remove|delete|update|refactor|run|deploy|push|merge|test|check|investigate|find|search|show|list|generate|set\s+up|ensure)\b/i;
6991
7132
  CLARIFY_PHRASES = /\b(?:wdym|what do you mean|explain|clarify|what is|what's|huh\??|i don'?t understand)\b/i;
6992
7133
  FRUSTRATED_PHRASES = /\b(?:why (?:the )?(?:fuck|hell)|wtf|are you (?:kidding|serious)|stop slacking|stop making|why did you|why didn'?t you|i (?:fucking )?(?:asked|told you)|are you (?:listening|even)|come\s*on|just\s+do)\b/i;
6993
- MARKERS_VERSION = 2;
7134
+ MARKERS_VERSION = 3;
6994
7135
  }
6995
7136
  });
6996
7137
 
@@ -12662,7 +12803,13 @@ function redactSecrets(text, opts = {}) {
12662
12803
  return whole;
12663
12804
  if (opts.count)
12664
12805
  opts.count.redactions++;
12665
- return whole.slice(0, whole.length - secret.length) + `[REDACTED:${r.label}]`;
12806
+ let last = args.length - 1;
12807
+ if (typeof args[last] === "object")
12808
+ last--;
12809
+ const source = args[last];
12810
+ const secretStart = args[last - 1] + whole.length - secret.length;
12811
+ const head = escapeHead(source, secretStart, secret.length);
12812
+ return whole.slice(0, whole.length - secret.length + head) + `[REDACTED:${r.label}]` + escapeKept(whole, whole.length);
12666
12813
  });
12667
12814
  }
12668
12815
  const ctx = findContextualSecrets(out);
@@ -12670,10 +12817,25 @@ function redactSecrets(text, opts = {}) {
12670
12817
  const { start, end } = ctx[i];
12671
12818
  if (opts.count)
12672
12819
  opts.count.redactions++;
12673
- out = out.slice(0, start) + "[REDACTED:secret-context]" + out.slice(end);
12820
+ const head = escapeHead(out, start, end - start);
12821
+ out = out.slice(0, start + head) + "[REDACTED:secret-context]" + escapeKept(out, end) + out.slice(end);
12674
12822
  }
12675
12823
  return out;
12676
12824
  }
12825
+ function escapeKept(text, end) {
12826
+ let run = 0;
12827
+ while (run < end && text.charCodeAt(end - 1 - run) === 92)
12828
+ run++;
12829
+ return run % 2 === 1 ? "\\" : "";
12830
+ }
12831
+ function escapeHead(text, start, length) {
12832
+ let run = 0;
12833
+ while (run < start && text.charCodeAt(start - 1 - run) === 92)
12834
+ run++;
12835
+ if (run % 2 === 0)
12836
+ return 0;
12837
+ return Math.min(text[start] === "u" ? 5 : 1, length);
12838
+ }
12677
12839
  function maskSecret(s) {
12678
12840
  if (!s)
12679
12841
  return "";
@@ -12828,7 +12990,12 @@ var init_secret_redactor = __esm({
12828
12990
  // userinfo URL walked through in cleartext — and a `jdbc:postgresql://…`
12829
12991
  // prefix broke the \b anchor for the one family it did cover. Any scheme
12830
12992
  // followed by userinfo is a credential, so match the shape, not a list.
12831
- { label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/]{1,64}:([^@\s/]{1,256})(?=@)/g },
12993
+ //
12994
+ // A quote in userinfo is percent-encoded, so neither part takes a `"`. The
12995
+ // sync redacts JSONL text, and a match that ran on through `","is_error":`
12996
+ // to a later `@` replaced JSON structure: 4 lines on one machine stopped
12997
+ // parsing, and their records were dropped.
12998
+ { label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/"]{1,64}:([^@\s/"]{1,256})(?=@)/g },
12832
12999
  // Bare AWS secret-access-key VALUE: EXACTLY 40 base64 chars, word-bounded,
12833
13000
  // containing upper+lower+digit. This is the gitleaks heuristic — the mixed-case
12834
13001
  // requirement excludes 40-char lowercase-hex git SHAs, and the exact-40 bound
@@ -14150,6 +14317,10 @@ __export(transcript_exports, {
14150
14317
  parseTranscript: () => parseTranscript,
14151
14318
  parseTranscriptFromContainer: () => parseTranscriptFromContainer,
14152
14319
  readShadowContainer: () => readShadowContainer,
14320
+ redactContainer: () => redactContainer,
14321
+ redactJsonLine: () => redactJsonLine,
14322
+ repairContainer: () => repairContainer,
14323
+ repairRedactedJsonl: () => repairRedactedJsonl,
14153
14324
  seedShadow: () => seedShadow,
14154
14325
  shadowFileFor: () => shadowFileFor,
14155
14326
  shadowRoot: () => shadowRoot,
@@ -18765,7 +18936,7 @@ var init_http = __esm({
18765
18936
  CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
18766
18937
  } catch {
18767
18938
  try {
18768
- if (true) CLI_VERSION = "0.7.11";
18939
+ if (true) CLI_VERSION = "0.7.12";
18769
18940
  } catch {
18770
18941
  }
18771
18942
  }
@@ -19263,7 +19434,7 @@ var init_telemetry = __esm({
19263
19434
  init_sync_client();
19264
19435
  cliVersion2 = () => {
19265
19436
  try {
19266
- return true ? "0.7.11" : "dev";
19437
+ return true ? "0.7.12" : "dev";
19267
19438
  } catch {
19268
19439
  return "dev";
19269
19440
  }
@@ -21444,7 +21615,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
21444
21615
  } else {
21445
21616
  try {
21446
21617
  const count2 = { redactions: 0 };
21447
- const redacted = mapContainerText(container, (t) => redactSecrets(t, { force: true, count: count2 }));
21618
+ const redacted = redactContainer(container, (t) => redactSecrets(t, { force: true, count: count2 }));
21448
21619
  count.redactions += count2.redactions;
21449
21620
  const { gz, size } = gzipContainer(redacted);
21450
21621
  if (gz.length <= 8 * 1024 * 1024) {
@@ -21644,7 +21815,7 @@ var init_sync_client = __esm({
21644
21815
  ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
21645
21816
  } catch {
21646
21817
  try {
21647
- if (true) ownVersion = "0.7.11";
21818
+ if (true) ownVersion = "0.7.12";
21648
21819
  } catch {
21649
21820
  }
21650
21821
  }
@@ -25806,7 +25977,7 @@ var init_intent_drain = __esm({
25806
25977
  ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
25807
25978
  } catch {
25808
25979
  try {
25809
- if (true) ownVersion2 = "0.7.11";
25980
+ if (true) ownVersion2 = "0.7.12";
25810
25981
  } catch {
25811
25982
  }
25812
25983
  }
@@ -29368,7 +29539,7 @@ program.command("verify").description("Check that the server holds everything th
29368
29539
  }
29369
29540
  const { verifyAgainstServer: verifyAgainstServer2, verifyTargets: verifyTargets2 } = await Promise.resolve().then(() => (init_verify_deep(), verify_deep_exports));
29370
29541
  const { getBackend: getBackend2 } = await Promise.resolve().then(() => (init_tool_backend(), tool_backend_exports));
29371
- const { gzipContainer: gzipContainer2, mapContainerText: mapContainerText2 } = await Promise.resolve().then(() => (init_transcript(), transcript_exports));
29542
+ const { gzipContainer: gzipContainer2, redactContainer: redactContainer2 } = await Promise.resolve().then(() => (init_transcript(), transcript_exports));
29372
29543
  const { redactSecrets: redactSecrets2 } = await Promise.resolve().then(() => (init_secret_redactor(), secret_redactor_exports));
29373
29544
  const { fetchWithTimeout: fetchWithTimeout2 } = await Promise.resolve().then(() => (init_http(), http_exports));
29374
29545
  const { forceFullResync: forceFullResync2 } = await Promise.resolve().then(() => (init_verify_repair(), verify_repair_exports));
@@ -29417,7 +29588,7 @@ program.command("verify").description("Check that the server holds everything th
29417
29588
  mtime: exp.mtime,
29418
29589
  files: exp.files.map((f) => ({ name: f.name, text: f.bytes.toString("utf-8") }))
29419
29590
  };
29420
- const redacted = mapContainerText2(container, (t) => redactSecrets2(t, { force: true }));
29591
+ const redacted = redactContainer2(container, (t) => redactSecrets2(t, { force: true }));
29421
29592
  return gzipContainer2(redacted).size;
29422
29593
  } catch {
29423
29594
  return null;