chat-recall 0.7.7 → 0.7.9
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 +380 -211
- package/dist/cli.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +306 -168
- package/dist/scan-worker.js +70 -16
- package/dist/watch.js +105 -39
- package/package.json +1 -1
- package/skills/chat-recall-find/SKILL.md +3 -1
- package/skills/chat-recall-resume/SKILL.md +3 -1
package/dist/cli.js
CHANGED
|
@@ -4892,8 +4892,8 @@ function writeSecrets(secrets) {
|
|
|
4892
4892
|
_secretsCache = null;
|
|
4893
4893
|
const p = secretsPath();
|
|
4894
4894
|
mkdirSync2(dirname2(p), { recursive: true });
|
|
4895
|
-
const
|
|
4896
|
-
writeFileSync(p,
|
|
4895
|
+
const body2 = "# chat-recall secrets \u2014 NOT committed/synced. Mode 0600.\n" + Object.entries(secrets).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join("\n") + "\n";
|
|
4896
|
+
writeFileSync(p, body2);
|
|
4897
4897
|
try {
|
|
4898
4898
|
chmodSync(p, 384);
|
|
4899
4899
|
} catch {
|
|
@@ -5979,11 +5979,11 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
5979
5979
|
}
|
|
5980
5980
|
const toolResult = obj.toolUseResult;
|
|
5981
5981
|
if (toolResult && typeof toolResult === "object" && toolCount < maxMessages) {
|
|
5982
|
-
const
|
|
5982
|
+
const resultText2 = toolResult.result;
|
|
5983
5983
|
const query = toolResult.query;
|
|
5984
|
-
if (
|
|
5984
|
+
if (resultText2 && typeof resultText2 === "string" && isValuableToolResult(resultText2, "WebSearch")) {
|
|
5985
5985
|
const searchText = query ? `Search: ${query}
|
|
5986
|
-
${
|
|
5986
|
+
${resultText2}` : resultText2;
|
|
5987
5987
|
content.toolResults.push({
|
|
5988
5988
|
text: searchText.slice(0, 2e3),
|
|
5989
5989
|
lineNumber: lineNum,
|
|
@@ -7002,7 +7002,7 @@ function gitLogRepo(repo, startIso, endIso) {
|
|
|
7002
7002
|
const authorIso = seg.slice(fieldPositions[1] + 1, fieldPositions[2]);
|
|
7003
7003
|
const authorName = seg.slice(fieldPositions[2] + 1, fieldPositions[3]);
|
|
7004
7004
|
const subject = seg.slice(fieldPositions[3] + 1, fieldPositions[4]);
|
|
7005
|
-
let
|
|
7005
|
+
let body2 = seg.slice(fieldPositions[4] + 1);
|
|
7006
7006
|
current = {
|
|
7007
7007
|
sha,
|
|
7008
7008
|
shortSha,
|
|
@@ -7016,11 +7016,11 @@ function gitLogRepo(repo, startIso, endIso) {
|
|
|
7016
7016
|
};
|
|
7017
7017
|
const recovered = [];
|
|
7018
7018
|
let m;
|
|
7019
|
-
while (m = TRAILING_NUMSTAT.exec(
|
|
7019
|
+
while (m = TRAILING_NUMSTAT.exec(body2)) {
|
|
7020
7020
|
recovered.unshift(m[1]);
|
|
7021
|
-
|
|
7021
|
+
body2 = body2.slice(0, body2.length - m[0].length);
|
|
7022
7022
|
}
|
|
7023
|
-
current.body =
|
|
7023
|
+
current.body = body2.trim();
|
|
7024
7024
|
for (const line of recovered)
|
|
7025
7025
|
recordNumstat(line);
|
|
7026
7026
|
} else if (NUMSTAT.test(seg)) {
|
|
@@ -7914,7 +7914,7 @@ var init_opencode = __esm({
|
|
|
7914
7914
|
});
|
|
7915
7915
|
const out = d?.state?.output;
|
|
7916
7916
|
if (out !== void 0 && out !== null) {
|
|
7917
|
-
const
|
|
7917
|
+
const body2 = typeof out === "string" ? out : JSON.stringify(out);
|
|
7918
7918
|
events.push({
|
|
7919
7919
|
kind: "tool_result",
|
|
7920
7920
|
ts,
|
|
@@ -7922,9 +7922,9 @@ var init_opencode = __esm({
|
|
|
7922
7922
|
line: lineNum,
|
|
7923
7923
|
toolUseId: callId,
|
|
7924
7924
|
toolName,
|
|
7925
|
-
resultBody:
|
|
7925
|
+
resultBody: body2,
|
|
7926
7926
|
resultIsError: d?.state?.status === "error",
|
|
7927
|
-
resultBytes:
|
|
7927
|
+
resultBytes: body2.length
|
|
7928
7928
|
});
|
|
7929
7929
|
}
|
|
7930
7930
|
}
|
|
@@ -8699,13 +8699,13 @@ var init_codex2 = __esm({
|
|
|
8699
8699
|
} else if (obj.type === "response_item" && payload.type === "function_call_output") {
|
|
8700
8700
|
const callId = String(payload.call_id || "");
|
|
8701
8701
|
const out = payload.output;
|
|
8702
|
-
let
|
|
8702
|
+
let body2 = "";
|
|
8703
8703
|
let isError = false;
|
|
8704
8704
|
let exitCode;
|
|
8705
8705
|
if (typeof out === "string")
|
|
8706
|
-
|
|
8706
|
+
body2 = out;
|
|
8707
8707
|
else if (out && typeof out === "object") {
|
|
8708
|
-
|
|
8708
|
+
body2 = String(out.content ?? out.output ?? out.stdout ?? out.text ?? "");
|
|
8709
8709
|
if (typeof out.exit_code === "number") {
|
|
8710
8710
|
exitCode = out.exit_code;
|
|
8711
8711
|
isError = exitCode !== 0;
|
|
@@ -8717,10 +8717,10 @@ var init_codex2 = __esm({
|
|
|
8717
8717
|
tsIso,
|
|
8718
8718
|
line: lineNum,
|
|
8719
8719
|
toolUseId: callId,
|
|
8720
|
-
resultBody:
|
|
8720
|
+
resultBody: body2,
|
|
8721
8721
|
resultIsError: isError,
|
|
8722
8722
|
resultExitCode: exitCode,
|
|
8723
|
-
resultBytes:
|
|
8723
|
+
resultBytes: body2.length
|
|
8724
8724
|
});
|
|
8725
8725
|
}
|
|
8726
8726
|
}
|
|
@@ -9742,15 +9742,15 @@ function messagesToEvents(messages, createdAtMs, updatedAtMs) {
|
|
|
9742
9742
|
const p = part;
|
|
9743
9743
|
if (p.type !== "tool-result")
|
|
9744
9744
|
continue;
|
|
9745
|
-
const
|
|
9745
|
+
const body2 = resultBodyOf(p);
|
|
9746
9746
|
events.push({
|
|
9747
9747
|
kind: "tool_result",
|
|
9748
9748
|
ts: clock,
|
|
9749
9749
|
line: 0,
|
|
9750
9750
|
toolUseId: typeof p.toolCallId === "string" ? p.toolCallId : void 0,
|
|
9751
|
-
resultBody:
|
|
9751
|
+
resultBody: body2,
|
|
9752
9752
|
resultIsError: isError,
|
|
9753
|
-
resultBytes: Buffer.byteLength(
|
|
9753
|
+
resultBytes: Buffer.byteLength(body2, "utf8")
|
|
9754
9754
|
});
|
|
9755
9755
|
}
|
|
9756
9756
|
}
|
|
@@ -10613,11 +10613,11 @@ var init_cursor = __esm({
|
|
|
10613
10613
|
const events = readComposerEvents(r.composer);
|
|
10614
10614
|
if (events.length === 0)
|
|
10615
10615
|
return null;
|
|
10616
|
-
const
|
|
10616
|
+
const body2 = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
10617
10617
|
return {
|
|
10618
10618
|
tool: "cursor",
|
|
10619
10619
|
mtime: statSync9(r.composer.globalDbPath).mtimeMs,
|
|
10620
|
-
files: [{ name: `${r.composer.composerId}.jsonl`, bytes: Buffer.from(
|
|
10620
|
+
files: [{ name: `${r.composer.composerId}.jsonl`, bytes: Buffer.from(body2, "utf8") }]
|
|
10621
10621
|
};
|
|
10622
10622
|
} catch {
|
|
10623
10623
|
return null;
|
|
@@ -10972,9 +10972,29 @@ function findSessionFile(sessionId) {
|
|
|
10972
10972
|
function invalidateSessionFileIndex() {
|
|
10973
10973
|
indexCache = null;
|
|
10974
10974
|
}
|
|
10975
|
+
function indexStillValid(cache4) {
|
|
10976
|
+
const roots = claudeProjectDirs();
|
|
10977
|
+
if (roots.length !== cache4.roots.length || roots.some((r, i) => r !== cache4.roots[i]))
|
|
10978
|
+
return false;
|
|
10979
|
+
for (const [dir, mtime] of cache4.dirs) {
|
|
10980
|
+
if (dirMtime(dir) !== mtime)
|
|
10981
|
+
return false;
|
|
10982
|
+
}
|
|
10983
|
+
return true;
|
|
10984
|
+
}
|
|
10975
10985
|
function sessionFileIndex() {
|
|
10976
|
-
if (indexCache)
|
|
10977
|
-
|
|
10986
|
+
if (indexCache) {
|
|
10987
|
+
const now = Date.now();
|
|
10988
|
+
if (now - indexCache.checkedAt < INDEX_RECHECK_MS)
|
|
10989
|
+
return indexCache.byId;
|
|
10990
|
+
if (indexStillValid(indexCache)) {
|
|
10991
|
+
indexCache.checkedAt = now;
|
|
10992
|
+
return indexCache.byId;
|
|
10993
|
+
}
|
|
10994
|
+
indexCache = null;
|
|
10995
|
+
}
|
|
10996
|
+
const dirs = /* @__PURE__ */ new Map();
|
|
10997
|
+
const roots = claudeProjectDirs();
|
|
10978
10998
|
const byId = /* @__PURE__ */ new Map();
|
|
10979
10999
|
const seenRoots = /* @__PURE__ */ new Set();
|
|
10980
11000
|
const projectPaths = /* @__PURE__ */ new Map();
|
|
@@ -10986,10 +11006,11 @@ function sessionFileIndex() {
|
|
|
10986
11006
|
}
|
|
10987
11007
|
return p;
|
|
10988
11008
|
};
|
|
10989
|
-
for (const root of
|
|
11009
|
+
for (const root of roots) {
|
|
10990
11010
|
if (seenRoots.has(root) || !existsSync13(root))
|
|
10991
11011
|
continue;
|
|
10992
11012
|
seenRoots.add(root);
|
|
11013
|
+
dirs.set(root, dirMtime(root));
|
|
10993
11014
|
let entries;
|
|
10994
11015
|
try {
|
|
10995
11016
|
entries = readdirSync10(root, { withFileTypes: true });
|
|
@@ -11000,6 +11021,7 @@ function sessionFileIndex() {
|
|
|
11000
11021
|
if (!entry.isDirectory())
|
|
11001
11022
|
continue;
|
|
11002
11023
|
const dir = join15(root, entry.name);
|
|
11024
|
+
dirs.set(dir, dirMtime(dir));
|
|
11003
11025
|
let names;
|
|
11004
11026
|
try {
|
|
11005
11027
|
names = readdirSync10(dir);
|
|
@@ -11024,7 +11046,7 @@ function sessionFileIndex() {
|
|
|
11024
11046
|
}
|
|
11025
11047
|
}
|
|
11026
11048
|
if (scanScopeDepth > 0)
|
|
11027
|
-
indexCache = byId;
|
|
11049
|
+
indexCache = { byId, dirs, roots, checkedAt: Date.now() };
|
|
11028
11050
|
return byId;
|
|
11029
11051
|
}
|
|
11030
11052
|
function findSessionFiles(sessionId) {
|
|
@@ -11182,7 +11204,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
11182
11204
|
}
|
|
11183
11205
|
return scanDir(root);
|
|
11184
11206
|
}
|
|
11185
|
-
var scanScopeDepth, indexCache, readScope, readScopeDepth, derivedScope, geminiCache, MAX_EVENT_LINE_BYTES;
|
|
11207
|
+
var scanScopeDepth, indexCache, INDEX_RECHECK_MS, dirMtime, readScope, readScopeDepth, derivedScope, geminiCache, MAX_EVENT_LINE_BYTES;
|
|
11186
11208
|
var init_live_session_scan = __esm({
|
|
11187
11209
|
"../engine/dist/core/live-session-scan.js"() {
|
|
11188
11210
|
"use strict";
|
|
@@ -11194,6 +11216,14 @@ var init_live_session_scan = __esm({
|
|
|
11194
11216
|
init_project_dir_name();
|
|
11195
11217
|
scanScopeDepth = 0;
|
|
11196
11218
|
indexCache = null;
|
|
11219
|
+
INDEX_RECHECK_MS = 1e3;
|
|
11220
|
+
dirMtime = (p) => {
|
|
11221
|
+
try {
|
|
11222
|
+
return statSync11(p).mtimeMs;
|
|
11223
|
+
} catch {
|
|
11224
|
+
return -1;
|
|
11225
|
+
}
|
|
11226
|
+
};
|
|
11197
11227
|
readScope = null;
|
|
11198
11228
|
readScopeDepth = 0;
|
|
11199
11229
|
derivedScope = null;
|
|
@@ -11459,15 +11489,36 @@ var init_claude2 = __esm({
|
|
|
11459
11489
|
listSessions(opts = {}) {
|
|
11460
11490
|
const cutoff = opts.sinceMs ?? 0;
|
|
11461
11491
|
const filter = opts.projectFilter?.toLowerCase();
|
|
11462
|
-
const
|
|
11463
|
-
const out = [];
|
|
11492
|
+
const byId = /* @__PURE__ */ new Map();
|
|
11464
11493
|
for (const root of claudeProjectDirs()) {
|
|
11465
|
-
this.collectSessionsFromRoot(root,
|
|
11494
|
+
this.collectSessionsFromRoot(root, filter, byId, opts.previews !== false);
|
|
11466
11495
|
}
|
|
11496
|
+
const out = [...byId.values()].filter((r) => r.mtime >= cutoff);
|
|
11467
11497
|
out.sort((a, b) => b.mtime - a.mtime);
|
|
11468
11498
|
return opts.limit ? out.slice(0, opts.limit) : out;
|
|
11469
11499
|
}
|
|
11470
|
-
|
|
11500
|
+
/**
|
|
11501
|
+
* Add this root's sessions to `byId`. A session resumed under a second
|
|
11502
|
+
* profile has one file in each home under the same id. It is ONE session: the
|
|
11503
|
+
* first home keeps its path, and its mtime is the newest of all copies.
|
|
11504
|
+
*
|
|
11505
|
+
* Each copy was listed as its own ref before. Session 8da8d72b had a primary
|
|
11506
|
+
* copy frozen at 05:55 and a second-home copy growing until 12:00; the walk
|
|
11507
|
+
* handled both refs under one ledger row with two different mtimes, and the
|
|
11508
|
+
* row that shipped nothing stamped the other copy's mtime.
|
|
11509
|
+
*/
|
|
11510
|
+
collectSessionsFromRoot(root, filter, byId, previews) {
|
|
11511
|
+
const add = (ref) => {
|
|
11512
|
+
const prior = byId.get(ref.rawId);
|
|
11513
|
+
if (!prior) {
|
|
11514
|
+
byId.set(ref.rawId, ref);
|
|
11515
|
+
return;
|
|
11516
|
+
}
|
|
11517
|
+
if (ref.mtime > prior.mtime) {
|
|
11518
|
+
prior.mtime = ref.mtime;
|
|
11519
|
+
prior.modified = ref.modified;
|
|
11520
|
+
}
|
|
11521
|
+
};
|
|
11471
11522
|
if (!existsSync15(root))
|
|
11472
11523
|
return;
|
|
11473
11524
|
for (const proj of readdirSync11(root, { withFileTypes: true })) {
|
|
@@ -11478,6 +11529,7 @@ var init_claude2 = __esm({
|
|
|
11478
11529
|
const projPath = join16(root, proj.name);
|
|
11479
11530
|
const projectPath = resolveProjectDirName(proj.name);
|
|
11480
11531
|
const indexPath = join16(projPath, "sessions-index.json");
|
|
11532
|
+
const indexed = /* @__PURE__ */ new Set();
|
|
11481
11533
|
if (existsSync15(indexPath)) {
|
|
11482
11534
|
try {
|
|
11483
11535
|
const indexData = JSON.parse(readFileSync10(indexPath, "utf-8"));
|
|
@@ -11485,10 +11537,8 @@ var init_claude2 = __esm({
|
|
|
11485
11537
|
for (const entry of entries) {
|
|
11486
11538
|
if (!entry.fullPath || !existsSync15(entry.fullPath))
|
|
11487
11539
|
continue;
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
seen.add(entry.sessionId);
|
|
11491
|
-
out.push({
|
|
11540
|
+
indexed.add(entry.sessionId);
|
|
11541
|
+
add({
|
|
11492
11542
|
toolId: "claude",
|
|
11493
11543
|
rawId: entry.sessionId,
|
|
11494
11544
|
prefixedId: entry.sessionId,
|
|
@@ -11515,7 +11565,7 @@ var init_claude2 = __esm({
|
|
|
11515
11565
|
if (!f.endsWith(".jsonl") || f === "sessions-index.json")
|
|
11516
11566
|
continue;
|
|
11517
11567
|
const sessionId = basename10(f, ".jsonl");
|
|
11518
|
-
if (
|
|
11568
|
+
if (indexed.has(sessionId))
|
|
11519
11569
|
continue;
|
|
11520
11570
|
const fullPath = join16(projPath, f);
|
|
11521
11571
|
let stat3;
|
|
@@ -11524,10 +11574,13 @@ var init_claude2 = __esm({
|
|
|
11524
11574
|
} catch {
|
|
11525
11575
|
continue;
|
|
11526
11576
|
}
|
|
11527
|
-
|
|
11577
|
+
const prior = byId.get(sessionId);
|
|
11578
|
+
if (prior) {
|
|
11579
|
+
add({ ...prior, mtime: stat3.mtimeMs, modified: stat3.mtime.toISOString() });
|
|
11528
11580
|
continue;
|
|
11581
|
+
}
|
|
11529
11582
|
const firstPrompt = previews ? extractFirstUserPromptSync(fullPath, { maxLength: 200 }) : "";
|
|
11530
|
-
|
|
11583
|
+
add({
|
|
11531
11584
|
toolId: "claude",
|
|
11532
11585
|
rawId: sessionId,
|
|
11533
11586
|
prefixedId: sessionId,
|
|
@@ -11657,20 +11710,20 @@ var init_claude2 = __esm({
|
|
|
11657
11710
|
text += (text ? "\n" : "") + it.text;
|
|
11658
11711
|
} else if (it.type === "tool_result") {
|
|
11659
11712
|
const id = typeof it.tool_use_id === "string" ? it.tool_use_id : "";
|
|
11660
|
-
let
|
|
11713
|
+
let body2 = "";
|
|
11661
11714
|
const c = it.content;
|
|
11662
11715
|
if (typeof c === "string")
|
|
11663
|
-
|
|
11716
|
+
body2 = c;
|
|
11664
11717
|
else if (Array.isArray(c)) {
|
|
11665
11718
|
for (const sub of c) {
|
|
11666
11719
|
if (sub && typeof sub === "object" && sub.type === "text") {
|
|
11667
11720
|
const t = sub.text;
|
|
11668
11721
|
if (typeof t === "string")
|
|
11669
|
-
|
|
11722
|
+
body2 += t;
|
|
11670
11723
|
}
|
|
11671
11724
|
}
|
|
11672
11725
|
}
|
|
11673
|
-
toolResults.push({ id, body, isError: it.is_error === true });
|
|
11726
|
+
toolResults.push({ id, body: body2, isError: it.is_error === true });
|
|
11674
11727
|
}
|
|
11675
11728
|
}
|
|
11676
11729
|
}
|
|
@@ -12606,10 +12659,10 @@ function applyChunkPrivacy(text) {
|
|
|
12606
12659
|
out = redactFilePaths(out);
|
|
12607
12660
|
return out;
|
|
12608
12661
|
}
|
|
12609
|
-
function redactToolResultBody(toolName,
|
|
12610
|
-
if (!
|
|
12611
|
-
return
|
|
12612
|
-
return `[redacted: ${toolName} output, ${
|
|
12662
|
+
function redactToolResultBody(toolName, body2) {
|
|
12663
|
+
if (!body2)
|
|
12664
|
+
return body2;
|
|
12665
|
+
return `[redacted: ${toolName} output, ${body2.length} chars]`;
|
|
12613
12666
|
}
|
|
12614
12667
|
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache, privacyCache, PATH_REGEX;
|
|
12615
12668
|
var init_secret_redactor = __esm({
|
|
@@ -14839,8 +14892,8 @@ function parseFrontmatter(content) {
|
|
|
14839
14892
|
return { body: content };
|
|
14840
14893
|
const header = content.slice(3, close);
|
|
14841
14894
|
const afterFence = content.indexOf("\n", close + 1);
|
|
14842
|
-
const
|
|
14843
|
-
const out = { body };
|
|
14895
|
+
const body2 = afterFence === -1 ? "" : content.slice(afterFence + 1);
|
|
14896
|
+
const out = { body: body2 };
|
|
14844
14897
|
for (const line of header.split("\n")) {
|
|
14845
14898
|
const m = line.match(/^\s*([A-Za-z_]+)\s*:\s*(.+?)\s*$/);
|
|
14846
14899
|
if (!m)
|
|
@@ -14932,9 +14985,9 @@ var init_plan_source = __esm({
|
|
|
14932
14985
|
const isAgentPlan = planName.includes("-agent-");
|
|
14933
14986
|
const content = readFileSync15(filePath, "utf-8");
|
|
14934
14987
|
const fm = parseFrontmatter(content);
|
|
14935
|
-
const
|
|
14936
|
-
const firstLine =
|
|
14937
|
-
const projectPath = fm.cwd || this.extractProjectPath(
|
|
14988
|
+
const body2 = fm.body;
|
|
14989
|
+
const firstLine = body2.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || planName;
|
|
14990
|
+
const projectPath = fm.cwd || this.extractProjectPath(body2);
|
|
14938
14991
|
const baseName = planName.replace(/-agent-[a-z0-9]+$/i, "");
|
|
14939
14992
|
const claudeSessionId = fm.sessionId || (UUID_RE3.test(baseName) ? baseName : void 0);
|
|
14940
14993
|
yield {
|
|
@@ -14944,7 +14997,7 @@ var init_plan_source = __esm({
|
|
|
14944
14997
|
projectPath,
|
|
14945
14998
|
filePath,
|
|
14946
14999
|
mtime: stat3.mtimeMs,
|
|
14947
|
-
contentPreview:
|
|
15000
|
+
contentPreview: body2.slice(0, 300),
|
|
14948
15001
|
extra: {
|
|
14949
15002
|
tool: "claude",
|
|
14950
15003
|
isAgentPlan,
|
|
@@ -15051,8 +15104,8 @@ var init_plan_source = __esm({
|
|
|
15051
15104
|
return [];
|
|
15052
15105
|
const content = readFileSync15(item.filePath, "utf-8");
|
|
15053
15106
|
const chunks = [];
|
|
15054
|
-
const { body } = parseFrontmatter(content);
|
|
15055
|
-
const sections = splitByHeaders(
|
|
15107
|
+
const { body: body2 } = parseFrontmatter(content);
|
|
15108
|
+
const sections = splitByHeaders(body2);
|
|
15056
15109
|
for (let i = 0; i < sections.length; i++) {
|
|
15057
15110
|
const section = sections[i];
|
|
15058
15111
|
if (!section.text.trim() || section.text.trim().length < 20)
|
|
@@ -15685,10 +15738,10 @@ import { homedir as homedir9 } from "os";
|
|
|
15685
15738
|
import { join as join26, basename as basename14 } from "path";
|
|
15686
15739
|
function parseFrontmatter2(content) {
|
|
15687
15740
|
const fm = {};
|
|
15688
|
-
let
|
|
15741
|
+
let body2 = content;
|
|
15689
15742
|
const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
15690
15743
|
if (m) {
|
|
15691
|
-
|
|
15744
|
+
body2 = m[2];
|
|
15692
15745
|
for (const line of m[1].split(/\r?\n/)) {
|
|
15693
15746
|
const t = line.trim();
|
|
15694
15747
|
if (!t || t.startsWith("#"))
|
|
@@ -15705,7 +15758,7 @@ function parseFrontmatter2(content) {
|
|
|
15705
15758
|
fm[k] = v;
|
|
15706
15759
|
}
|
|
15707
15760
|
}
|
|
15708
|
-
return { fm, body };
|
|
15761
|
+
return { fm, body: body2 };
|
|
15709
15762
|
}
|
|
15710
15763
|
function projectHashToPath(hashDir) {
|
|
15711
15764
|
return resolveProjectDirName(hashDir);
|
|
@@ -15782,9 +15835,9 @@ var init_agent_memory_source = __esm({
|
|
|
15782
15835
|
if (!existsSync25(item.filePath))
|
|
15783
15836
|
return [];
|
|
15784
15837
|
const content = readFileSync18(item.filePath, "utf-8");
|
|
15785
|
-
const { body } = parseFrontmatter2(content);
|
|
15838
|
+
const { body: body2 } = parseFrontmatter2(content);
|
|
15786
15839
|
const chunks = [];
|
|
15787
|
-
const sections = splitByHeaders(
|
|
15840
|
+
const sections = splitByHeaders(body2);
|
|
15788
15841
|
for (let i = 0; i < sections.length; i++) {
|
|
15789
15842
|
const section = sections[i];
|
|
15790
15843
|
if (!section.text.trim() || section.text.trim().length < 20)
|
|
@@ -17428,13 +17481,13 @@ function parseFrontmatter4(text) {
|
|
|
17428
17481
|
}
|
|
17429
17482
|
return { fm, body: m[2] ?? "" };
|
|
17430
17483
|
}
|
|
17431
|
-
function stringifyFrontmatter(fm,
|
|
17484
|
+
function stringifyFrontmatter(fm, body2) {
|
|
17432
17485
|
const lines = Object.entries(fm).filter(([, v]) => v !== void 0 && v !== "").map(([k, v]) => `${k}: ${needsQuote(v) ? JSON.stringify(v) : v}`);
|
|
17433
17486
|
return `---
|
|
17434
17487
|
${lines.join("\n")}
|
|
17435
17488
|
---
|
|
17436
17489
|
|
|
17437
|
-
${
|
|
17490
|
+
${body2.replace(/^\n+/, "")}`;
|
|
17438
17491
|
}
|
|
17439
17492
|
function needsQuote(v) {
|
|
17440
17493
|
return /[:#]/.test(v) || /^\s|\s$/.test(v);
|
|
@@ -17521,11 +17574,11 @@ function parseCommand(content, fallbackName, format) {
|
|
|
17521
17574
|
body: t.prompt || ""
|
|
17522
17575
|
};
|
|
17523
17576
|
}
|
|
17524
|
-
const { fm, body } = parseFrontmatter4(content);
|
|
17577
|
+
const { fm, body: body2 } = parseFrontmatter4(content);
|
|
17525
17578
|
return {
|
|
17526
17579
|
name: fm.name || fallbackName,
|
|
17527
17580
|
description: fm.description || "",
|
|
17528
|
-
body:
|
|
17581
|
+
body: body2.trim()
|
|
17529
17582
|
};
|
|
17530
17583
|
}
|
|
17531
17584
|
var MAX_CHUNK_CHARS12, MAX_BODY_CHARS2, SlashCommandsSource;
|
|
@@ -17669,12 +17722,12 @@ function parseAgent(content, fallbackName, format) {
|
|
|
17669
17722
|
body: t.developer_instructions || t.instructions || ""
|
|
17670
17723
|
};
|
|
17671
17724
|
}
|
|
17672
|
-
const { fm, body } = parseFrontmatter4(content);
|
|
17725
|
+
const { fm, body: body2 } = parseFrontmatter4(content);
|
|
17673
17726
|
return {
|
|
17674
17727
|
name: fm.name || fallbackName,
|
|
17675
17728
|
description: fm.description || "",
|
|
17676
17729
|
tools: fm.tools || "",
|
|
17677
|
-
body:
|
|
17730
|
+
body: body2.trim()
|
|
17678
17731
|
};
|
|
17679
17732
|
}
|
|
17680
17733
|
var MAX_CHUNK_CHARS13, MAX_BODY_CHARS3, SubagentsSource;
|
|
@@ -18587,7 +18640,7 @@ var init_http = __esm({
|
|
|
18587
18640
|
CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
18588
18641
|
} catch {
|
|
18589
18642
|
try {
|
|
18590
|
-
if (true) CLI_VERSION = "0.7.
|
|
18643
|
+
if (true) CLI_VERSION = "0.7.9";
|
|
18591
18644
|
} catch {
|
|
18592
18645
|
}
|
|
18593
18646
|
}
|
|
@@ -19086,7 +19139,7 @@ var init_telemetry = __esm({
|
|
|
19086
19139
|
init_sync_client();
|
|
19087
19140
|
cliVersion2 = () => {
|
|
19088
19141
|
try {
|
|
19089
|
-
return true ? "0.7.
|
|
19142
|
+
return true ? "0.7.9" : "dev";
|
|
19090
19143
|
} catch {
|
|
19091
19144
|
return "dev";
|
|
19092
19145
|
}
|
|
@@ -19103,9 +19156,12 @@ __export(collector_health_exports, {
|
|
|
19103
19156
|
STALE_AFTER_MS: () => STALE_AFTER_MS,
|
|
19104
19157
|
applySyncOutcome: () => applySyncOutcome,
|
|
19105
19158
|
collectorHealthPath: () => collectorHealthPath,
|
|
19159
|
+
crashesAtBoot: () => crashesAtBoot,
|
|
19106
19160
|
judgeHealth: () => judgeHealth,
|
|
19161
|
+
markCleanExit: () => markCleanExit,
|
|
19107
19162
|
progressLine: () => progressLine,
|
|
19108
19163
|
readCollectorHealth: () => readCollectorHealth,
|
|
19164
|
+
recentCrashes: () => recentCrashes,
|
|
19109
19165
|
reportWalkProgress: () => reportWalkProgress,
|
|
19110
19166
|
updateCollectorHealth: () => updateCollectorHealth,
|
|
19111
19167
|
writeCollectorHealth: () => writeCollectorHealth
|
|
@@ -19174,6 +19230,20 @@ function reportWalkProgress(p) {
|
|
|
19174
19230
|
lastProgressWrite = now;
|
|
19175
19231
|
updateCollectorHealth({ progress: p });
|
|
19176
19232
|
}
|
|
19233
|
+
function crashesAtBoot(prior, procStart) {
|
|
19234
|
+
const history = (prior?.crashes ?? []).filter((t) => typeof t === "number");
|
|
19235
|
+
if (!prior)
|
|
19236
|
+
return history;
|
|
19237
|
+
const leftOnPurpose = typeof prior.cleanExitAt === "number" && prior.cleanExitAt >= prior.startedAt;
|
|
19238
|
+
return leftOnPurpose ? history : [...history, procStart];
|
|
19239
|
+
}
|
|
19240
|
+
function recentCrashes(crashes, now = Date.now()) {
|
|
19241
|
+
const cutoff = now - 36e5;
|
|
19242
|
+
return [...new Set(crashes.filter((t) => t > cutoff))].sort((a, b) => a - b).slice(-20);
|
|
19243
|
+
}
|
|
19244
|
+
function markCleanExit(now = Date.now()) {
|
|
19245
|
+
updateCollectorHealth({ cleanExitAt: now });
|
|
19246
|
+
}
|
|
19177
19247
|
function judgeHealth(h, now = Date.now()) {
|
|
19178
19248
|
if (!h)
|
|
19179
19249
|
return { ok: true, summary: null, reasons: [] };
|
|
@@ -19183,7 +19253,7 @@ function judgeHealth(h, now = Date.now()) {
|
|
|
19183
19253
|
reasons.push(`the collector has not reported for ${ago(silent)} \u2014 it may not be running`);
|
|
19184
19254
|
}
|
|
19185
19255
|
if (h.restartsLastHour >= CRASHLOOP_RESTARTS) {
|
|
19186
|
-
reasons.push(`it
|
|
19256
|
+
reasons.push(`it crashed ${h.restartsLastHour} times in the last hour`);
|
|
19187
19257
|
}
|
|
19188
19258
|
const targets = Object.entries(h.targets ?? {});
|
|
19189
19259
|
const stale = targets.filter(([, t]) => t.lastOkAt === null || now - t.lastOkAt > STALE_AFTER_MS);
|
|
@@ -19258,20 +19328,20 @@ async function probeServer(base3, opts = {}) {
|
|
|
19258
19328
|
if (res.status === 404 || res.status === 410) return { kind: "moved", status: res.status };
|
|
19259
19329
|
if (res.status >= 500) return { kind: "server_error", status: res.status };
|
|
19260
19330
|
if (!res.ok) return { kind: "moved", status: res.status };
|
|
19261
|
-
let
|
|
19331
|
+
let body2;
|
|
19262
19332
|
try {
|
|
19263
|
-
|
|
19333
|
+
body2 = await res.text();
|
|
19264
19334
|
} catch (err) {
|
|
19265
19335
|
return { kind: "unreachable", error: describeCause(err), reason: classifyUnreachable(err) };
|
|
19266
19336
|
}
|
|
19267
19337
|
let parsed;
|
|
19268
19338
|
try {
|
|
19269
|
-
parsed = JSON.parse(
|
|
19339
|
+
parsed = JSON.parse(body2);
|
|
19270
19340
|
} catch {
|
|
19271
|
-
return { kind: "not_api", status: res.status, snippet:
|
|
19341
|
+
return { kind: "not_api", status: res.status, snippet: body2.trim().slice(0, 60) };
|
|
19272
19342
|
}
|
|
19273
19343
|
if (typeof parsed?.apiVersion !== "number") {
|
|
19274
|
-
return { kind: "not_api", status: res.status, snippet:
|
|
19344
|
+
return { kind: "not_api", status: res.status, snippet: body2.trim().slice(0, 60) };
|
|
19275
19345
|
}
|
|
19276
19346
|
return {
|
|
19277
19347
|
kind: "ok",
|
|
@@ -19390,7 +19460,7 @@ function reportClientEvent(kind, opts = {}) {
|
|
|
19390
19460
|
try {
|
|
19391
19461
|
const targets = loadAllCredentials();
|
|
19392
19462
|
if (!targets.length) return;
|
|
19393
|
-
const
|
|
19463
|
+
const body2 = JSON.stringify({
|
|
19394
19464
|
events: [{
|
|
19395
19465
|
ts: Date.now(),
|
|
19396
19466
|
kind: String(kind).slice(0, 64),
|
|
@@ -19407,7 +19477,7 @@ function reportClientEvent(kind, opts = {}) {
|
|
|
19407
19477
|
void fetch(`${t.serverUrl.replace(/\/+$/, "")}/api/client-events`, {
|
|
19408
19478
|
method: "POST",
|
|
19409
19479
|
headers,
|
|
19410
|
-
body,
|
|
19480
|
+
body: body2,
|
|
19411
19481
|
signal: AbortSignal.timeout(3e3)
|
|
19412
19482
|
}).catch(() => {
|
|
19413
19483
|
});
|
|
@@ -19821,10 +19891,10 @@ async function fetchTenantSecurityConfig(cred) {
|
|
|
19821
19891
|
let tenantRules = [];
|
|
19822
19892
|
let rulePackVersion = null;
|
|
19823
19893
|
if (rulesRes.ok) {
|
|
19824
|
-
const
|
|
19825
|
-
const enabled = (
|
|
19894
|
+
const body2 = await rulesRes.json().catch(() => ({}));
|
|
19895
|
+
const enabled = (body2.rules || []).filter((r) => r.enabled !== false);
|
|
19826
19896
|
tenantRules = enabled;
|
|
19827
|
-
const packSpec =
|
|
19897
|
+
const packSpec = body2.pack?.rules ? { version: body2.pack.version, rules: body2.pack.rules.map((r) => ({ name: r.name, regex: r.regex, flags: r.flags, redact: true, source: r.source })) } : { version: body2.version, rules: enabled.filter((r) => r.redact === true).map((r) => ({ name: r.name, regex: r.regex, redact: true, source: "tenant" })) };
|
|
19828
19898
|
lastServerPackSpec = { version: packSpec.version || "", rules: packSpec.rules };
|
|
19829
19899
|
const pack = installServerRulePack(packSpec);
|
|
19830
19900
|
rulePackVersion = serverRulePackVersion();
|
|
@@ -19832,20 +19902,20 @@ async function fetchTenantSecurityConfig(cred) {
|
|
|
19832
19902
|
console.error(`[sync] server redaction rule "${r.name}" ignored: ${r.reason}`);
|
|
19833
19903
|
}
|
|
19834
19904
|
if (pack.accepted > 0) {
|
|
19835
|
-
const rev =
|
|
19905
|
+
const rev = body2.pack?.revision ? `, rev ${body2.pack.revision}` : "";
|
|
19836
19906
|
console.error(`[sync] ${pack.accepted} server redaction rule(s) active (pack ${rulePackVersion}${rev})`);
|
|
19837
19907
|
}
|
|
19838
19908
|
}
|
|
19839
19909
|
let verifySecrets = true;
|
|
19840
19910
|
if (settingsRes?.ok) {
|
|
19841
|
-
const
|
|
19842
|
-
if (typeof
|
|
19843
|
-
if (typeof
|
|
19844
|
-
setTelemetryEligible(base3,
|
|
19911
|
+
const body2 = await settingsRes.json().catch(() => ({}));
|
|
19912
|
+
if (typeof body2.verifySecrets === "boolean") verifySecrets = body2.verifySecrets;
|
|
19913
|
+
if (typeof body2.telemetry === "boolean") {
|
|
19914
|
+
setTelemetryEligible(base3, body2.telemetry);
|
|
19845
19915
|
try {
|
|
19846
19916
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
19847
19917
|
updateCollectorHealth({
|
|
19848
|
-
telemetryEligible: { ...prior, [base3]: { allowed:
|
|
19918
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
|
|
19849
19919
|
});
|
|
19850
19920
|
} catch {
|
|
19851
19921
|
}
|
|
@@ -19904,14 +19974,14 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
19904
19974
|
return EMPTY_SYNC_CONFIG;
|
|
19905
19975
|
}
|
|
19906
19976
|
if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
|
|
19907
|
-
const
|
|
19977
|
+
const body2 = await res.json().catch(() => ({}));
|
|
19908
19978
|
const config2 = {
|
|
19909
|
-
excludeTools: Array.isArray(
|
|
19910
|
-
excludeProjects: Array.isArray(
|
|
19979
|
+
excludeTools: Array.isArray(body2.excludeTools) ? body2.excludeTools.filter((t) => typeof t === "string") : [],
|
|
19980
|
+
excludeProjects: Array.isArray(body2.excludeProjects) ? body2.excludeProjects.filter((p) => typeof p === "string") : [],
|
|
19911
19981
|
// Ids only — installSourceExclusions drops anything else, so a server
|
|
19912
19982
|
// sending a path cannot make this collector read it.
|
|
19913
|
-
excludeSources: Array.isArray(
|
|
19914
|
-
approveSources: Array.isArray(
|
|
19983
|
+
excludeSources: Array.isArray(body2.excludeSources) ? body2.excludeSources.filter((x) => typeof x === "string") : [],
|
|
19984
|
+
approveSources: Array.isArray(body2.approveSources) ? body2.approveSources.filter((x) => typeof x === "string") : []
|
|
19915
19985
|
};
|
|
19916
19986
|
const applied = installSourceExclusions(config2.excludeSources);
|
|
19917
19987
|
if (applied.excluded > 0) {
|
|
@@ -20306,9 +20376,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20306
20376
|
const maxInflight = explicitThrottle ? 1 : isLocalHost(cred.serverUrl) ? Math.max(LOCAL_INFLIGHT, advertised ?? 0) : advertised ?? REMOTE_INFLIGHT_FALLBACK;
|
|
20307
20377
|
const UPLOAD_TIMEOUT_MS = Number(process.env.CHAT_RECALL_UPLOAD_TIMEOUT_MS) || 9e4;
|
|
20308
20378
|
const gzipBody = serverAcceptsGzipBody(cred.serverUrl);
|
|
20309
|
-
const post = async (
|
|
20379
|
+
const post = async (body2) => {
|
|
20310
20380
|
const payload = (() => {
|
|
20311
|
-
const withProgress = walkProgressForUpload ? { ...
|
|
20381
|
+
const withProgress = walkProgressForUpload ? { ...body2, progress: walkProgressForUpload } : body2;
|
|
20312
20382
|
const json = JSON.stringify(withProgress);
|
|
20313
20383
|
const raw = Buffer.from(json, "utf8");
|
|
20314
20384
|
return gzipBody ? gzipSync3(raw, { level: 6 }) : raw;
|
|
@@ -20332,25 +20402,25 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20332
20402
|
});
|
|
20333
20403
|
if (res.ok) {
|
|
20334
20404
|
acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
|
|
20335
|
-
const
|
|
20336
|
-
if (typeof
|
|
20337
|
-
setTelemetryEligible(base3,
|
|
20405
|
+
const body3 = await res.json().catch(() => ({}));
|
|
20406
|
+
if (typeof body3.telemetry === "boolean") {
|
|
20407
|
+
setTelemetryEligible(base3, body3.telemetry);
|
|
20338
20408
|
try {
|
|
20339
20409
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
20340
20410
|
updateCollectorHealth({
|
|
20341
|
-
telemetryEligible: { ...prior, [base3]: { allowed:
|
|
20411
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body3.telemetry, at: Date.now() } }
|
|
20342
20412
|
});
|
|
20343
20413
|
} catch {
|
|
20344
20414
|
}
|
|
20345
20415
|
}
|
|
20346
|
-
const adv =
|
|
20416
|
+
const adv = body3.limits?.ingestConcurrencyPerTenant;
|
|
20347
20417
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
20348
20418
|
setServerIngestConcurrency(base3, Math.floor(adv));
|
|
20349
20419
|
}
|
|
20350
|
-
if (
|
|
20420
|
+
if (body3.cli && body3.cli.version) {
|
|
20351
20421
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
20352
20422
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
20353
|
-
const plan = planAutoUpdate2(base3, { cli:
|
|
20423
|
+
const plan = planAutoUpdate2(base3, { cli: body3.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20354
20424
|
sweepStaleStaging2();
|
|
20355
20425
|
if (plan.update) {
|
|
20356
20426
|
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
@@ -20367,13 +20437,13 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20367
20437
|
if (res.status === 402) {
|
|
20368
20438
|
let detail = text;
|
|
20369
20439
|
try {
|
|
20370
|
-
const
|
|
20371
|
-
detail =
|
|
20372
|
-
if (
|
|
20373
|
-
${
|
|
20374
|
-
if (
|
|
20375
|
-
if (
|
|
20376
|
-
${
|
|
20440
|
+
const body3 = JSON.parse(text);
|
|
20441
|
+
detail = body3.error ?? text;
|
|
20442
|
+
if (body3.detail) detail += `
|
|
20443
|
+
${body3.detail}`;
|
|
20444
|
+
if (body3.resetsAt) detail += ` (resets ${new Date(body3.resetsAt).toISOString().slice(0, 10)})`;
|
|
20445
|
+
if (body3.upgradeUrl) detail += `
|
|
20446
|
+
${body3.upgradeUrl}`;
|
|
20377
20447
|
} catch {
|
|
20378
20448
|
}
|
|
20379
20449
|
throw classedError("payment_required", `sync paused by the server: ${detail}`);
|
|
@@ -20402,7 +20472,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20402
20472
|
let poolError = null;
|
|
20403
20473
|
const MAX_INFLIGHT_BYTES = (Number(process.env.CHAT_RECALL_MAX_INFLIGHT_MB) || 32) * 1024 * 1024;
|
|
20404
20474
|
let inflightBytes = 0;
|
|
20405
|
-
const submit = async (
|
|
20475
|
+
const submit = async (body2, after, bytesHint = 0) => {
|
|
20406
20476
|
while (inflight.size > 0 && (inflight.size >= maxInflight || inflightBytes + bytesHint > MAX_INFLIGHT_BYTES)) {
|
|
20407
20477
|
await Promise.race(inflight);
|
|
20408
20478
|
}
|
|
@@ -20410,7 +20480,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20410
20480
|
inflightBytes += bytesHint;
|
|
20411
20481
|
let task;
|
|
20412
20482
|
task = (async () => {
|
|
20413
|
-
await post(
|
|
20483
|
+
await post(body2);
|
|
20414
20484
|
after();
|
|
20415
20485
|
})().catch((e) => {
|
|
20416
20486
|
poolError = poolError ?? e;
|
|
@@ -20477,18 +20547,18 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20477
20547
|
signal: ac.signal
|
|
20478
20548
|
});
|
|
20479
20549
|
if (!res.ok) throw new Error(`append sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
20480
|
-
const
|
|
20481
|
-
if (
|
|
20550
|
+
const body2 = await res.json().catch(() => ({}));
|
|
20551
|
+
if (body2.cli && body2.cli.version) {
|
|
20482
20552
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
20483
20553
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
20484
|
-
const plan = planAutoUpdate2(base3, { cli:
|
|
20554
|
+
const plan = planAutoUpdate2(base3, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20485
20555
|
sweepStaleStaging2();
|
|
20486
20556
|
if (plan.update) {
|
|
20487
20557
|
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
20488
20558
|
});
|
|
20489
20559
|
}
|
|
20490
20560
|
}
|
|
20491
|
-
const fullNeeded = new Set(
|
|
20561
|
+
const fullNeeded = new Set(body2.full_resync_needed ?? []);
|
|
20492
20562
|
const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
|
|
20493
20563
|
if (acked.length > 0) {
|
|
20494
20564
|
try {
|
|
@@ -20523,9 +20593,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20523
20593
|
signal: ac.signal
|
|
20524
20594
|
});
|
|
20525
20595
|
if (!res.ok) throw new Error(`chunked head sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
20526
|
-
const
|
|
20596
|
+
const body2 = await res.json().catch(() => ({}));
|
|
20527
20597
|
const id = conv.session_id;
|
|
20528
|
-
const guarded = (
|
|
20598
|
+
const guarded = (body2.shrink_guarded ?? []).find((g) => g.session_id === id);
|
|
20529
20599
|
const mtime = conv.mtime;
|
|
20530
20600
|
try {
|
|
20531
20601
|
if (!guarded) {
|
|
@@ -21402,7 +21472,7 @@ var init_sync_client = __esm({
|
|
|
21402
21472
|
ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21403
21473
|
} catch {
|
|
21404
21474
|
try {
|
|
21405
|
-
if (true) ownVersion = "0.7.
|
|
21475
|
+
if (true) ownVersion = "0.7.9";
|
|
21406
21476
|
} catch {
|
|
21407
21477
|
}
|
|
21408
21478
|
}
|
|
@@ -21481,8 +21551,8 @@ async function fetchNpmLatest() {
|
|
|
21481
21551
|
headers: { accept: "application/vnd.npm.install-v1+json" }
|
|
21482
21552
|
}, 5e3);
|
|
21483
21553
|
if (!res.ok) return null;
|
|
21484
|
-
const
|
|
21485
|
-
const v =
|
|
21554
|
+
const body2 = await res.json();
|
|
21555
|
+
const v = body2["dist-tags"]?.latest;
|
|
21486
21556
|
return typeof v === "string" && v ? v : null;
|
|
21487
21557
|
} catch {
|
|
21488
21558
|
return null;
|
|
@@ -21664,9 +21734,9 @@ function envHome(varName, fallback) {
|
|
|
21664
21734
|
const v = process.env[varName];
|
|
21665
21735
|
return v && v.trim() ? v.trim() : fallback;
|
|
21666
21736
|
}
|
|
21667
|
-
function writeFileMkdir(path,
|
|
21737
|
+
function writeFileMkdir(path, body2) {
|
|
21668
21738
|
mkdirSync12(dirname21(path), { recursive: true });
|
|
21669
|
-
writeFileSync12(path,
|
|
21739
|
+
writeFileSync12(path, body2);
|
|
21670
21740
|
}
|
|
21671
21741
|
function readJsonObject(path) {
|
|
21672
21742
|
const raw = readFileSync37(path, "utf-8");
|
|
@@ -21748,8 +21818,8 @@ function registerCodexToml(path, spec) {
|
|
|
21748
21818
|
const lines = prev.length ? prev.split("\n") : [];
|
|
21749
21819
|
const start = lines.findIndex((l) => l.trim() === CODEX_HEADER);
|
|
21750
21820
|
if (start === -1) {
|
|
21751
|
-
const
|
|
21752
|
-
writeFileMkdir(path,
|
|
21821
|
+
const body2 = prev.length ? prev.replace(/\n*$/, "\n") + "\n" + block : block;
|
|
21822
|
+
writeFileMkdir(path, body2);
|
|
21753
21823
|
return { id, label, path, state: "created" };
|
|
21754
21824
|
}
|
|
21755
21825
|
let end = lines.length;
|
|
@@ -22290,8 +22360,8 @@ function parseCommandText(content, format, fallbackName) {
|
|
|
22290
22360
|
const t = parseScalarToml(content);
|
|
22291
22361
|
return { name: t.name || fallbackName, description: t.description || "", body: t.prompt || "" };
|
|
22292
22362
|
}
|
|
22293
|
-
const { fm, body } = parseFrontmatter4(content);
|
|
22294
|
-
return { name: fm.name || fallbackName, description: fm.description || "", body:
|
|
22363
|
+
const { fm, body: body2 } = parseFrontmatter4(content);
|
|
22364
|
+
return { name: fm.name || fallbackName, description: fm.description || "", body: body2.trim() };
|
|
22295
22365
|
}
|
|
22296
22366
|
function parseAgentText(content, format, fallbackName) {
|
|
22297
22367
|
if (format === "toml") {
|
|
@@ -22302,8 +22372,8 @@ function parseAgentText(content, format, fallbackName) {
|
|
|
22302
22372
|
body: t.developer_instructions || t.instructions || ""
|
|
22303
22373
|
};
|
|
22304
22374
|
}
|
|
22305
|
-
const { fm, body } = parseFrontmatter4(content);
|
|
22306
|
-
return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body:
|
|
22375
|
+
const { fm, body: body2 } = parseFrontmatter4(content);
|
|
22376
|
+
return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body2.trim() };
|
|
22307
22377
|
}
|
|
22308
22378
|
function readCommand(filePath, format) {
|
|
22309
22379
|
return parseCommandText(readFileSync40(filePath, "utf-8"), format, base(filePath));
|
|
@@ -22960,8 +23030,8 @@ function planPull(rows, opts = {}) {
|
|
|
22960
23030
|
continue;
|
|
22961
23031
|
const extra2 = parseExtra(row);
|
|
22962
23032
|
const name2 = extra2.skillName || row.title;
|
|
22963
|
-
const
|
|
22964
|
-
if (!name2 || typeof
|
|
23033
|
+
const body2 = extra2.body;
|
|
23034
|
+
if (!name2 || typeof body2 !== "string" || !body2.trim()) {
|
|
22965
23035
|
seenUnsupported.set("skill", (seenUnsupported.get("skill") || 0) + 1);
|
|
22966
23036
|
continue;
|
|
22967
23037
|
}
|
|
@@ -22970,7 +23040,7 @@ function planPull(rows, opts = {}) {
|
|
|
22970
23040
|
const prev2 = skillsByName.get(name2);
|
|
22971
23041
|
if (!prev2 || rank >= 0 && (prev2.rank < 0 || rank < prev2.rank)) {
|
|
22972
23042
|
skillsByName.set(name2, {
|
|
22973
|
-
body,
|
|
23043
|
+
body: body2,
|
|
22974
23044
|
rank,
|
|
22975
23045
|
truncated: extra2.bodyTruncated === true,
|
|
22976
23046
|
redacted: extra2.bodySecretsRedacted === true
|
|
@@ -22983,8 +23053,8 @@ function planPull(rows, opts = {}) {
|
|
|
22983
23053
|
continue;
|
|
22984
23054
|
const extra2 = parseExtra(row);
|
|
22985
23055
|
const name2 = extra2[type === "agent" ? "agentName" : "commandName"] || row.title;
|
|
22986
|
-
const
|
|
22987
|
-
if (!name2 || typeof
|
|
23056
|
+
const body2 = extra2.body;
|
|
23057
|
+
if (!name2 || typeof body2 !== "string" || !body2.trim() || extra2.bodyTruncated === true) {
|
|
22988
23058
|
seenUnsupported.set(type, (seenUnsupported.get(type) || 0) + 1);
|
|
22989
23059
|
continue;
|
|
22990
23060
|
}
|
|
@@ -22994,7 +23064,7 @@ function planPull(rows, opts = {}) {
|
|
|
22994
23064
|
const prev2 = bucket.get(name2);
|
|
22995
23065
|
if (!prev2 || rank >= 0 && (prev2.rank < 0 || rank < prev2.rank)) {
|
|
22996
23066
|
bucket.set(name2, {
|
|
22997
|
-
body,
|
|
23067
|
+
body: body2,
|
|
22998
23068
|
rank,
|
|
22999
23069
|
format: extra2.format === "toml" ? "toml" : "md",
|
|
23000
23070
|
redacted: extra2.bodySecretsRedacted === true
|
|
@@ -23063,7 +23133,7 @@ function executePull(rows, opts = {}) {
|
|
|
23063
23133
|
const explicit = new Set(opts.explicit ?? []);
|
|
23064
23134
|
const { mcps, skills, codecs, unsupported } = planPull(rows, opts);
|
|
23065
23135
|
const outcomes = [];
|
|
23066
|
-
for (const { name, body, truncated, redacted, tools } of skills) {
|
|
23136
|
+
for (const { name, body: body2, truncated, redacted, tools } of skills) {
|
|
23067
23137
|
for (const tool of tools) {
|
|
23068
23138
|
const dir = join51(skillsDirFor(tool), name);
|
|
23069
23139
|
const file = join51(dir, "SKILL.md");
|
|
@@ -23081,17 +23151,17 @@ function executePull(rows, opts = {}) {
|
|
|
23081
23151
|
}
|
|
23082
23152
|
try {
|
|
23083
23153
|
mkdirSync16(dir, { recursive: true });
|
|
23084
|
-
writeFileSync16(file,
|
|
23154
|
+
writeFileSync16(file, body2);
|
|
23085
23155
|
outcomes.push({ type: "skill", name, tool, status: "written", path: file, redactedContent: redacted });
|
|
23086
23156
|
} catch (e) {
|
|
23087
23157
|
outcomes.push({ type: "skill", name, tool, status: "failed", reason: e instanceof Error ? e.message : "write failed" });
|
|
23088
23158
|
}
|
|
23089
23159
|
}
|
|
23090
23160
|
}
|
|
23091
|
-
for (const { type, name, body, format, redacted, tools } of codecs) {
|
|
23161
|
+
for (const { type, name, body: body2, format, redacted, tools } of codecs) {
|
|
23092
23162
|
let art;
|
|
23093
23163
|
try {
|
|
23094
|
-
art = type === "agent" ? parseAgentText(
|
|
23164
|
+
art = type === "agent" ? parseAgentText(body2, format, name) : parseCommandText(body2, format, name);
|
|
23095
23165
|
} catch (e) {
|
|
23096
23166
|
for (const tool of tools) {
|
|
23097
23167
|
outcomes.push({ type, name, tool, status: "failed", reason: `could not parse the stored body: ${e instanceof Error ? e.message : "failed"}` });
|
|
@@ -24370,11 +24440,11 @@ async function collectCode(opts) {
|
|
|
24370
24440
|
for (const block of log22.split("\0END\0")) {
|
|
24371
24441
|
if (!block.includes("\0"))
|
|
24372
24442
|
continue;
|
|
24373
|
-
const [h,
|
|
24443
|
+
const [h, body2] = [block.slice(0, block.indexOf("\0")).trim(), block.slice(block.indexOf("\0") + 1)];
|
|
24374
24444
|
if (!h)
|
|
24375
24445
|
continue;
|
|
24376
24446
|
totalCommits++;
|
|
24377
|
-
if (AI_RE.test(
|
|
24447
|
+
if (AI_RE.test(body2)) {
|
|
24378
24448
|
aiCommits++;
|
|
24379
24449
|
try {
|
|
24380
24450
|
const files2 = execSync4(`git -C "${ws}" show --format= --name-only ${h}`, { encoding: "utf8", timeout: 2e4, maxBuffer: 64 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] });
|
|
@@ -25417,8 +25487,8 @@ async function runPull(base3, opts) {
|
|
|
25417
25487
|
try {
|
|
25418
25488
|
const res = await fetchWithTimeout(`${base3}/api/toolkit/browse/${type}?limit=1000`, { headers });
|
|
25419
25489
|
if (!res.ok) continue;
|
|
25420
|
-
const
|
|
25421
|
-
for (const it of
|
|
25490
|
+
const body2 = await res.json();
|
|
25491
|
+
for (const it of body2.items || []) rows.push(it);
|
|
25422
25492
|
} catch {
|
|
25423
25493
|
}
|
|
25424
25494
|
}
|
|
@@ -25563,7 +25633,7 @@ var init_intent_drain = __esm({
|
|
|
25563
25633
|
ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25564
25634
|
} catch {
|
|
25565
25635
|
try {
|
|
25566
|
-
if (true) ownVersion2 = "0.7.
|
|
25636
|
+
if (true) ownVersion2 = "0.7.9";
|
|
25567
25637
|
} catch {
|
|
25568
25638
|
}
|
|
25569
25639
|
}
|
|
@@ -25604,7 +25674,7 @@ function context(opts = {}) {
|
|
|
25604
25674
|
throw new TeamConfigError("Not joined to a team. Run `chat-recall team join <invite-token>`.");
|
|
25605
25675
|
return { serverUrl: t.serverUrl, token, handle: t.memberHandle ?? "", teamId: t.teamId };
|
|
25606
25676
|
}
|
|
25607
|
-
async function http(ctx, method, path,
|
|
25677
|
+
async function http(ctx, method, path, body2) {
|
|
25608
25678
|
const url = ctx.serverUrl.replace(/\/+$/, "") + path;
|
|
25609
25679
|
const r = await fetch(url, {
|
|
25610
25680
|
method,
|
|
@@ -25613,7 +25683,7 @@ async function http(ctx, method, path, body) {
|
|
|
25613
25683
|
"Content-Type": "application/json",
|
|
25614
25684
|
"Accept": "application/json"
|
|
25615
25685
|
},
|
|
25616
|
-
body:
|
|
25686
|
+
body: body2 == null ? void 0 : JSON.stringify(body2)
|
|
25617
25687
|
});
|
|
25618
25688
|
const text = await r.text();
|
|
25619
25689
|
let parsed = void 0;
|
|
@@ -25750,10 +25820,10 @@ var init_team_client = __esm({
|
|
|
25750
25820
|
TeamHttpError = class extends Error {
|
|
25751
25821
|
status;
|
|
25752
25822
|
body;
|
|
25753
|
-
constructor(msg, status,
|
|
25823
|
+
constructor(msg, status, body2) {
|
|
25754
25824
|
super(msg);
|
|
25755
25825
|
this.status = status;
|
|
25756
|
-
this.body =
|
|
25826
|
+
this.body = body2;
|
|
25757
25827
|
}
|
|
25758
25828
|
};
|
|
25759
25829
|
}
|
|
@@ -25846,8 +25916,8 @@ async function mergePullResult(opts) {
|
|
|
25846
25916
|
report.skipped.push({ artifactId: a.id, path: "(no installed target tool)", reason: "no-target-tool" });
|
|
25847
25917
|
continue;
|
|
25848
25918
|
}
|
|
25849
|
-
const
|
|
25850
|
-
const sha = createHash14("sha256").update(
|
|
25919
|
+
const body2 = Buffer.from(a.bodyB64, "base64");
|
|
25920
|
+
const sha = createHash14("sha256").update(body2).digest("hex");
|
|
25851
25921
|
for (const tool of targets) {
|
|
25852
25922
|
const path = installPathFor(a, tool);
|
|
25853
25923
|
if (!path)
|
|
@@ -25860,7 +25930,7 @@ async function mergePullResult(opts) {
|
|
|
25860
25930
|
continue;
|
|
25861
25931
|
}
|
|
25862
25932
|
mkdirSync20(dirname27(path), { recursive: true });
|
|
25863
|
-
writeFileSync20(path,
|
|
25933
|
+
writeFileSync20(path, body2);
|
|
25864
25934
|
pending.push({ artifactId: a.id, tool, artifactType: a.type, artifactName: a.name, sha256: sha, installedAt: Date.now() });
|
|
25865
25935
|
report.written.push({ artifactId: a.id, path });
|
|
25866
25936
|
} catch (err) {
|
|
@@ -26166,7 +26236,7 @@ function context2() {
|
|
|
26166
26236
|
throw new VaultConfigError(`Env var ${s.tokenRef} is not set.`);
|
|
26167
26237
|
return { serverUrl: s.serverUrl, teamId: s.teamId, token };
|
|
26168
26238
|
}
|
|
26169
|
-
async function api(ctx, method, path,
|
|
26239
|
+
async function api(ctx, method, path, body2) {
|
|
26170
26240
|
const doFetch = () => fetch(ctx.serverUrl.replace(/\/+$/, "") + path, {
|
|
26171
26241
|
method,
|
|
26172
26242
|
headers: {
|
|
@@ -26174,7 +26244,7 @@ async function api(ctx, method, path, body) {
|
|
|
26174
26244
|
"Content-Type": "application/json",
|
|
26175
26245
|
"Accept": "application/json"
|
|
26176
26246
|
},
|
|
26177
|
-
body:
|
|
26247
|
+
body: body2 == null ? void 0 : JSON.stringify(body2)
|
|
26178
26248
|
});
|
|
26179
26249
|
let r;
|
|
26180
26250
|
try {
|
|
@@ -26253,13 +26323,13 @@ async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
|
|
|
26253
26323
|
body: JSON.stringify({ saltHex: result.saltHex, keyId: result.keyId })
|
|
26254
26324
|
});
|
|
26255
26325
|
if (r.status === 409) {
|
|
26256
|
-
const
|
|
26257
|
-
if (
|
|
26258
|
-
const redone = vaultEnable(passphrase, { existingSaltHex:
|
|
26259
|
-
if (
|
|
26326
|
+
const body2 = await r.json();
|
|
26327
|
+
if (body2.saltHex && body2.saltHex !== result.saltHex) {
|
|
26328
|
+
const redone = vaultEnable(passphrase, { existingSaltHex: body2.saltHex });
|
|
26329
|
+
if (body2.keyId && body2.keyId !== redone.keyId) {
|
|
26260
26330
|
throw new VaultPassphraseMismatchError("Another device published a vault with a different passphrase. Nothing was changed here.");
|
|
26261
26331
|
}
|
|
26262
|
-
return { ...redone, saltSource: "server", keyIdMatches:
|
|
26332
|
+
return { ...redone, saltSource: "server", keyIdMatches: body2.keyId ? true : void 0 };
|
|
26263
26333
|
}
|
|
26264
26334
|
}
|
|
26265
26335
|
} catch (err) {
|
|
@@ -26421,10 +26491,10 @@ var init_vault_client = __esm({
|
|
|
26421
26491
|
VaultHttpError = class extends Error {
|
|
26422
26492
|
status;
|
|
26423
26493
|
body;
|
|
26424
|
-
constructor(msg, status,
|
|
26494
|
+
constructor(msg, status, body2) {
|
|
26425
26495
|
super(msg);
|
|
26426
26496
|
this.status = status;
|
|
26427
|
-
this.body =
|
|
26497
|
+
this.body = body2;
|
|
26428
26498
|
}
|
|
26429
26499
|
};
|
|
26430
26500
|
uploadKey = (sessionId, tool) => `${sessionId}\0${tool}`;
|
|
@@ -27321,15 +27391,15 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
27321
27391
|
code_verifier: codeVerifier
|
|
27322
27392
|
})
|
|
27323
27393
|
});
|
|
27324
|
-
const
|
|
27325
|
-
if (res.ok && typeof
|
|
27394
|
+
const body2 = await res.json().catch(() => ({}));
|
|
27395
|
+
if (res.ok && typeof body2.access_token === "string") {
|
|
27326
27396
|
return {
|
|
27327
|
-
accessToken:
|
|
27328
|
-
refreshToken: typeof
|
|
27329
|
-
expiresIn: typeof
|
|
27397
|
+
accessToken: body2.access_token,
|
|
27398
|
+
refreshToken: typeof body2.refresh_token === "string" ? body2.refresh_token : void 0,
|
|
27399
|
+
expiresIn: typeof body2.expires_in === "number" ? body2.expires_in : 0
|
|
27330
27400
|
};
|
|
27331
27401
|
}
|
|
27332
|
-
const err =
|
|
27402
|
+
const err = body2.error;
|
|
27333
27403
|
if (err === "authorization_pending") continue;
|
|
27334
27404
|
if (err === "slow_down") {
|
|
27335
27405
|
interval += 5e3;
|
|
@@ -27369,14 +27439,14 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27369
27439
|
client_id: BETTER_AUTH_CLI_CLIENT_ID
|
|
27370
27440
|
})
|
|
27371
27441
|
});
|
|
27372
|
-
const
|
|
27373
|
-
if (res.ok && typeof
|
|
27442
|
+
const body2 = await res.json().catch(() => ({}));
|
|
27443
|
+
if (res.ok && typeof body2.access_token === "string") {
|
|
27374
27444
|
return {
|
|
27375
|
-
accessToken:
|
|
27376
|
-
expiresIn: typeof
|
|
27445
|
+
accessToken: body2.access_token,
|
|
27446
|
+
expiresIn: typeof body2.expires_in === "number" ? body2.expires_in : 0
|
|
27377
27447
|
};
|
|
27378
27448
|
}
|
|
27379
|
-
const err =
|
|
27449
|
+
const err = body2.error;
|
|
27380
27450
|
if (err === "authorization_pending") continue;
|
|
27381
27451
|
if (err === "slow_down") {
|
|
27382
27452
|
interval += 5e3;
|
|
@@ -27466,8 +27536,8 @@ async function selectSessions(target, opts, fetchImpl = fetch) {
|
|
|
27466
27536
|
headers: { authorization: `Bearer ${target.token}` }
|
|
27467
27537
|
});
|
|
27468
27538
|
if (!res.ok) throw new Error(`list failed: HTTP ${res.status}`);
|
|
27469
|
-
const
|
|
27470
|
-
const page =
|
|
27539
|
+
const body2 = await res.json();
|
|
27540
|
+
const page = body2.sessions ?? [];
|
|
27471
27541
|
if (page.length === 0) break;
|
|
27472
27542
|
for (const row of page) {
|
|
27473
27543
|
if (!row.sessionId) continue;
|
|
@@ -27550,9 +27620,9 @@ async function restoreSessions(ids, opts = {}) {
|
|
|
27550
27620
|
body: JSON.stringify({ session_ids: unique.slice(i, i + BATCH) })
|
|
27551
27621
|
});
|
|
27552
27622
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
27553
|
-
const
|
|
27554
|
-
restored +=
|
|
27555
|
-
notDeleted += (
|
|
27623
|
+
const body2 = await res.json();
|
|
27624
|
+
restored += body2.restored ?? 0;
|
|
27625
|
+
notDeleted += (body2.notDeleted ?? []).length;
|
|
27556
27626
|
}
|
|
27557
27627
|
out.perTarget[t.serverUrl] = { restored, notDeleted };
|
|
27558
27628
|
best = Math.max(best, restored);
|
|
@@ -27618,6 +27688,104 @@ function resumeCommandFor(sessionId, tool) {
|
|
|
27618
27688
|
}
|
|
27619
27689
|
}
|
|
27620
27690
|
|
|
27691
|
+
// ../engine/dist/mcp/show-render.js
|
|
27692
|
+
var BODY_LIMIT = 2e3;
|
|
27693
|
+
var EDGE = 100;
|
|
27694
|
+
var INDENT = " ";
|
|
27695
|
+
var oneLine = (v) => String(v).replace(/\s*\n\s*/g, " \u23CE ");
|
|
27696
|
+
var indent = (text) => text.split("\n").map((l) => INDENT + l).join("\n");
|
|
27697
|
+
function safeSlice(s, start, end) {
|
|
27698
|
+
const lo = start > 0 && /[\uDC00-\uDFFF]/.test(s[start] ?? "") ? start - 1 : start;
|
|
27699
|
+
const hi = end < s.length && /[\uD800-\uDBFF]/.test(s[end - 1] ?? "") ? end + 1 : end;
|
|
27700
|
+
return s.slice(lo, hi);
|
|
27701
|
+
}
|
|
27702
|
+
function body(text, line, opts) {
|
|
27703
|
+
if (opts.full || text.length <= BODY_LIMIT)
|
|
27704
|
+
return indent(text);
|
|
27705
|
+
const lines = text.split("\n").length;
|
|
27706
|
+
const cut = text.length - 2 * EDGE;
|
|
27707
|
+
const how = opts.expandHint ? ` ${opts.expandHint(line)}` : "";
|
|
27708
|
+
return [
|
|
27709
|
+
indent(safeSlice(text, 0, EDGE)),
|
|
27710
|
+
`${INDENT}\u2026 ${cut} characters cut (${text.length} in all, ${lines} lines).${how} \u2026`,
|
|
27711
|
+
indent(safeSlice(text, text.length - EDGE, text.length))
|
|
27712
|
+
].join("\n");
|
|
27713
|
+
}
|
|
27714
|
+
function resultText(result) {
|
|
27715
|
+
if (typeof result === "string")
|
|
27716
|
+
return result;
|
|
27717
|
+
if (Array.isArray(result)) {
|
|
27718
|
+
return result.map((b) => {
|
|
27719
|
+
if (b?.type === "text")
|
|
27720
|
+
return String(b.text ?? "");
|
|
27721
|
+
if (b?.type === "image")
|
|
27722
|
+
return "[image]";
|
|
27723
|
+
if (b?.type === "tool_reference")
|
|
27724
|
+
return `[tool_reference: ${b.tool_name ?? ""}]`;
|
|
27725
|
+
return JSON.stringify(b);
|
|
27726
|
+
}).join("\n");
|
|
27727
|
+
}
|
|
27728
|
+
return JSON.stringify(result);
|
|
27729
|
+
}
|
|
27730
|
+
function renderToolCall(tc, line, opts) {
|
|
27731
|
+
const inp = tc.input && typeof tc.input === "object" ? tc.input : {};
|
|
27732
|
+
const out = [];
|
|
27733
|
+
if (tc.name === "Bash" && inp.command !== void 0) {
|
|
27734
|
+
const desc = inp.description ? ` # ${oneLine(inp.description)}` : "";
|
|
27735
|
+
out.push(`[Bash]${desc}
|
|
27736
|
+
$ ${oneLine(inp.command)}`);
|
|
27737
|
+
} else if (inp.file_path !== void 0) {
|
|
27738
|
+
const inline = {};
|
|
27739
|
+
const blocks = [];
|
|
27740
|
+
for (const [k, v] of Object.entries(inp)) {
|
|
27741
|
+
if (k === "file_path")
|
|
27742
|
+
continue;
|
|
27743
|
+
if (typeof v === "string" && (v.includes("\n") || v.length > 120))
|
|
27744
|
+
blocks.push([k, v]);
|
|
27745
|
+
else
|
|
27746
|
+
inline[k] = v;
|
|
27747
|
+
}
|
|
27748
|
+
const opts_ = Object.keys(inline).length ? ` ${JSON.stringify(inline)}` : "";
|
|
27749
|
+
out.push(`[${tc.name}] ${inp.file_path}${opts_}`);
|
|
27750
|
+
for (const [k, v] of blocks)
|
|
27751
|
+
out.push(` ${k}:`, body(v, line, opts));
|
|
27752
|
+
} else if (typeof tc.input === "string") {
|
|
27753
|
+
out.push(`[${tc.name}]`, body(tc.input, line, opts));
|
|
27754
|
+
} else {
|
|
27755
|
+
const json = JSON.stringify(tc.input ?? {});
|
|
27756
|
+
if (opts.full || json.length <= BODY_LIMIT)
|
|
27757
|
+
out.push(`[${tc.name}] ${oneLine(json)}`);
|
|
27758
|
+
else
|
|
27759
|
+
out.push(`[${tc.name}]`, body(json, line, opts));
|
|
27760
|
+
}
|
|
27761
|
+
if (tc.result !== void 0) {
|
|
27762
|
+
out.push(tc.isError ? " \u2192 error:" : " \u2192 result:", body(resultText(tc.result), line, opts));
|
|
27763
|
+
}
|
|
27764
|
+
return out.join("\n");
|
|
27765
|
+
}
|
|
27766
|
+
function renderShowMessages(messages, opts = {}) {
|
|
27767
|
+
const out = [];
|
|
27768
|
+
for (const msg of messages) {
|
|
27769
|
+
const text = msg.content ?? "";
|
|
27770
|
+
const thinking = msg.thinking ?? "";
|
|
27771
|
+
const calls = msg.toolCalls ?? [];
|
|
27772
|
+
if (!text.trim() && !thinking.trim() && !calls.length && msg.thinking !== void 0)
|
|
27773
|
+
continue;
|
|
27774
|
+
out.push(`**${msg.role}** (line ${msg.line})`);
|
|
27775
|
+
if (thinking.trim())
|
|
27776
|
+
out.push(`_(thinking)_
|
|
27777
|
+
${thinking}`);
|
|
27778
|
+
if (text.trim())
|
|
27779
|
+
out.push(text);
|
|
27780
|
+
for (const tc of calls)
|
|
27781
|
+
out.push(renderToolCall(tc, msg.line, opts));
|
|
27782
|
+
if (!text.trim() && !thinking.trim() && !calls.length)
|
|
27783
|
+
out.push("_(empty)_");
|
|
27784
|
+
out.push("");
|
|
27785
|
+
}
|
|
27786
|
+
return out;
|
|
27787
|
+
}
|
|
27788
|
+
|
|
27621
27789
|
// src/cli.ts
|
|
27622
27790
|
init_paths();
|
|
27623
27791
|
init_claude2();
|
|
@@ -27850,38 +28018,38 @@ async function serverGetSoft(path) {
|
|
|
27850
28018
|
const t = requireTarget();
|
|
27851
28019
|
const res = await fetch(t.base + path, { headers: t.token ? { authorization: `Bearer ${t.token}` } : {} });
|
|
27852
28020
|
if (res.status === 202 || res.status === 404) {
|
|
27853
|
-
const
|
|
27854
|
-
return { status: res.status, data: null, message:
|
|
28021
|
+
const body2 = await res.json().catch(() => ({}));
|
|
28022
|
+
return { status: res.status, data: null, message: body2.message };
|
|
27855
28023
|
}
|
|
27856
28024
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27857
28025
|
return { status: res.status, data: await readJsonBody(res, t.base, `GET ${path}`) };
|
|
27858
28026
|
}
|
|
27859
|
-
async function serverPost(path,
|
|
28027
|
+
async function serverPost(path, body2) {
|
|
27860
28028
|
const t = requireTarget();
|
|
27861
28029
|
const res = await fetch(t.base + path, {
|
|
27862
28030
|
method: "POST",
|
|
27863
28031
|
headers: t.token ? { "content-type": "application/json", authorization: `Bearer ${t.token}` } : { "content-type": "application/json" },
|
|
27864
|
-
body: JSON.stringify(
|
|
28032
|
+
body: JSON.stringify(body2)
|
|
27865
28033
|
});
|
|
27866
28034
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27867
28035
|
return readJsonBody(res, t.base, `POST ${path}`);
|
|
27868
28036
|
}
|
|
27869
|
-
async function serverPatch(path,
|
|
28037
|
+
async function serverPatch(path, body2) {
|
|
27870
28038
|
const t = requireTarget();
|
|
27871
28039
|
const res = await fetch(t.base + path, {
|
|
27872
28040
|
method: "PATCH",
|
|
27873
28041
|
headers: t.token ? { "content-type": "application/json", authorization: `Bearer ${t.token}` } : { "content-type": "application/json" },
|
|
27874
|
-
body: JSON.stringify(
|
|
28042
|
+
body: JSON.stringify(body2)
|
|
27875
28043
|
});
|
|
27876
28044
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27877
28045
|
return readJsonBody(res, t.base, `PATCH ${path}`);
|
|
27878
28046
|
}
|
|
27879
|
-
async function serverDelete(path,
|
|
28047
|
+
async function serverDelete(path, body2) {
|
|
27880
28048
|
const t = requireTarget();
|
|
27881
28049
|
const res = await fetch(t.base + path, {
|
|
27882
28050
|
method: "DELETE",
|
|
27883
28051
|
headers: t.token ? { "content-type": "application/json", authorization: `Bearer ${t.token}` } : { "content-type": "application/json" },
|
|
27884
|
-
body: JSON.stringify(
|
|
28052
|
+
body: JSON.stringify(body2)
|
|
27885
28053
|
});
|
|
27886
28054
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27887
28055
|
return readJsonBody(res, t.base, `DELETE ${path}`);
|
|
@@ -28168,15 +28336,15 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
28168
28336
|
continue;
|
|
28169
28337
|
}
|
|
28170
28338
|
const text = await res.text();
|
|
28171
|
-
let
|
|
28339
|
+
let body2;
|
|
28172
28340
|
try {
|
|
28173
|
-
|
|
28341
|
+
body2 = JSON.parse(text);
|
|
28174
28342
|
} catch {
|
|
28175
28343
|
askFailed.push(`${t.serverUrl} (not JSON: ${JSON.stringify(text.trim().slice(0, 40))})`);
|
|
28176
28344
|
continue;
|
|
28177
28345
|
}
|
|
28178
28346
|
answered++;
|
|
28179
|
-
for (const it of
|
|
28347
|
+
for (const it of body2.items || []) rows.push(it);
|
|
28180
28348
|
} catch (e) {
|
|
28181
28349
|
askFailed.push(`${t.serverUrl} (${describeProbeError(e)})`);
|
|
28182
28350
|
}
|
|
@@ -28425,7 +28593,7 @@ program.command("optimize").description("Deprecated: storage is server-side now,
|
|
|
28425
28593
|
console.log(chalk2.dim("Run `chat-recall sync` to ship sessions; the server manages its own storage."));
|
|
28426
28594
|
process.exit(0);
|
|
28427
28595
|
});
|
|
28428
|
-
program.command("show <session_id>").description("Show conversation content from a session (requires login)").option("-m, --messages <number>", "Number of messages to show", "10").option("-f, --full", "Show full conversation (all messages)", false).action(async (sessionId, options) => {
|
|
28596
|
+
program.command("show <session_id>").description("Show conversation content from a session (requires login)").option("-m, --messages <number>", "Number of messages to show", "10").option("-f, --full", "Show full conversation (all messages)", false).option("-l, --line <number>", "Show only the message at this line, with every tool input and result whole").action(async (sessionId, options) => {
|
|
28429
28597
|
try {
|
|
28430
28598
|
const soft = await serverGetSoft(`/api/conversations/${encodeURIComponent(sessionId)}?limit=0`);
|
|
28431
28599
|
if (!soft.data || soft.data.messages.length === 0) {
|
|
@@ -28435,20 +28603,21 @@ program.command("show <session_id>").description("Show conversation content from
|
|
|
28435
28603
|
const messagesList = soft.data.messages;
|
|
28436
28604
|
console.log(chalk2.bold("Session:"), sessionId);
|
|
28437
28605
|
console.log();
|
|
28438
|
-
|
|
28439
|
-
|
|
28440
|
-
|
|
28441
|
-
|
|
28442
|
-
|
|
28443
|
-
console.log(
|
|
28444
|
-
|
|
28445
|
-
console.log(`${chalk2.bold.green("Assistant")} ${chalk2.dim(`(line ${msg.line})`)}`);
|
|
28446
|
-
} else {
|
|
28447
|
-
console.log(chalk2.bold.yellow(msg.role));
|
|
28606
|
+
if (options.line !== void 0) {
|
|
28607
|
+
const line = parseInt(options.line, 10);
|
|
28608
|
+
const hit = messagesList.find((m) => m.line === line);
|
|
28609
|
+
if (!hit) {
|
|
28610
|
+
const lines = messagesList.map((m) => m.line);
|
|
28611
|
+
console.log(chalk2.yellow(`No message at line ${options.line}. Its lines run from ${Math.min(...lines)} to ${Math.max(...lines)}.`));
|
|
28612
|
+
process.exit(1);
|
|
28448
28613
|
}
|
|
28449
|
-
console.log(
|
|
28450
|
-
|
|
28614
|
+
console.log(renderShowMessages([hit], { full: true }).join("\n"));
|
|
28615
|
+
return;
|
|
28451
28616
|
}
|
|
28617
|
+
const maxMessages = parseInt(options.messages, 10);
|
|
28618
|
+
const displayMessages = options.full ? messagesList : messagesList.slice(0, maxMessages);
|
|
28619
|
+
const expandHint = (line) => `Run chat-recall show ${sessionId} --line ${line} for the whole text.`;
|
|
28620
|
+
console.log(renderShowMessages(displayMessages, { expandHint }).join("\n"));
|
|
28452
28621
|
console.log(chalk2.dim(`Showing ${displayMessages.length} of ${messagesList.length} messages. Use --full for the complete conversation.`));
|
|
28453
28622
|
{
|
|
28454
28623
|
const rc = resumeCommandFor(sessionId);
|
|
@@ -28661,8 +28830,8 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
28661
28830
|
signal: AbortSignal.timeout(1e4)
|
|
28662
28831
|
});
|
|
28663
28832
|
if (!res.ok) {
|
|
28664
|
-
const
|
|
28665
|
-
console.error(chalk2.red(`Could not send: ${
|
|
28833
|
+
const body2 = await res.json().catch(() => ({}));
|
|
28834
|
+
console.error(chalk2.red(`Could not send: ${body2.error || res.status}`));
|
|
28666
28835
|
process.exitCode = 1;
|
|
28667
28836
|
return;
|
|
28668
28837
|
}
|
|
@@ -29079,8 +29248,8 @@ program.command("verify").description("Check that the server holds everything th
|
|
|
29079
29248
|
if (token) headers.authorization = `Bearer ${token}`;
|
|
29080
29249
|
const res = await fetchWithTimeout2(`${server}/api/status/archives`, { headers }, 12e4);
|
|
29081
29250
|
if (!res.ok) throw new Error(`${server}: HTTP ${res.status} from /api/status/archives`);
|
|
29082
|
-
const
|
|
29083
|
-
return new Map((
|
|
29251
|
+
const body2 = await res.json();
|
|
29252
|
+
return new Map((body2.archives || []).map((a) => [a.id, Number(a.size) || 0]));
|
|
29084
29253
|
}
|
|
29085
29254
|
};
|
|
29086
29255
|
let exitCode = 0;
|
|
@@ -29132,8 +29301,8 @@ ${t.serverUrl}`));
|
|
|
29132
29301
|
console.log(` ${f.sessionId.slice(0, 8)} server records unavailable (HTTP ${res.status})`);
|
|
29133
29302
|
continue;
|
|
29134
29303
|
}
|
|
29135
|
-
const
|
|
29136
|
-
serverIds = new Set(
|
|
29304
|
+
const body2 = await res.json();
|
|
29305
|
+
serverIds = new Set(body2.records || []);
|
|
29137
29306
|
} catch (e) {
|
|
29138
29307
|
console.log(` ${f.sessionId.slice(0, 8)} record fetch failed: ${e instanceof Error ? e.message : e}`);
|
|
29139
29308
|
continue;
|
|
@@ -29453,8 +29622,8 @@ toolkit.command("pull").description("Install artifacts this device is missing, f
|
|
|
29453
29622
|
headers: t.token ? { authorization: `Bearer ${t.token}` } : {}
|
|
29454
29623
|
});
|
|
29455
29624
|
if (!res.ok) continue;
|
|
29456
|
-
const
|
|
29457
|
-
for (const it of
|
|
29625
|
+
const body2 = await res.json();
|
|
29626
|
+
for (const it of body2.items || []) rows.push(it);
|
|
29458
29627
|
} catch (err) {
|
|
29459
29628
|
console.log(chalk2.dim(` (${t.serverUrl} ${type}: ${err instanceof Error ? err.message : err})`));
|
|
29460
29629
|
}
|
|
@@ -29696,13 +29865,13 @@ team.command("publish <type> <name> <file>").description("Publish a local file a
|
|
|
29696
29865
|
process.exit(1);
|
|
29697
29866
|
}
|
|
29698
29867
|
const { readFileSync: readFileSync50 } = await import("fs");
|
|
29699
|
-
const
|
|
29868
|
+
const body2 = readFileSync50(file);
|
|
29700
29869
|
const { teamPublish: teamPublish2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
|
|
29701
29870
|
const a = await teamPublish2({
|
|
29702
29871
|
type,
|
|
29703
29872
|
tool: opts.tool,
|
|
29704
29873
|
name,
|
|
29705
|
-
body,
|
|
29874
|
+
body: body2,
|
|
29706
29875
|
pinnedTo: opts.pinnedTo
|
|
29707
29876
|
});
|
|
29708
29877
|
console.log(chalk2.green(`\u2713 Published ${chalk2.bold(type + "/" + name)} v${a.version}`));
|
|
@@ -29995,13 +30164,13 @@ program.command("task-hook").description("Move a board card when a prompt or a c
|
|
|
29995
30164
|
4e3
|
|
29996
30165
|
);
|
|
29997
30166
|
if (!res.ok) return null;
|
|
29998
|
-
const
|
|
29999
|
-
return
|
|
30167
|
+
const body2 = await res.json().catch(() => ({}));
|
|
30168
|
+
return body2.task ?? null;
|
|
30000
30169
|
};
|
|
30001
|
-
const patchCard = async (id,
|
|
30170
|
+
const patchCard = async (id, body2) => {
|
|
30002
30171
|
const res = await fetchWithTimeout2(
|
|
30003
30172
|
`${target.base}/api/tasks/${encodeURIComponent(id)}`,
|
|
30004
|
-
{ method: "PATCH", headers, body: JSON.stringify(
|
|
30173
|
+
{ method: "PATCH", headers, body: JSON.stringify(body2) },
|
|
30005
30174
|
6e3
|
|
30006
30175
|
);
|
|
30007
30176
|
return res.ok;
|
|
@@ -30166,8 +30335,8 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30166
30335
|
for (const target of reg.guardTargets()) {
|
|
30167
30336
|
if (!existsSync58(target.configPath)) continue;
|
|
30168
30337
|
if (target.tool === "opencode") {
|
|
30169
|
-
const
|
|
30170
|
-
if (!
|
|
30338
|
+
const body2 = readFileSync50(target.configPath, "utf-8");
|
|
30339
|
+
if (!body2.includes("chat-recall install-hooks")) continue;
|
|
30171
30340
|
unlinkSync4(target.configPath);
|
|
30172
30341
|
removed += 1;
|
|
30173
30342
|
} else {
|