chat-recall 0.7.11 → 0.7.13
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 +202 -25
- package/dist/cli.js.map +1 -1
- package/dist/derived.js +2 -2
- package/dist/derived.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +290 -79
- package/dist/scan-worker.d.ts.map +1 -1
- package/dist/scan-worker.js +205 -104
- package/dist/scan-worker.js.map +1 -1
- package/dist/sync-client.js +2 -2
- package/dist/sync-client.js.map +1 -1
- package/dist/watch.js +189 -16
- package/package.json +1 -1
package/dist/watch.js
CHANGED
|
@@ -194,8 +194,15 @@ var init_claude_prompt_origin = __esm({
|
|
|
194
194
|
INJECTED_PREFIXES = [
|
|
195
195
|
["<task-notification", "task-notification"],
|
|
196
196
|
["<agent-message", "peer"],
|
|
197
|
+
["<cross-session-message", "peer"],
|
|
198
|
+
["[Cross-session delivery notice]", "peer"],
|
|
197
199
|
["Another Claude session sent a message:", "peer"],
|
|
198
|
-
["Stop hook feedback:", "hook"]
|
|
200
|
+
["Stop hook feedback:", "hook"],
|
|
201
|
+
["<bash-stdout>", "command-output"],
|
|
202
|
+
["<bash-stderr>", "command-output"],
|
|
203
|
+
["<local-command-stdout>", "command-output"],
|
|
204
|
+
["<local-command-stderr>", "command-output"],
|
|
205
|
+
["<<autonomous-loop", "meta"]
|
|
199
206
|
];
|
|
200
207
|
}
|
|
201
208
|
});
|
|
@@ -6449,7 +6456,11 @@ __export(raw_exports, {
|
|
|
6449
6456
|
gzipContainer: () => gzipContainer,
|
|
6450
6457
|
mapContainerText: () => mapContainerText,
|
|
6451
6458
|
parseOpenCodeDumpText: () => parseOpenCodeDumpText,
|
|
6452
|
-
parseTranscriptFromContainer: () => parseTranscriptFromContainer
|
|
6459
|
+
parseTranscriptFromContainer: () => parseTranscriptFromContainer,
|
|
6460
|
+
redactContainer: () => redactContainer,
|
|
6461
|
+
redactJsonLine: () => redactJsonLine,
|
|
6462
|
+
repairContainer: () => repairContainer,
|
|
6463
|
+
repairRedactedJsonl: () => repairRedactedJsonl
|
|
6453
6464
|
});
|
|
6454
6465
|
import { gzipSync, gunzipSync } from "zlib";
|
|
6455
6466
|
import { createHash } from "crypto";
|
|
@@ -6490,6 +6501,134 @@ function gunzipContainer(gz) {
|
|
|
6490
6501
|
function mapContainerText(c, fn) {
|
|
6491
6502
|
return { ...c, files: c.files.map((f) => ({ name: f.name, text: fn(f.text) })) };
|
|
6492
6503
|
}
|
|
6504
|
+
function repairRedactedJsonl(text) {
|
|
6505
|
+
let repaired = 0;
|
|
6506
|
+
const parts = [];
|
|
6507
|
+
let copied = 0;
|
|
6508
|
+
let at = text.indexOf("[REDACTED:");
|
|
6509
|
+
while (at >= 0) {
|
|
6510
|
+
const start = text.lastIndexOf("\n", at) + 1;
|
|
6511
|
+
let end = text.indexOf("\n", at);
|
|
6512
|
+
if (end < 0)
|
|
6513
|
+
end = text.length;
|
|
6514
|
+
const fixed = repairLine(text.slice(start, end));
|
|
6515
|
+
if (fixed !== null) {
|
|
6516
|
+
parts.push(text.slice(copied, start), fixed);
|
|
6517
|
+
copied = end;
|
|
6518
|
+
repaired++;
|
|
6519
|
+
}
|
|
6520
|
+
at = text.indexOf("[REDACTED:", end);
|
|
6521
|
+
}
|
|
6522
|
+
if (repaired === 0)
|
|
6523
|
+
return { text, repaired: 0 };
|
|
6524
|
+
parts.push(text.slice(copied));
|
|
6525
|
+
return { text: parts.join(""), repaired };
|
|
6526
|
+
}
|
|
6527
|
+
function parseError(line) {
|
|
6528
|
+
try {
|
|
6529
|
+
JSON.parse(line);
|
|
6530
|
+
return null;
|
|
6531
|
+
} catch (e) {
|
|
6532
|
+
const m = /position (\d+)/.exec(e instanceof Error ? e.message : "");
|
|
6533
|
+
return m ? Number(m[1]) : line.length;
|
|
6534
|
+
}
|
|
6535
|
+
}
|
|
6536
|
+
function repairLine(line) {
|
|
6537
|
+
if (!line.includes("[REDACTED:") || parseError(line) === null)
|
|
6538
|
+
return null;
|
|
6539
|
+
let out = line.replace(/(?<!\\)((?:\\\\)*)\\(\[REDACTED:)/g, "$1$2");
|
|
6540
|
+
for (let attempt = 0; attempt < 64; attempt++) {
|
|
6541
|
+
const at = parseError(out);
|
|
6542
|
+
if (at === null)
|
|
6543
|
+
return out;
|
|
6544
|
+
let site = -1;
|
|
6545
|
+
for (const m of out.matchAll(MARKER_QUOTE)) {
|
|
6546
|
+
const q = m.index + m[0].length - 1;
|
|
6547
|
+
if (q < at)
|
|
6548
|
+
site = q;
|
|
6549
|
+
}
|
|
6550
|
+
if (site < 0)
|
|
6551
|
+
return null;
|
|
6552
|
+
out = out.slice(0, site) + "\\" + out.slice(site);
|
|
6553
|
+
}
|
|
6554
|
+
return null;
|
|
6555
|
+
}
|
|
6556
|
+
function redactJsonLine(line, redact) {
|
|
6557
|
+
if (!line.includes('"'))
|
|
6558
|
+
return redact(line);
|
|
6559
|
+
try {
|
|
6560
|
+
JSON.parse(line);
|
|
6561
|
+
} catch {
|
|
6562
|
+
return redact(line);
|
|
6563
|
+
}
|
|
6564
|
+
const decoded = mapJsonStrings(line, redact, true);
|
|
6565
|
+
const out = redact(decoded);
|
|
6566
|
+
try {
|
|
6567
|
+
JSON.parse(out);
|
|
6568
|
+
return out;
|
|
6569
|
+
} catch {
|
|
6570
|
+
return mapJsonStrings(decoded, redact, false);
|
|
6571
|
+
}
|
|
6572
|
+
}
|
|
6573
|
+
function mapJsonStrings(line, fn, escapedOnly) {
|
|
6574
|
+
let out = "";
|
|
6575
|
+
let i = 0;
|
|
6576
|
+
for (; ; ) {
|
|
6577
|
+
const q = line.indexOf('"', i);
|
|
6578
|
+
if (q < 0)
|
|
6579
|
+
return out + line.slice(i);
|
|
6580
|
+
let j = q + 1;
|
|
6581
|
+
while (j < line.length) {
|
|
6582
|
+
const c = line.charCodeAt(j);
|
|
6583
|
+
if (c === 92)
|
|
6584
|
+
j += 2;
|
|
6585
|
+
else if (c === 34)
|
|
6586
|
+
break;
|
|
6587
|
+
else
|
|
6588
|
+
j++;
|
|
6589
|
+
}
|
|
6590
|
+
const token = line.slice(q, j + 1);
|
|
6591
|
+
out += line.slice(i, q);
|
|
6592
|
+
i = j + 1;
|
|
6593
|
+
const body = token.slice(1, -1);
|
|
6594
|
+
const escaped = body.includes("\\");
|
|
6595
|
+
if (escapedOnly && !escaped) {
|
|
6596
|
+
out += token;
|
|
6597
|
+
continue;
|
|
6598
|
+
}
|
|
6599
|
+
let value = body;
|
|
6600
|
+
if (escaped) {
|
|
6601
|
+
try {
|
|
6602
|
+
value = JSON.parse(token);
|
|
6603
|
+
} catch {
|
|
6604
|
+
out += token;
|
|
6605
|
+
continue;
|
|
6606
|
+
}
|
|
6607
|
+
}
|
|
6608
|
+
const next = fn(value);
|
|
6609
|
+
out += next === value ? token : JSON.stringify(next);
|
|
6610
|
+
}
|
|
6611
|
+
}
|
|
6612
|
+
function redactContainer(c, redact) {
|
|
6613
|
+
return {
|
|
6614
|
+
...c,
|
|
6615
|
+
files: c.files.map((f) => ({
|
|
6616
|
+
name: f.name,
|
|
6617
|
+
text: f.name.endsWith(".jsonl") ? f.text.split("\n").map((l) => l ? redactJsonLine(l, redact) : l).join("\n") : redact(f.text)
|
|
6618
|
+
}))
|
|
6619
|
+
};
|
|
6620
|
+
}
|
|
6621
|
+
function repairContainer(c) {
|
|
6622
|
+
let repaired = 0;
|
|
6623
|
+
const files = c.files.map((f) => {
|
|
6624
|
+
if (!f.name.endsWith(".jsonl"))
|
|
6625
|
+
return f;
|
|
6626
|
+
const r = repairRedactedJsonl(f.text);
|
|
6627
|
+
repaired += r.repaired;
|
|
6628
|
+
return r.repaired > 0 ? { name: f.name, text: r.text } : f;
|
|
6629
|
+
});
|
|
6630
|
+
return repaired > 0 ? { container: { ...c, files }, repaired } : { container: c, repaired: 0 };
|
|
6631
|
+
}
|
|
6493
6632
|
function subagentKind(id) {
|
|
6494
6633
|
return id.includes("acompact") ? "compact" : id.includes("aside_question") ? "aside" : id.includes("explore") || /^agent-a[0-9a-f]{16,}$/i.test(id) ? "explore" : "other";
|
|
6495
6634
|
}
|
|
@@ -6660,6 +6799,7 @@ function requireFs() {
|
|
|
6660
6799
|
function requirePath() {
|
|
6661
6800
|
return pathMod;
|
|
6662
6801
|
}
|
|
6802
|
+
var MARKER_QUOTE;
|
|
6663
6803
|
var init_raw = __esm({
|
|
6664
6804
|
"../engine/dist/transcript/raw.js"() {
|
|
6665
6805
|
"use strict";
|
|
@@ -6667,6 +6807,7 @@ var init_raw = __esm({
|
|
|
6667
6807
|
init_claude();
|
|
6668
6808
|
init_codex();
|
|
6669
6809
|
init_from_events();
|
|
6810
|
+
MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
|
|
6670
6811
|
}
|
|
6671
6812
|
});
|
|
6672
6813
|
|
|
@@ -7316,7 +7457,7 @@ function markersFromTurns(sessionId, turns) {
|
|
|
7316
7457
|
const prompts = turns.filter((t) => t.kind === "user" && t.text).map((t) => ({ line: t.line, ts: t.ts, tsIso: t.tsIso, ...markPrompt(t.text) }));
|
|
7317
7458
|
return { v: MARKERS_VERSION, sessionId, prompts, summary: summarizeMarkers(prompts) };
|
|
7318
7459
|
}
|
|
7319
|
-
var PROFANITY, PROFANITY_LOOSE, APPROVAL_HEAD, NEG_HEAD, QUESTION_HEAD, DIRECTIVE_HEAD, CLARIFY_PHRASES, FRUSTRATED_PHRASES, MARKERS_VERSION;
|
|
7460
|
+
var PROFANITY, PROFANITY_LOOSE, APPROVAL_HEAD, NEG_HEAD, QUESTION_HEAD, DIRECTIVE_HEAD, CLARIFY_PHRASES, FRUSTRATED_PHRASES, MARKERS_VERSION, MARKERS_TURN_OPTS;
|
|
7320
7461
|
var init_session_sentiment = __esm({
|
|
7321
7462
|
"../engine/dist/core/session-sentiment.js"() {
|
|
7322
7463
|
"use strict";
|
|
@@ -7329,7 +7470,8 @@ var init_session_sentiment = __esm({
|
|
|
7329
7470
|
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;
|
|
7330
7471
|
CLARIFY_PHRASES = /\b(?:wdym|what do you mean|explain|clarify|what is|what's|huh\??|i don'?t understand)\b/i;
|
|
7331
7472
|
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;
|
|
7332
|
-
MARKERS_VERSION =
|
|
7473
|
+
MARKERS_VERSION = 3;
|
|
7474
|
+
MARKERS_TURN_OPTS = { maxTurns: 5e4, userMax: Number.POSITIVE_INFINITY };
|
|
7333
7475
|
}
|
|
7334
7476
|
});
|
|
7335
7477
|
|
|
@@ -7505,7 +7647,7 @@ function extractTurnsAny(sessionId, opts = {}) {
|
|
|
7505
7647
|
const backend = getBackendForId(sessionId);
|
|
7506
7648
|
if (!backend)
|
|
7507
7649
|
return { sessionId, found: false, turns: [], startMs: 0, endMs: 0 };
|
|
7508
|
-
return memoInSessionScope(`turns:${sessionId}:${opts.maxTurns ?? ""}:${opts.assistantMax ?? ""}`, () => backend.extractTurns(sessionId, opts));
|
|
7650
|
+
return memoInSessionScope(`turns:${sessionId}:${opts.maxTurns ?? ""}:${opts.assistantMax ?? ""}:${opts.userMax ?? ""}`, () => backend.extractTurns(sessionId, opts));
|
|
7509
7651
|
}
|
|
7510
7652
|
function replaySessionAny(sessionId) {
|
|
7511
7653
|
const backend = getBackendForId(sessionId);
|
|
@@ -7913,6 +8055,7 @@ function shorten(text, max) {
|
|
|
7913
8055
|
function extractTurnsFromEvents(sessionId, events, opts = {}) {
|
|
7914
8056
|
const maxTurns = opts.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
7915
8057
|
const assistantMax = opts.assistantMax ?? DEFAULT_ASSISTANT_MAX;
|
|
8058
|
+
const userMax = opts.userMax ?? DEFAULT_USER_MAX;
|
|
7916
8059
|
const turns = [];
|
|
7917
8060
|
let startMs = 0, endMs = 0;
|
|
7918
8061
|
let found = false;
|
|
@@ -7930,7 +8073,7 @@ function extractTurnsFromEvents(sessionId, events, opts = {}) {
|
|
|
7930
8073
|
ts: e.ts,
|
|
7931
8074
|
tsIso: e.tsIso,
|
|
7932
8075
|
line: e.line,
|
|
7933
|
-
text: shorten(e.text,
|
|
8076
|
+
text: shorten(e.text, userMax)
|
|
7934
8077
|
});
|
|
7935
8078
|
} else if (e.kind === "assistant_text" && e.text) {
|
|
7936
8079
|
turns.push({
|
|
@@ -12163,7 +12306,13 @@ function redactSecrets(text, opts = {}) {
|
|
|
12163
12306
|
return whole;
|
|
12164
12307
|
if (opts.count)
|
|
12165
12308
|
opts.count.redactions++;
|
|
12166
|
-
|
|
12309
|
+
let last = args.length - 1;
|
|
12310
|
+
if (typeof args[last] === "object")
|
|
12311
|
+
last--;
|
|
12312
|
+
const source = args[last];
|
|
12313
|
+
const secretStart = args[last - 1] + whole.length - secret.length;
|
|
12314
|
+
const head = escapeHead(source, secretStart, secret.length);
|
|
12315
|
+
return whole.slice(0, whole.length - secret.length + head) + `[REDACTED:${r.label}]` + escapeKept(whole, whole.length);
|
|
12167
12316
|
});
|
|
12168
12317
|
}
|
|
12169
12318
|
const ctx = findContextualSecrets(out);
|
|
@@ -12171,10 +12320,25 @@ function redactSecrets(text, opts = {}) {
|
|
|
12171
12320
|
const { start, end } = ctx[i];
|
|
12172
12321
|
if (opts.count)
|
|
12173
12322
|
opts.count.redactions++;
|
|
12174
|
-
|
|
12323
|
+
const head = escapeHead(out, start, end - start);
|
|
12324
|
+
out = out.slice(0, start + head) + "[REDACTED:secret-context]" + escapeKept(out, end) + out.slice(end);
|
|
12175
12325
|
}
|
|
12176
12326
|
return out;
|
|
12177
12327
|
}
|
|
12328
|
+
function escapeKept(text, end) {
|
|
12329
|
+
let run = 0;
|
|
12330
|
+
while (run < end && text.charCodeAt(end - 1 - run) === 92)
|
|
12331
|
+
run++;
|
|
12332
|
+
return run % 2 === 1 ? "\\" : "";
|
|
12333
|
+
}
|
|
12334
|
+
function escapeHead(text, start, length) {
|
|
12335
|
+
let run = 0;
|
|
12336
|
+
while (run < start && text.charCodeAt(start - 1 - run) === 92)
|
|
12337
|
+
run++;
|
|
12338
|
+
if (run % 2 === 0)
|
|
12339
|
+
return 0;
|
|
12340
|
+
return Math.min(text[start] === "u" ? 5 : 1, length);
|
|
12341
|
+
}
|
|
12178
12342
|
function maskSecret(s) {
|
|
12179
12343
|
if (!s)
|
|
12180
12344
|
return "";
|
|
@@ -12281,7 +12445,12 @@ var init_secret_redactor = __esm({
|
|
|
12281
12445
|
// userinfo URL walked through in cleartext — and a `jdbc:postgresql://…`
|
|
12282
12446
|
// prefix broke the \b anchor for the one family it did cover. Any scheme
|
|
12283
12447
|
// followed by userinfo is a credential, so match the shape, not a list.
|
|
12284
|
-
|
|
12448
|
+
//
|
|
12449
|
+
// A quote in userinfo is percent-encoded, so neither part takes a `"`. The
|
|
12450
|
+
// sync redacts JSONL text, and a match that ran on through `","is_error":`
|
|
12451
|
+
// to a later `@` replaced JSON structure: 4 lines on one machine stopped
|
|
12452
|
+
// parsing, and their records were dropped.
|
|
12453
|
+
{ label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/"]{1,64}:([^@\s/"]{1,256})(?=@)/g },
|
|
12285
12454
|
// Bare AWS secret-access-key VALUE: EXACTLY 40 base64 chars, word-bounded,
|
|
12286
12455
|
// containing upper+lower+digit. This is the gitleaks heuristic — the mixed-case
|
|
12287
12456
|
// requirement excludes 40-char lowercase-hex git SHAs, and the exact-40 bound
|
|
@@ -13315,6 +13484,10 @@ __export(transcript_exports, {
|
|
|
13315
13484
|
parseTranscript: () => parseTranscript,
|
|
13316
13485
|
parseTranscriptFromContainer: () => parseTranscriptFromContainer,
|
|
13317
13486
|
readShadowContainer: () => readShadowContainer,
|
|
13487
|
+
redactContainer: () => redactContainer,
|
|
13488
|
+
redactJsonLine: () => redactJsonLine,
|
|
13489
|
+
repairContainer: () => repairContainer,
|
|
13490
|
+
repairRedactedJsonl: () => repairRedactedJsonl,
|
|
13318
13491
|
seedShadow: () => seedShadow,
|
|
13319
13492
|
shadowFileFor: () => shadowFileFor,
|
|
13320
13493
|
shadowRoot: () => shadowRoot,
|
|
@@ -18312,7 +18485,7 @@ var init_http = __esm({
|
|
|
18312
18485
|
CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
18313
18486
|
} catch {
|
|
18314
18487
|
try {
|
|
18315
|
-
if (true) CLI_VERSION = "0.7.
|
|
18488
|
+
if (true) CLI_VERSION = "0.7.13";
|
|
18316
18489
|
} catch {
|
|
18317
18490
|
}
|
|
18318
18491
|
}
|
|
@@ -18356,7 +18529,7 @@ function collectDerivedRows(ref, mtime, count, maxRowBytes) {
|
|
|
18356
18529
|
if (!fullOutcome) fullOutcome = computeOutcome(id);
|
|
18357
18530
|
if (fullOutcome.found) data = fullOutcome.commits;
|
|
18358
18531
|
} else if (kind === "markers") {
|
|
18359
|
-
const turns = extractTurnsAny(id,
|
|
18532
|
+
const turns = extractTurnsAny(id, MARKERS_TURN_OPTS);
|
|
18360
18533
|
data = markersFromTurns(id, turns.turns);
|
|
18361
18534
|
}
|
|
18362
18535
|
} catch {
|
|
@@ -18806,7 +18979,7 @@ var init_telemetry = __esm({
|
|
|
18806
18979
|
init_sync_client();
|
|
18807
18980
|
cliVersion = () => {
|
|
18808
18981
|
try {
|
|
18809
|
-
return true ? "0.7.
|
|
18982
|
+
return true ? "0.7.13" : "dev";
|
|
18810
18983
|
} catch {
|
|
18811
18984
|
return "dev";
|
|
18812
18985
|
}
|
|
@@ -20739,7 +20912,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
20739
20912
|
} else {
|
|
20740
20913
|
try {
|
|
20741
20914
|
const count2 = { redactions: 0 };
|
|
20742
|
-
const redacted =
|
|
20915
|
+
const redacted = redactContainer(container, (t) => redactSecrets(t, { force: true, count: count2 }));
|
|
20743
20916
|
count.redactions += count2.redactions;
|
|
20744
20917
|
const { gz, size } = gzipContainer(redacted);
|
|
20745
20918
|
if (gz.length <= 8 * 1024 * 1024) {
|
|
@@ -20939,7 +21112,7 @@ var init_sync_client = __esm({
|
|
|
20939
21112
|
ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
20940
21113
|
} catch {
|
|
20941
21114
|
try {
|
|
20942
|
-
if (true) ownVersion = "0.7.
|
|
21115
|
+
if (true) ownVersion = "0.7.13";
|
|
20943
21116
|
} catch {
|
|
20944
21117
|
}
|
|
20945
21118
|
}
|
|
@@ -24076,7 +24249,7 @@ try {
|
|
|
24076
24249
|
ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
24077
24250
|
} catch {
|
|
24078
24251
|
try {
|
|
24079
|
-
if (true) ownVersion2 = "0.7.
|
|
24252
|
+
if (true) ownVersion2 = "0.7.13";
|
|
24080
24253
|
} catch {
|
|
24081
24254
|
}
|
|
24082
24255
|
}
|
|
@@ -24461,7 +24634,7 @@ async function runCollectorMigration(opts) {
|
|
|
24461
24634
|
init_sync_ledger();
|
|
24462
24635
|
init_collector_health();
|
|
24463
24636
|
import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync45 } from "fs";
|
|
24464
|
-
var CLI_VERSION3 = true ? "0.7.
|
|
24637
|
+
var CLI_VERSION3 = true ? "0.7.13" : "0.0.0";
|
|
24465
24638
|
var DEBOUNCE_MS = 5e3;
|
|
24466
24639
|
var PLANS_DIR = claudeBackend.plansDir();
|
|
24467
24640
|
var TASKS_DIR = claudeBackend.tasksDir();
|