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/derived.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { withSessionReadCache } from '@chat-recall/engine/core/live-session-scan.js';
|
|
23
23
|
import { replaySessionAny, extractTurnsAny } from '@chat-recall/engine/core/session-multi-tool.js';
|
|
24
24
|
import { computeOutcome } from '@chat-recall/engine/core/session-outcome.js';
|
|
25
|
-
import { markersFromTurns } from '@chat-recall/engine/core/session-sentiment.js';
|
|
25
|
+
import { markersFromTurns, MARKERS_TURN_OPTS } from '@chat-recall/engine/core/session-sentiment.js';
|
|
26
26
|
import { redactDeep } from './redact-deep.js';
|
|
27
27
|
/** Which compute rows a session ships. */
|
|
28
28
|
export const COMPUTE_KINDS = ['diff', 'outcome', 'commits', 'markers'];
|
|
@@ -57,7 +57,7 @@ export function collectDerivedRows(ref, mtime, count, maxRowBytes) {
|
|
|
57
57
|
else if (kind === 'markers') {
|
|
58
58
|
// Analysis-only use of the turns extractor (R4) — markers need
|
|
59
59
|
// per-prompt line/ts, not render fidelity.
|
|
60
|
-
const turns = extractTurnsAny(id,
|
|
60
|
+
const turns = extractTurnsAny(id, MARKERS_TURN_OPTS);
|
|
61
61
|
data = markersFromTurns(id, turns.turns);
|
|
62
62
|
}
|
|
63
63
|
}
|
package/dist/derived.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derived.js","sourceRoot":"","sources":["../src/derived.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,oBAAoB,EAAE,MAAM,+CAA+C,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gDAAgD,CAAC;AACnG,OAAO,EAAE,cAAc,EAAE,MAAM,6CAA6C,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;
|
|
1
|
+
{"version":3,"file":"derived.js","sourceRoot":"","sources":["../src/derived.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp-relay.js
CHANGED
|
@@ -192,7 +192,7 @@ function bridge(input, output, sock, exit, opts = {}) {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
// src/mcp-relay.ts
|
|
195
|
-
var VERSION = true ? "0.7.
|
|
195
|
+
var VERSION = true ? "0.7.13" : "0.0.0";
|
|
196
196
|
var SERVER_URL = new URL("./mcp.js", import.meta.url);
|
|
197
197
|
var SERVER_PATH = fileURLToPath(SERVER_URL);
|
|
198
198
|
var START_TIMEOUT_MS = 15e3;
|
package/dist/mcp.js
CHANGED
|
@@ -5065,8 +5065,15 @@ var init_claude_prompt_origin = __esm({
|
|
|
5065
5065
|
INJECTED_PREFIXES = [
|
|
5066
5066
|
["<task-notification", "task-notification"],
|
|
5067
5067
|
["<agent-message", "peer"],
|
|
5068
|
+
["<cross-session-message", "peer"],
|
|
5069
|
+
["[Cross-session delivery notice]", "peer"],
|
|
5068
5070
|
["Another Claude session sent a message:", "peer"],
|
|
5069
|
-
["Stop hook feedback:", "hook"]
|
|
5071
|
+
["Stop hook feedback:", "hook"],
|
|
5072
|
+
["<bash-stdout>", "command-output"],
|
|
5073
|
+
["<bash-stderr>", "command-output"],
|
|
5074
|
+
["<local-command-stdout>", "command-output"],
|
|
5075
|
+
["<local-command-stderr>", "command-output"],
|
|
5076
|
+
["<<autonomous-loop", "meta"]
|
|
5070
5077
|
];
|
|
5071
5078
|
}
|
|
5072
5079
|
});
|
|
@@ -6028,7 +6035,7 @@ function markersFromTurns(sessionId, turns) {
|
|
|
6028
6035
|
const prompts = turns.filter((t) => t.kind === "user" && t.text).map((t) => ({ line: t.line, ts: t.ts, tsIso: t.tsIso, ...markPrompt(t.text) }));
|
|
6029
6036
|
return { v: MARKERS_VERSION, sessionId, prompts, summary: summarizeMarkers(prompts) };
|
|
6030
6037
|
}
|
|
6031
|
-
var PROFANITY, PROFANITY_LOOSE, APPROVAL_HEAD, NEG_HEAD, QUESTION_HEAD, DIRECTIVE_HEAD, CLARIFY_PHRASES, FRUSTRATED_PHRASES, MARKERS_VERSION;
|
|
6038
|
+
var PROFANITY, PROFANITY_LOOSE, APPROVAL_HEAD, NEG_HEAD, QUESTION_HEAD, DIRECTIVE_HEAD, CLARIFY_PHRASES, FRUSTRATED_PHRASES, MARKERS_VERSION, MARKERS_TURN_OPTS;
|
|
6032
6039
|
var init_session_sentiment = __esm({
|
|
6033
6040
|
"../engine/dist/core/session-sentiment.js"() {
|
|
6034
6041
|
"use strict";
|
|
@@ -6041,7 +6048,8 @@ var init_session_sentiment = __esm({
|
|
|
6041
6048
|
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;
|
|
6042
6049
|
CLARIFY_PHRASES = /\b(?:wdym|what do you mean|explain|clarify|what is|what's|huh\??|i don'?t understand)\b/i;
|
|
6043
6050
|
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;
|
|
6044
|
-
MARKERS_VERSION =
|
|
6051
|
+
MARKERS_VERSION = 3;
|
|
6052
|
+
MARKERS_TURN_OPTS = { maxTurns: 5e4, userMax: Number.POSITIVE_INFINITY };
|
|
6045
6053
|
}
|
|
6046
6054
|
});
|
|
6047
6055
|
|
|
@@ -6267,6 +6275,7 @@ function shorten(text, max) {
|
|
|
6267
6275
|
function extractTurnsFromEvents(sessionId, events, opts = {}) {
|
|
6268
6276
|
const maxTurns = opts.maxTurns ?? DEFAULT_MAX_TURNS;
|
|
6269
6277
|
const assistantMax = opts.assistantMax ?? DEFAULT_ASSISTANT_MAX;
|
|
6278
|
+
const userMax = opts.userMax ?? DEFAULT_USER_MAX;
|
|
6270
6279
|
const turns = [];
|
|
6271
6280
|
let startMs = 0, endMs = 0;
|
|
6272
6281
|
let found = false;
|
|
@@ -6284,7 +6293,7 @@ function extractTurnsFromEvents(sessionId, events, opts = {}) {
|
|
|
6284
6293
|
ts: e.ts,
|
|
6285
6294
|
tsIso: e.tsIso,
|
|
6286
6295
|
line: e.line,
|
|
6287
|
-
text: shorten(e.text,
|
|
6296
|
+
text: shorten(e.text, userMax)
|
|
6288
6297
|
});
|
|
6289
6298
|
} else if (e.kind === "assistant_text" && e.text) {
|
|
6290
6299
|
turns.push({
|
|
@@ -9648,7 +9657,7 @@ function extractTurnsAny(sessionId, opts = {}) {
|
|
|
9648
9657
|
const backend = getBackendForId(sessionId);
|
|
9649
9658
|
if (!backend)
|
|
9650
9659
|
return { sessionId, found: false, turns: [], startMs: 0, endMs: 0 };
|
|
9651
|
-
return memoInSessionScope(`turns:${sessionId}:${opts.maxTurns ?? ""}:${opts.assistantMax ?? ""}`, () => backend.extractTurns(sessionId, opts));
|
|
9660
|
+
return memoInSessionScope(`turns:${sessionId}:${opts.maxTurns ?? ""}:${opts.assistantMax ?? ""}:${opts.userMax ?? ""}`, () => backend.extractTurns(sessionId, opts));
|
|
9652
9661
|
}
|
|
9653
9662
|
function replaySessionAny(sessionId) {
|
|
9654
9663
|
const backend = getBackendForId(sessionId);
|
|
@@ -11619,7 +11628,11 @@ __export(raw_exports, {
|
|
|
11619
11628
|
gzipContainer: () => gzipContainer,
|
|
11620
11629
|
mapContainerText: () => mapContainerText,
|
|
11621
11630
|
parseOpenCodeDumpText: () => parseOpenCodeDumpText,
|
|
11622
|
-
parseTranscriptFromContainer: () => parseTranscriptFromContainer
|
|
11631
|
+
parseTranscriptFromContainer: () => parseTranscriptFromContainer,
|
|
11632
|
+
redactContainer: () => redactContainer,
|
|
11633
|
+
redactJsonLine: () => redactJsonLine,
|
|
11634
|
+
repairContainer: () => repairContainer,
|
|
11635
|
+
repairRedactedJsonl: () => repairRedactedJsonl
|
|
11623
11636
|
});
|
|
11624
11637
|
import { gzipSync, gunzipSync } from "zlib";
|
|
11625
11638
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -11660,6 +11673,134 @@ function gunzipContainer(gz) {
|
|
|
11660
11673
|
function mapContainerText(c, fn) {
|
|
11661
11674
|
return { ...c, files: c.files.map((f) => ({ name: f.name, text: fn(f.text) })) };
|
|
11662
11675
|
}
|
|
11676
|
+
function repairRedactedJsonl(text) {
|
|
11677
|
+
let repaired = 0;
|
|
11678
|
+
const parts = [];
|
|
11679
|
+
let copied = 0;
|
|
11680
|
+
let at = text.indexOf("[REDACTED:");
|
|
11681
|
+
while (at >= 0) {
|
|
11682
|
+
const start = text.lastIndexOf("\n", at) + 1;
|
|
11683
|
+
let end = text.indexOf("\n", at);
|
|
11684
|
+
if (end < 0)
|
|
11685
|
+
end = text.length;
|
|
11686
|
+
const fixed = repairLine(text.slice(start, end));
|
|
11687
|
+
if (fixed !== null) {
|
|
11688
|
+
parts.push(text.slice(copied, start), fixed);
|
|
11689
|
+
copied = end;
|
|
11690
|
+
repaired++;
|
|
11691
|
+
}
|
|
11692
|
+
at = text.indexOf("[REDACTED:", end);
|
|
11693
|
+
}
|
|
11694
|
+
if (repaired === 0)
|
|
11695
|
+
return { text, repaired: 0 };
|
|
11696
|
+
parts.push(text.slice(copied));
|
|
11697
|
+
return { text: parts.join(""), repaired };
|
|
11698
|
+
}
|
|
11699
|
+
function parseError(line) {
|
|
11700
|
+
try {
|
|
11701
|
+
JSON.parse(line);
|
|
11702
|
+
return null;
|
|
11703
|
+
} catch (e) {
|
|
11704
|
+
const m = /position (\d+)/.exec(e instanceof Error ? e.message : "");
|
|
11705
|
+
return m ? Number(m[1]) : line.length;
|
|
11706
|
+
}
|
|
11707
|
+
}
|
|
11708
|
+
function repairLine(line) {
|
|
11709
|
+
if (!line.includes("[REDACTED:") || parseError(line) === null)
|
|
11710
|
+
return null;
|
|
11711
|
+
let out = line.replace(/(?<!\\)((?:\\\\)*)\\(\[REDACTED:)/g, "$1$2");
|
|
11712
|
+
for (let attempt = 0; attempt < 64; attempt++) {
|
|
11713
|
+
const at = parseError(out);
|
|
11714
|
+
if (at === null)
|
|
11715
|
+
return out;
|
|
11716
|
+
let site = -1;
|
|
11717
|
+
for (const m of out.matchAll(MARKER_QUOTE)) {
|
|
11718
|
+
const q = m.index + m[0].length - 1;
|
|
11719
|
+
if (q < at)
|
|
11720
|
+
site = q;
|
|
11721
|
+
}
|
|
11722
|
+
if (site < 0)
|
|
11723
|
+
return null;
|
|
11724
|
+
out = out.slice(0, site) + "\\" + out.slice(site);
|
|
11725
|
+
}
|
|
11726
|
+
return null;
|
|
11727
|
+
}
|
|
11728
|
+
function redactJsonLine(line, redact) {
|
|
11729
|
+
if (!line.includes('"'))
|
|
11730
|
+
return redact(line);
|
|
11731
|
+
try {
|
|
11732
|
+
JSON.parse(line);
|
|
11733
|
+
} catch {
|
|
11734
|
+
return redact(line);
|
|
11735
|
+
}
|
|
11736
|
+
const decoded = mapJsonStrings(line, redact, true);
|
|
11737
|
+
const out = redact(decoded);
|
|
11738
|
+
try {
|
|
11739
|
+
JSON.parse(out);
|
|
11740
|
+
return out;
|
|
11741
|
+
} catch {
|
|
11742
|
+
return mapJsonStrings(decoded, redact, false);
|
|
11743
|
+
}
|
|
11744
|
+
}
|
|
11745
|
+
function mapJsonStrings(line, fn, escapedOnly) {
|
|
11746
|
+
let out = "";
|
|
11747
|
+
let i = 0;
|
|
11748
|
+
for (; ; ) {
|
|
11749
|
+
const q = line.indexOf('"', i);
|
|
11750
|
+
if (q < 0)
|
|
11751
|
+
return out + line.slice(i);
|
|
11752
|
+
let j = q + 1;
|
|
11753
|
+
while (j < line.length) {
|
|
11754
|
+
const c = line.charCodeAt(j);
|
|
11755
|
+
if (c === 92)
|
|
11756
|
+
j += 2;
|
|
11757
|
+
else if (c === 34)
|
|
11758
|
+
break;
|
|
11759
|
+
else
|
|
11760
|
+
j++;
|
|
11761
|
+
}
|
|
11762
|
+
const token = line.slice(q, j + 1);
|
|
11763
|
+
out += line.slice(i, q);
|
|
11764
|
+
i = j + 1;
|
|
11765
|
+
const body2 = token.slice(1, -1);
|
|
11766
|
+
const escaped = body2.includes("\\");
|
|
11767
|
+
if (escapedOnly && !escaped) {
|
|
11768
|
+
out += token;
|
|
11769
|
+
continue;
|
|
11770
|
+
}
|
|
11771
|
+
let value = body2;
|
|
11772
|
+
if (escaped) {
|
|
11773
|
+
try {
|
|
11774
|
+
value = JSON.parse(token);
|
|
11775
|
+
} catch {
|
|
11776
|
+
out += token;
|
|
11777
|
+
continue;
|
|
11778
|
+
}
|
|
11779
|
+
}
|
|
11780
|
+
const next = fn(value);
|
|
11781
|
+
out += next === value ? token : JSON.stringify(next);
|
|
11782
|
+
}
|
|
11783
|
+
}
|
|
11784
|
+
function redactContainer(c, redact) {
|
|
11785
|
+
return {
|
|
11786
|
+
...c,
|
|
11787
|
+
files: c.files.map((f) => ({
|
|
11788
|
+
name: f.name,
|
|
11789
|
+
text: f.name.endsWith(".jsonl") ? f.text.split("\n").map((l) => l ? redactJsonLine(l, redact) : l).join("\n") : redact(f.text)
|
|
11790
|
+
}))
|
|
11791
|
+
};
|
|
11792
|
+
}
|
|
11793
|
+
function repairContainer(c) {
|
|
11794
|
+
let repaired = 0;
|
|
11795
|
+
const files = c.files.map((f) => {
|
|
11796
|
+
if (!f.name.endsWith(".jsonl"))
|
|
11797
|
+
return f;
|
|
11798
|
+
const r = repairRedactedJsonl(f.text);
|
|
11799
|
+
repaired += r.repaired;
|
|
11800
|
+
return r.repaired > 0 ? { name: f.name, text: r.text } : f;
|
|
11801
|
+
});
|
|
11802
|
+
return repaired > 0 ? { container: { ...c, files }, repaired } : { container: c, repaired: 0 };
|
|
11803
|
+
}
|
|
11663
11804
|
function subagentKind(id) {
|
|
11664
11805
|
return id.includes("acompact") ? "compact" : id.includes("aside_question") ? "aside" : id.includes("explore") || /^agent-a[0-9a-f]{16,}$/i.test(id) ? "explore" : "other";
|
|
11665
11806
|
}
|
|
@@ -11830,6 +11971,7 @@ function requireFs() {
|
|
|
11830
11971
|
function requirePath() {
|
|
11831
11972
|
return pathMod;
|
|
11832
11973
|
}
|
|
11974
|
+
var MARKER_QUOTE;
|
|
11833
11975
|
var init_raw = __esm({
|
|
11834
11976
|
"../engine/dist/transcript/raw.js"() {
|
|
11835
11977
|
"use strict";
|
|
@@ -11837,6 +11979,7 @@ var init_raw = __esm({
|
|
|
11837
11979
|
init_claude2();
|
|
11838
11980
|
init_codex2();
|
|
11839
11981
|
init_from_events();
|
|
11982
|
+
MARKER_QUOTE = /\[REDACTED:[A-Za-z0-9_-]+\]"/g;
|
|
11840
11983
|
}
|
|
11841
11984
|
});
|
|
11842
11985
|
|
|
@@ -12797,9 +12940,9 @@ function judgeHealth(h, now = Date.now()) {
|
|
|
12797
12940
|
return (a.t.lastOkAt ?? 0) - (b.t.lastOkAt ?? 0);
|
|
12798
12941
|
});
|
|
12799
12942
|
const worst = ranked[0];
|
|
12800
|
-
const
|
|
12943
|
+
const when2 = worst.t.lastOkAt ? `${ago(now - worst.t.lastOkAt)} ago` : "never";
|
|
12801
12944
|
const why = worst.t.lastError ? ` (${worst.t.lastError})` : "";
|
|
12802
|
-
reasons.push(`nothing has synced since ${
|
|
12945
|
+
reasons.push(`nothing has synced since ${when2}${why}`);
|
|
12803
12946
|
}
|
|
12804
12947
|
if (reasons.length === 0)
|
|
12805
12948
|
return { ok: true, summary: null, reasons: [] };
|
|
@@ -13173,7 +13316,13 @@ function redactSecrets(text, opts = {}) {
|
|
|
13173
13316
|
return whole;
|
|
13174
13317
|
if (opts.count)
|
|
13175
13318
|
opts.count.redactions++;
|
|
13176
|
-
|
|
13319
|
+
let last = args.length - 1;
|
|
13320
|
+
if (typeof args[last] === "object")
|
|
13321
|
+
last--;
|
|
13322
|
+
const source = args[last];
|
|
13323
|
+
const secretStart = args[last - 1] + whole.length - secret.length;
|
|
13324
|
+
const head = escapeHead(source, secretStart, secret.length);
|
|
13325
|
+
return whole.slice(0, whole.length - secret.length + head) + `[REDACTED:${r.label}]` + escapeKept(whole, whole.length);
|
|
13177
13326
|
});
|
|
13178
13327
|
}
|
|
13179
13328
|
const ctx = findContextualSecrets(out);
|
|
@@ -13181,10 +13330,25 @@ function redactSecrets(text, opts = {}) {
|
|
|
13181
13330
|
const { start, end } = ctx[i];
|
|
13182
13331
|
if (opts.count)
|
|
13183
13332
|
opts.count.redactions++;
|
|
13184
|
-
|
|
13333
|
+
const head = escapeHead(out, start, end - start);
|
|
13334
|
+
out = out.slice(0, start + head) + "[REDACTED:secret-context]" + escapeKept(out, end) + out.slice(end);
|
|
13185
13335
|
}
|
|
13186
13336
|
return out;
|
|
13187
13337
|
}
|
|
13338
|
+
function escapeKept(text, end) {
|
|
13339
|
+
let run = 0;
|
|
13340
|
+
while (run < end && text.charCodeAt(end - 1 - run) === 92)
|
|
13341
|
+
run++;
|
|
13342
|
+
return run % 2 === 1 ? "\\" : "";
|
|
13343
|
+
}
|
|
13344
|
+
function escapeHead(text, start, length) {
|
|
13345
|
+
let run = 0;
|
|
13346
|
+
while (run < start && text.charCodeAt(start - 1 - run) === 92)
|
|
13347
|
+
run++;
|
|
13348
|
+
if (run % 2 === 0)
|
|
13349
|
+
return 0;
|
|
13350
|
+
return Math.min(text[start] === "u" ? 5 : 1, length);
|
|
13351
|
+
}
|
|
13188
13352
|
function maskSecret(s) {
|
|
13189
13353
|
if (!s)
|
|
13190
13354
|
return "";
|
|
@@ -13291,7 +13455,12 @@ var init_secret_redactor = __esm({
|
|
|
13291
13455
|
// userinfo URL walked through in cleartext — and a `jdbc:postgresql://…`
|
|
13292
13456
|
// prefix broke the \b anchor for the one family it did cover. Any scheme
|
|
13293
13457
|
// followed by userinfo is a credential, so match the shape, not a list.
|
|
13294
|
-
|
|
13458
|
+
//
|
|
13459
|
+
// A quote in userinfo is percent-encoded, so neither part takes a `"`. The
|
|
13460
|
+
// sync redacts JSONL text, and a match that ran on through `","is_error":`
|
|
13461
|
+
// to a later `@` replaced JSON structure: 4 lines on one machine stopped
|
|
13462
|
+
// parsing, and their records were dropped.
|
|
13463
|
+
{ label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/"]{1,64}:([^@\s/"]{1,256})(?=@)/g },
|
|
13295
13464
|
// Bare AWS secret-access-key VALUE: EXACTLY 40 base64 chars, word-bounded,
|
|
13296
13465
|
// containing upper+lower+digit. This is the gitleaks heuristic — the mixed-case
|
|
13297
13466
|
// requirement excludes 40-char lowercase-hex git SHAs, and the exact-40 bound
|
|
@@ -19677,7 +19846,7 @@ var init_http = __esm({
|
|
|
19677
19846
|
CLI_VERSION = JSON.parse(readFileSync36(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19678
19847
|
} catch {
|
|
19679
19848
|
try {
|
|
19680
|
-
if (true) CLI_VERSION = "0.7.
|
|
19849
|
+
if (true) CLI_VERSION = "0.7.13";
|
|
19681
19850
|
} catch {
|
|
19682
19851
|
}
|
|
19683
19852
|
}
|
|
@@ -19721,7 +19890,7 @@ function collectDerivedRows(ref, mtime, count, maxRowBytes) {
|
|
|
19721
19890
|
if (!fullOutcome) fullOutcome = computeOutcome(id);
|
|
19722
19891
|
if (fullOutcome.found) data = fullOutcome.commits;
|
|
19723
19892
|
} else if (kind === "markers") {
|
|
19724
|
-
const turns = extractTurnsAny(id,
|
|
19893
|
+
const turns = extractTurnsAny(id, MARKERS_TURN_OPTS);
|
|
19725
19894
|
data = markersFromTurns(id, turns.turns);
|
|
19726
19895
|
}
|
|
19727
19896
|
} catch {
|
|
@@ -20175,7 +20344,7 @@ var init_telemetry = __esm({
|
|
|
20175
20344
|
init_sync_client();
|
|
20176
20345
|
cliVersion2 = () => {
|
|
20177
20346
|
try {
|
|
20178
|
-
return true ? "0.7.
|
|
20347
|
+
return true ? "0.7.13" : "dev";
|
|
20179
20348
|
} catch {
|
|
20180
20349
|
return "dev";
|
|
20181
20350
|
}
|
|
@@ -22138,7 +22307,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
22138
22307
|
} else {
|
|
22139
22308
|
try {
|
|
22140
22309
|
const count2 = { redactions: 0 };
|
|
22141
|
-
const redacted =
|
|
22310
|
+
const redacted = redactContainer(container, (t) => redactSecrets(t, { force: true, count: count2 }));
|
|
22142
22311
|
count.redactions += count2.redactions;
|
|
22143
22312
|
const { gz, size } = gzipContainer(redacted);
|
|
22144
22313
|
if (gz.length <= 8 * 1024 * 1024) {
|
|
@@ -22338,7 +22507,7 @@ var init_sync_client = __esm({
|
|
|
22338
22507
|
ownVersion = JSON.parse(readFileSync38(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22339
22508
|
} catch {
|
|
22340
22509
|
try {
|
|
22341
|
-
if (true) ownVersion = "0.7.
|
|
22510
|
+
if (true) ownVersion = "0.7.13";
|
|
22342
22511
|
} catch {
|
|
22343
22512
|
}
|
|
22344
22513
|
}
|
|
@@ -23815,8 +23984,8 @@ function formatDigest(input, summaryChars = 400) {
|
|
|
23815
23984
|
const { row, outcome, related, resumeCmd } = input;
|
|
23816
23985
|
const lines = [];
|
|
23817
23986
|
lines.push(`### ${digestTitle(row)}`);
|
|
23818
|
-
const
|
|
23819
|
-
lines.push(`**Project:** ${projectName(row.projectPath) || "(unknown)"} \xB7 **Tool:** ${row.tool || "claude"}` + (
|
|
23987
|
+
const when2 = (row.modified || "").slice(0, 16).replace("T", " ");
|
|
23988
|
+
lines.push(`**Project:** ${projectName(row.projectPath) || "(unknown)"} \xB7 **Tool:** ${row.tool || "claude"}` + (when2 ? ` \xB7 **Modified:** ${when2}` : "") + ` \xB7 \`${row.sessionId}\``);
|
|
23820
23989
|
if (outcome) {
|
|
23821
23990
|
const edits = outcome.fileCount > 0 ? ` \xB7 ${outcome.fileCount} file(s) +${outcome.totalLinesAdded}/\u2212${outcome.totalLinesRemoved}` : "";
|
|
23822
23991
|
const commits = outcome.commits && outcome.commits.totalCommits > 0 ? ` \xB7 ${outcome.commits.totalCommits} commit(s)` : "";
|
|
@@ -23876,17 +24045,21 @@ function safeSlice(s, start, end) {
|
|
|
23876
24045
|
const hi = end < s.length && /[\uD800-\uDBFF]/.test(s[end - 1] ?? "") ? end + 1 : end;
|
|
23877
24046
|
return s.slice(lo, hi);
|
|
23878
24047
|
}
|
|
23879
|
-
function
|
|
23880
|
-
if (
|
|
23881
|
-
return
|
|
24048
|
+
function headTail(text, how) {
|
|
24049
|
+
if (text.length <= BODY_LIMIT)
|
|
24050
|
+
return [text];
|
|
23882
24051
|
const lines = text.split("\n").length;
|
|
23883
24052
|
const cut = text.length - 2 * EDGE;
|
|
23884
|
-
const how = opts.expandHint ? ` ${opts.expandHint(line)}` : "";
|
|
23885
24053
|
return [
|
|
23886
|
-
|
|
23887
|
-
|
|
23888
|
-
|
|
23889
|
-
]
|
|
24054
|
+
safeSlice(text, 0, EDGE),
|
|
24055
|
+
`\u2026 ${cut} characters cut (${text.length} in all, ${lines} lines).${how ? ` ${how}` : ""} \u2026`,
|
|
24056
|
+
safeSlice(text, text.length - EDGE, text.length)
|
|
24057
|
+
];
|
|
24058
|
+
}
|
|
24059
|
+
function body(text, line, opts) {
|
|
24060
|
+
if (opts.full)
|
|
24061
|
+
return indent(text);
|
|
24062
|
+
return headTail(text, opts.expandHint?.(line)).map(indent).join("\n");
|
|
23890
24063
|
}
|
|
23891
24064
|
function resultText(result) {
|
|
23892
24065
|
if (typeof result === "string")
|
|
@@ -24008,6 +24181,59 @@ function findShowMessages(messages, query) {
|
|
|
24008
24181
|
return messages.filter((m) => searchableText(m).toLowerCase().includes(needle));
|
|
24009
24182
|
}
|
|
24010
24183
|
|
|
24184
|
+
// ../engine/dist/mcp/prompts-render.js
|
|
24185
|
+
var fold = (s) => s.toLowerCase().replace(/\s+/g, " ");
|
|
24186
|
+
function when(p, sessionMs) {
|
|
24187
|
+
if (p.ts && p.ts > 0)
|
|
24188
|
+
return p.ts;
|
|
24189
|
+
const parsed = p.tsIso ? Date.parse(p.tsIso) : NaN;
|
|
24190
|
+
return Number.isFinite(parsed) ? parsed : sessionMs;
|
|
24191
|
+
}
|
|
24192
|
+
function newestFirst(a, b) {
|
|
24193
|
+
if (b.at !== a.at)
|
|
24194
|
+
return b.at - a.at;
|
|
24195
|
+
if (a.row.sessionId === b.row.sessionId)
|
|
24196
|
+
return b.row.line - a.row.line;
|
|
24197
|
+
return 0;
|
|
24198
|
+
}
|
|
24199
|
+
function matching(rows, query) {
|
|
24200
|
+
const q = query ? fold(query.trim()) : "";
|
|
24201
|
+
return rows.filter((p) => p.text && p.text.trim() && (!q || fold(p.text).includes(q)));
|
|
24202
|
+
}
|
|
24203
|
+
function selectPrompts(rows, opts) {
|
|
24204
|
+
return matching(rows, opts.query).map((row) => ({ row, at: when(row, 0) })).sort(newestFirst).slice(0, Math.max(0, opts.limit)).map((x) => x.row);
|
|
24205
|
+
}
|
|
24206
|
+
async function collectAcrossSessions(feed, fetchPrompts, opts) {
|
|
24207
|
+
const limit = Math.max(0, opts.limit);
|
|
24208
|
+
let kept = [];
|
|
24209
|
+
for (const s of feed) {
|
|
24210
|
+
if (kept.length >= limit && s.modifiedMs < kept[kept.length - 1].at)
|
|
24211
|
+
break;
|
|
24212
|
+
const rows = await fetchPrompts(s.sessionId);
|
|
24213
|
+
if (!rows)
|
|
24214
|
+
continue;
|
|
24215
|
+
for (const row of matching(rows, opts.query))
|
|
24216
|
+
kept.push({ row, at: when(row, s.modifiedMs) });
|
|
24217
|
+
kept = kept.sort(newestFirst).slice(0, limit);
|
|
24218
|
+
}
|
|
24219
|
+
return kept.map((x) => x.row);
|
|
24220
|
+
}
|
|
24221
|
+
function renderPrompts(rows, opts) {
|
|
24222
|
+
const what = opts.query ? `, containing "${opts.query.trim()}"` : "";
|
|
24223
|
+
const lines = [`# User prompts (${rows.length}${what}, newest first)
|
|
24224
|
+
`];
|
|
24225
|
+
for (const p of rows) {
|
|
24226
|
+
const t = p.tsIso?.slice(0, 16).replace("T", " ") || "";
|
|
24227
|
+
const markerSuffix = opts.withMarkers && p.markers.length ? ` _[${p.markers.join(", ")}]_` : "";
|
|
24228
|
+
lines.push(`- **${p.sessionId}** L${p.line}${t ? ` \xB7 ${t}` : ""}${markerSuffix}`);
|
|
24229
|
+
const how = `Call recall_show with session_id "${p.sessionId}" and expand_line ${p.line} for the whole text.`;
|
|
24230
|
+
for (const part of headTail(p.text, how)) {
|
|
24231
|
+
lines.push(part.split("\n").map((l) => ` ${l}`).join("\n"));
|
|
24232
|
+
}
|
|
24233
|
+
}
|
|
24234
|
+
return lines.join("\n");
|
|
24235
|
+
}
|
|
24236
|
+
|
|
24011
24237
|
// ../engine/dist/mcp/show-freshness.js
|
|
24012
24238
|
init_tool_backend();
|
|
24013
24239
|
init_transcript();
|
|
@@ -24244,14 +24470,14 @@ function trialEndingBanner(state2, serverBase) {
|
|
|
24244
24470
|
const days = state2.trialDaysLeft;
|
|
24245
24471
|
if (typeof days !== "number" || days > TRIAL_WARN_DAYS)
|
|
24246
24472
|
return null;
|
|
24247
|
-
const
|
|
24473
|
+
const when2 = days <= 0 ? "today" : days === 1 ? "tomorrow" : `in ${days} days`;
|
|
24248
24474
|
const account = `${serverBase.replace(/\/+$/, "")}/app?view=account`;
|
|
24249
24475
|
return [
|
|
24250
24476
|
// No trial LENGTH here. It is FREE_TRIAL_DAYS on the server, so a "7-day
|
|
24251
24477
|
// trial" written into the CLI is a number that drifts the first time that is
|
|
24252
24478
|
// tuned — and this file already carries two sentences that went stale that
|
|
24253
24479
|
// exact way. Days REMAINING comes from the server and is always right.
|
|
24254
|
-
`\u23F3 TRIAL ENDS ${
|
|
24480
|
+
`\u23F3 TRIAL ENDS ${when2.toUpperCase()} \u2014 this chat-recall account is on the free trial.`,
|
|
24255
24481
|
"When it ends, recall switches off: searches and session reads stop, and new sessions stop syncing.",
|
|
24256
24482
|
"Nothing is deleted \u2014 the history is kept and export keeps working.",
|
|
24257
24483
|
`Tell the user now, and give them this link to subscribe or see the account: ${account}`
|
|
@@ -25033,7 +25259,8 @@ var RecallImprovementsSchema = z.object({
|
|
|
25033
25259
|
var RecallUserPromptsSchema = z.object({
|
|
25034
25260
|
session_id: z.string().optional().describe("If set, only that session's prompts"),
|
|
25035
25261
|
since_days: z.number().optional().default(7).describe("When session_id is omitted, look back this many days"),
|
|
25036
|
-
limit: z.number().optional().default(50).describe("Maximum prompts to return"),
|
|
25262
|
+
limit: z.number().optional().default(50).describe("Maximum prompts to return, newest first"),
|
|
25263
|
+
query: z.string().optional().describe("Keep only the prompts that contain this text (no case)"),
|
|
25037
25264
|
with_markers: z.boolean().optional().default(true).describe("Tag each prompt with sentiment / corrective markers (interrupt, frustrated, correction, approval, \u2026). Set false to revert to legacy text-only output.")
|
|
25038
25265
|
});
|
|
25039
25266
|
function resolveRecordScope(params) {
|
|
@@ -26132,15 +26359,18 @@ write.`,
|
|
|
26132
26359
|
// ── User-prompts / decision-record ──
|
|
26133
26360
|
{
|
|
26134
26361
|
name: "recall_user_prompts",
|
|
26135
|
-
description: `List the human-typed prompts from a session (or recent sessions)
|
|
26136
|
-
and system banners are stripped \u2014 you get only what the user actually wrote. Useful for
|
|
26137
|
-
I asking yesterday?" or "what did I tell the agent in this session?"
|
|
26362
|
+
description: `List the human-typed prompts from a session (or recent sessions), newest first.
|
|
26363
|
+
Tool results and system banners are stripped \u2014 you get only what the user actually wrote. Useful for
|
|
26364
|
+
"what was I asking yesterday?" or "what did I tell the agent in this session?". Pass \`query\` for
|
|
26365
|
+
"did I say X?": it keeps only the prompts that contain that text. Each prompt prints whole up to 2000
|
|
26366
|
+
characters; a longer one prints its start and end and the recall_show expand_line call for the rest.`,
|
|
26138
26367
|
inputSchema: {
|
|
26139
26368
|
type: "object",
|
|
26140
26369
|
properties: {
|
|
26141
26370
|
session_id: { type: "string", description: "If set, only that session's prompts" },
|
|
26142
26371
|
since_days: { type: "number", default: 7, description: "How far back to look, in days." },
|
|
26143
|
-
limit: { type: "number", default: 50, description: "Maximum prompts to return, newest first." }
|
|
26372
|
+
limit: { type: "number", default: 50, description: "Maximum prompts to return, newest first." },
|
|
26373
|
+
query: { type: "string", description: "Keep only the prompts that contain this text. Case and runs of whitespace are ignored." }
|
|
26144
26374
|
}
|
|
26145
26375
|
}
|
|
26146
26376
|
},
|
|
@@ -27305,9 +27535,9 @@ _Edits stayed local or window was off \u2014 try increasing buffer_minutes._` }]
|
|
|
27305
27535
|
const r = remote.results[i];
|
|
27306
27536
|
const kind = r.chunkType?.match(/:(\w+):imp([0-9])/);
|
|
27307
27537
|
const tag = kind ? ` \xB7 ${kind[1]} (imp${kind[2]})` : "";
|
|
27308
|
-
const
|
|
27538
|
+
const when2 = r.mtime ? ` \xB7 ${new Date(r.mtime).toISOString().slice(0, 10)}` : "";
|
|
27309
27539
|
lines.push(`## #${i + 1} [${r.sourceType}${tag}] ${(r.title || r.itemId).slice(0, 90)}`);
|
|
27310
|
-
lines.push(`**id:** \`${r.itemId}\`${
|
|
27540
|
+
lines.push(`**id:** \`${r.itemId}\`${when2}${r.projectPath ? ` \xB7 ${r.projectPath}` : ""}`);
|
|
27311
27541
|
if (r.sourceType === "session")
|
|
27312
27542
|
lines.push(`_fetch: recall_context / recall_show "${r.itemId}"_`);
|
|
27313
27543
|
const snippets = (r.matchedChunks?.length ? r.matchedChunks.map((c) => c.text) : [r.text]).filter(Boolean).slice(0, 3);
|
|
@@ -27599,8 +27829,8 @@ _Edits stayed local or window was off \u2014 try increasing buffer_minutes._` }]
|
|
|
27599
27829
|
const total = rows.reduce((n, r) => n + r.sessions, 0);
|
|
27600
27830
|
lines.push(`## ${member} \u2014 ${total} session(s)`);
|
|
27601
27831
|
for (const r of [...rows].sort((x, y) => y.lastMtime - x.lastMtime)) {
|
|
27602
|
-
const
|
|
27603
|
-
lines.push(`- ${r.projectId} \xB7 ${r.sessions} session(s) \xB7 last active ${
|
|
27832
|
+
const when2 = r.lastMtime ? new Date(r.lastMtime).toISOString().slice(0, 10) : "????";
|
|
27833
|
+
lines.push(`- ${r.projectId} \xB7 ${r.sessions} session(s) \xB7 last active ${when2}`);
|
|
27604
27834
|
}
|
|
27605
27835
|
lines.push("");
|
|
27606
27836
|
}
|
|
@@ -28281,54 +28511,35 @@ ${JSON.stringify(r, null, 2)}
|
|
|
28281
28511
|
case "recall_user_prompts": {
|
|
28282
28512
|
const params = RecallUserPromptsSchema.parse(args);
|
|
28283
28513
|
requireRemote();
|
|
28284
|
-
const
|
|
28285
|
-
|
|
28286
|
-
|
|
28287
|
-
|
|
28288
|
-
const t = p.tsIso?.slice(0, 16).replace("T", " ") || "";
|
|
28289
|
-
const snippet = p.text.length > 240 ? p.text.slice(0, 240) + "\u2026" : p.text;
|
|
28290
|
-
const markerSuffix = params.with_markers && p.markers.length ? ` _[${p.markers.join(", ")}]_` : "";
|
|
28291
|
-
lines.push(`- **${p.sessionId}** L${p.line}${t ? ` \xB7 ${t}` : ""}${markerSuffix}`);
|
|
28292
|
-
lines.push(` ${snippet.replace(/\n/g, " ")}`);
|
|
28293
|
-
}
|
|
28294
|
-
return lines.join("\n");
|
|
28295
|
-
};
|
|
28514
|
+
const toRows = (sessionId, prompts) => prompts.map((p) => ({ sessionId, line: p.line, ts: p.ts, tsIso: p.tsIso, markers: p.markers || [], text: p.text }));
|
|
28515
|
+
const select = { limit: params.limit, query: params.query };
|
|
28516
|
+
const render = (rows) => renderPrompts(rows, { withMarkers: params.with_markers, query: params.query });
|
|
28517
|
+
const none = params.query ? `No user prompts contain "${params.query.trim()}".` : "No user prompts found.";
|
|
28296
28518
|
if (params.session_id) {
|
|
28297
28519
|
const soft = await remoteGetSoft(`/api/conversations/${encodeURIComponent(params.session_id)}/markers`);
|
|
28298
28520
|
if (!soft.data) {
|
|
28299
28521
|
return { content: [{ type: "text", text: soft.message || (soft.status === 404 ? `Session ${params.session_id} not found.` : `Prompts not synced yet for ${params.session_id}.`) }] };
|
|
28300
28522
|
}
|
|
28301
|
-
const rows =
|
|
28302
|
-
|
|
28303
|
-
return { content: [{ type: "text", text: "No user prompts found." }] };
|
|
28304
|
-
}
|
|
28305
|
-
return { content: [{ type: "text", text: renderPrompts(rows) }] };
|
|
28523
|
+
const rows = selectPrompts(toRows(params.session_id, soft.data.prompts), select);
|
|
28524
|
+
return { content: [{ type: "text", text: rows.length ? render(rows) : none }] };
|
|
28306
28525
|
}
|
|
28307
28526
|
const sinceHours = params.since_days * 24;
|
|
28308
28527
|
const recent = await remoteGetQS("/api/conversations/recent", { limit: 200, since_hours: sinceHours });
|
|
28309
|
-
const
|
|
28310
|
-
|
|
28311
|
-
|
|
28312
|
-
}
|
|
28313
|
-
|
|
28314
|
-
|
|
28315
|
-
|
|
28316
|
-
|
|
28528
|
+
const feed = (recent.sessions || []).map((s) => ({
|
|
28529
|
+
sessionId: s.sessionId,
|
|
28530
|
+
modifiedMs: s.fileMtime || (s.modified ? Date.parse(s.modified) : 0) || 0
|
|
28531
|
+
}));
|
|
28532
|
+
if (feed.length === 0) {
|
|
28533
|
+
return { content: [{ type: "text", text: none }] };
|
|
28534
|
+
}
|
|
28535
|
+
const collected = await collectAcrossSessions(feed, async (sid) => {
|
|
28317
28536
|
const soft = await remoteGetSoft(`/api/conversations/${encodeURIComponent(sid)}/markers`);
|
|
28318
|
-
|
|
28319
|
-
|
|
28320
|
-
for (const p of soft.data.prompts) {
|
|
28321
|
-
if (!p.text || !p.text.trim())
|
|
28322
|
-
continue;
|
|
28323
|
-
collected.push({ sessionId: sid, line: p.line, tsIso: p.tsIso, markers: p.markers || [], text: p.text });
|
|
28324
|
-
if (collected.length >= params.limit)
|
|
28325
|
-
break;
|
|
28326
|
-
}
|
|
28327
|
-
}
|
|
28537
|
+
return soft.data ? toRows(sid, soft.data.prompts) : null;
|
|
28538
|
+
}, select);
|
|
28328
28539
|
if (collected.length === 0) {
|
|
28329
|
-
return { content: [{ type: "text", text: "No user prompts found (none of the recent sessions have synced markers yet)." }] };
|
|
28540
|
+
return { content: [{ type: "text", text: params.query ? none : "No user prompts found (none of the recent sessions have synced markers yet)." }] };
|
|
28330
28541
|
}
|
|
28331
|
-
return { content: [{ type: "text", text:
|
|
28542
|
+
return { content: [{ type: "text", text: render(collected) }] };
|
|
28332
28543
|
}
|
|
28333
28544
|
// ── Decision recording ────────────────────────────────────
|
|
28334
28545
|
case "recall_decision_record": {
|
|
@@ -28924,9 +29135,9 @@ _Tell the user \u2014 this changes how future sessions treat their repo._` }] };
|
|
|
28924
29135
|
}
|
|
28925
29136
|
const lines = [`# Files resembling \`${params.filename}\` (${data.hits.length})`, "_You may have built this before._\n"];
|
|
28926
29137
|
for (const h of data.hits) {
|
|
28927
|
-
const
|
|
29138
|
+
const when2 = h.mtime ? new Date(h.mtime).toISOString().slice(0, 10) : "";
|
|
28928
29139
|
lines.push(`- \`${h.file}\` \u2014 ${h.reason} (score ${h.score})`);
|
|
28929
|
-
lines.push(` ${h.project || "(no project)"} \xB7 ${h.sessionId}${
|
|
29140
|
+
lines.push(` ${h.project || "(no project)"} \xB7 ${h.sessionId}${when2 ? ` \xB7 ${when2}` : ""}`);
|
|
28930
29141
|
}
|
|
28931
29142
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
28932
29143
|
}
|
|
@@ -28968,8 +29179,8 @@ _Tell the user \u2014 this changes how future sessions treat their repo._` }] };
|
|
|
28968
29179
|
const lines = [`# ${params.source_type} items (${data.items.length})
|
|
28969
29180
|
`];
|
|
28970
29181
|
for (const it of data.items) {
|
|
28971
|
-
const
|
|
28972
|
-
lines.push(`- **${it.id}**${it.title ? ` \u2014 ${it.title}` : ""}${
|
|
29182
|
+
const when2 = it.mtime ? new Date(it.mtime).toISOString().slice(0, 10) : "";
|
|
29183
|
+
lines.push(`- **${it.id}**${it.title ? ` \u2014 ${it.title}` : ""}${when2 ? ` \xB7 ${when2}` : ""}`);
|
|
28973
29184
|
}
|
|
28974
29185
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
28975
29186
|
}
|
|
@@ -29287,7 +29498,7 @@ function installCrashGuards() {
|
|
|
29287
29498
|
reportClientEvent2("mcp_crash", { message: err.stack || err.message });
|
|
29288
29499
|
});
|
|
29289
29500
|
}
|
|
29290
|
-
var RELAY_VERSION = true ? "0.7.
|
|
29501
|
+
var RELAY_VERSION = true ? "0.7.13" : "0.0.0";
|
|
29291
29502
|
function daemonIdleSecs() {
|
|
29292
29503
|
const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
|
|
29293
29504
|
if (raw === void 0) return 900;
|