chat-recall 0.7.23 → 0.7.25
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/README.md +5 -5
- package/dist/cli.js +266 -69
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +339 -140
- package/dist/message-hook-core.d.ts.map +1 -1
- package/dist/message-hook-core.js +4 -1
- package/dist/message-hook-core.js.map +1 -1
- package/dist/message-hook.js +15 -6
- package/dist/message-hook.js.map +1 -1
- package/dist/scan-worker.js +138 -14
- package/dist/watch.js +181 -57
- package/package.json +1 -1
- package/skills/chat-recall-sessions/SKILL.md +7 -3
package/dist/mcp.js
CHANGED
|
@@ -6412,6 +6412,130 @@ var init_sqlite_reader = __esm({
|
|
|
6412
6412
|
}
|
|
6413
6413
|
});
|
|
6414
6414
|
|
|
6415
|
+
// ../engine/dist/core/backends/opencode-v2.js
|
|
6416
|
+
function hasTable(db, name) {
|
|
6417
|
+
return !!db.prepare("SELECT 1 FROM main.sqlite_master WHERE type = 'table' AND name = ?").get(name);
|
|
6418
|
+
}
|
|
6419
|
+
function columnsOf(db, table) {
|
|
6420
|
+
return new Set(db.prepare(`SELECT name FROM pragma_table_info('${table}', 'main')`).all().map((r) => r.name));
|
|
6421
|
+
}
|
|
6422
|
+
function installOpencodeV2Views(db) {
|
|
6423
|
+
if (!hasTable(db, "session_v2") || !hasTable(db, "session_message"))
|
|
6424
|
+
return false;
|
|
6425
|
+
const v2Cols = columnsOf(db, "session_v2");
|
|
6426
|
+
const sessionCols = SESSION_COLUMNS.map((c) => v2Cols.has(c) ? c : `NULL AS ${c}`).join(", ");
|
|
6427
|
+
const hasV1 = hasTable(db, "message") && hasTable(db, "part");
|
|
6428
|
+
const v1Messages = hasV1 ? `SELECT id, session_id, time_created, time_updated, data FROM main.message WHERE session_id NOT IN (${V2_SESSIONS}) UNION ALL ` : "";
|
|
6429
|
+
const v1Parts = hasV1 ? `SELECT id, message_id, session_id, time_created, time_updated, data FROM main.part WHERE session_id NOT IN (${V2_SESSIONS}) UNION ALL ` : "";
|
|
6430
|
+
db.exec(`
|
|
6431
|
+
CREATE TEMP VIEW IF NOT EXISTS session AS SELECT ${sessionCols} FROM main.session_v2;
|
|
6432
|
+
|
|
6433
|
+
CREATE TEMP VIEW IF NOT EXISTS message AS
|
|
6434
|
+
${v1Messages}
|
|
6435
|
+
SELECT m.id, m.session_id, m.time_created, m.time_updated,
|
|
6436
|
+
CASE m.type
|
|
6437
|
+
WHEN 'user' THEN json_object('role', 'user', 'time', ${j("$.time")})
|
|
6438
|
+
ELSE json_object(
|
|
6439
|
+
'role', 'assistant',
|
|
6440
|
+
'agent', json_extract(m.data, '$.agent'),
|
|
6441
|
+
'modelID', json_extract(m.data, '$.model.id'),
|
|
6442
|
+
'providerID', json_extract(m.data, '$.model.providerID'),
|
|
6443
|
+
'cost', coalesce(json_extract(m.data, '$.cost'), 0),
|
|
6444
|
+
'tokens', ${j("$.tokens")},
|
|
6445
|
+
'time', ${j("$.time")})
|
|
6446
|
+
END AS data
|
|
6447
|
+
FROM main.session_message m WHERE m.type IN ('user', 'assistant');
|
|
6448
|
+
|
|
6449
|
+
CREATE TEMP VIEW IF NOT EXISTS part AS
|
|
6450
|
+
${v1Parts}
|
|
6451
|
+
SELECT m.id || ':text', m.id, m.session_id, m.time_created, m.time_updated,
|
|
6452
|
+
json_object('type', 'text', 'text', json_extract(m.data, '$.text'))
|
|
6453
|
+
FROM main.session_message m
|
|
6454
|
+
WHERE m.type = 'user' AND json_extract(m.data, '$.text') IS NOT NULL
|
|
6455
|
+
UNION ALL
|
|
6456
|
+
SELECT m.id || ':' || c.key, m.id, m.session_id, m.time_created + c.key, m.time_updated,
|
|
6457
|
+
CASE json_extract(c.value, '$.type')
|
|
6458
|
+
WHEN 'tool' THEN json_object(
|
|
6459
|
+
'type', 'tool',
|
|
6460
|
+
'tool', json_extract(c.value, '$.name'),
|
|
6461
|
+
'callID', json_extract(c.value, '$.id'),
|
|
6462
|
+
'state', json_object(
|
|
6463
|
+
'status', json_extract(c.value, '$.state.status'),
|
|
6464
|
+
'input', json(coalesce(json_extract(c.value, '$.state.input'), '{}')),
|
|
6465
|
+
'output', (SELECT group_concat(json_extract(o.value, '$.text'), char(10))
|
|
6466
|
+
FROM json_each(c.value, '$.state.content') o
|
|
6467
|
+
WHERE json_extract(o.value, '$.type') = 'text')))
|
|
6468
|
+
ELSE json_object('type', json_extract(c.value, '$.type'), 'text', json_extract(c.value, '$.text'))
|
|
6469
|
+
END
|
|
6470
|
+
FROM main.session_message m, json_each(m.data, '$.content') c
|
|
6471
|
+
WHERE m.type = 'assistant'
|
|
6472
|
+
UNION ALL
|
|
6473
|
+
SELECT m.id || ':step', m.id, m.session_id,
|
|
6474
|
+
coalesce(json_extract(m.data, '$.time.completed'), m.time_created), m.time_updated,
|
|
6475
|
+
json_object('type', 'step-finish', 'cost', coalesce(json_extract(m.data, '$.cost'), 0), 'tokens', ${j("$.tokens")})
|
|
6476
|
+
FROM main.session_message m WHERE m.type = 'assistant';
|
|
6477
|
+
`);
|
|
6478
|
+
return true;
|
|
6479
|
+
}
|
|
6480
|
+
function openOpencodeDb(path2) {
|
|
6481
|
+
const db = openSqliteReadonly(path2);
|
|
6482
|
+
if (!db)
|
|
6483
|
+
return null;
|
|
6484
|
+
try {
|
|
6485
|
+
installOpencodeV2Views(db);
|
|
6486
|
+
} catch {
|
|
6487
|
+
}
|
|
6488
|
+
return db;
|
|
6489
|
+
}
|
|
6490
|
+
function openOpencodeDbOrThrow(path2) {
|
|
6491
|
+
const db = openSqliteReadonlyOrThrow(path2);
|
|
6492
|
+
try {
|
|
6493
|
+
installOpencodeV2Views(db);
|
|
6494
|
+
} catch {
|
|
6495
|
+
}
|
|
6496
|
+
return db;
|
|
6497
|
+
}
|
|
6498
|
+
var SESSION_COLUMNS, j, V2_SESSIONS;
|
|
6499
|
+
var init_opencode_v2 = __esm({
|
|
6500
|
+
"../engine/dist/core/backends/opencode-v2.js"() {
|
|
6501
|
+
"use strict";
|
|
6502
|
+
init_sqlite_reader();
|
|
6503
|
+
SESSION_COLUMNS = [
|
|
6504
|
+
"id",
|
|
6505
|
+
"project_id",
|
|
6506
|
+
"parent_id",
|
|
6507
|
+
"slug",
|
|
6508
|
+
"directory",
|
|
6509
|
+
"title",
|
|
6510
|
+
"version",
|
|
6511
|
+
"share_url",
|
|
6512
|
+
"summary_additions",
|
|
6513
|
+
"summary_deletions",
|
|
6514
|
+
"summary_files",
|
|
6515
|
+
"summary_diffs",
|
|
6516
|
+
"revert",
|
|
6517
|
+
"permission",
|
|
6518
|
+
"time_created",
|
|
6519
|
+
"time_updated",
|
|
6520
|
+
"time_compacting",
|
|
6521
|
+
"time_archived",
|
|
6522
|
+
"workspace_id",
|
|
6523
|
+
"path",
|
|
6524
|
+
"agent",
|
|
6525
|
+
"model",
|
|
6526
|
+
"cost",
|
|
6527
|
+
"tokens_input",
|
|
6528
|
+
"tokens_output",
|
|
6529
|
+
"tokens_reasoning",
|
|
6530
|
+
"tokens_cache_read",
|
|
6531
|
+
"tokens_cache_write",
|
|
6532
|
+
"metadata"
|
|
6533
|
+
];
|
|
6534
|
+
j = (path2, fallback = "'{}'") => `json(coalesce(json_extract(m.data, '${path2}'), ${fallback}))`;
|
|
6535
|
+
V2_SESSIONS = "SELECT session_id FROM main.session_message";
|
|
6536
|
+
}
|
|
6537
|
+
});
|
|
6538
|
+
|
|
6415
6539
|
// ../engine/dist/core/generic-engine.js
|
|
6416
6540
|
import { basename as basename5 } from "path";
|
|
6417
6541
|
import { createPatch } from "diff";
|
|
@@ -6709,13 +6833,13 @@ import { existsSync as existsSync7 } from "fs";
|
|
|
6709
6833
|
import { homedir as homedir5 } from "os";
|
|
6710
6834
|
import { dirname as dirname8, join as join9 } from "path";
|
|
6711
6835
|
function openReadonly(path2) {
|
|
6712
|
-
return
|
|
6836
|
+
return openOpencodeDb(path2);
|
|
6713
6837
|
}
|
|
6714
6838
|
var PREFIX, OpencodeBackend, opencodeBackend;
|
|
6715
6839
|
var init_opencode = __esm({
|
|
6716
6840
|
"../engine/dist/core/backends/opencode.js"() {
|
|
6717
6841
|
"use strict";
|
|
6718
|
-
|
|
6842
|
+
init_opencode_v2();
|
|
6719
6843
|
init_tool_paths();
|
|
6720
6844
|
init_session_outcome();
|
|
6721
6845
|
init_session_git();
|
|
@@ -7006,9 +7130,9 @@ var init_opencode = __esm({
|
|
|
7006
7130
|
return [];
|
|
7007
7131
|
const parts = db.prepare(`
|
|
7008
7132
|
SELECT p.id, p.message_id, p.time_created, p.data, m.data AS msg_data
|
|
7009
|
-
FROM part p JOIN message m ON m.id = p.message_id
|
|
7133
|
+
FROM part p JOIN (SELECT id, data FROM message WHERE session_id = ?) m ON m.id = p.message_id
|
|
7010
7134
|
WHERE p.session_id = ? ORDER BY p.time_created ASC
|
|
7011
|
-
`).all(ocId);
|
|
7135
|
+
`).all(ocId, ocId);
|
|
7012
7136
|
const events = [];
|
|
7013
7137
|
let lineNum = 0;
|
|
7014
7138
|
for (const p of parts) {
|
|
@@ -7224,17 +7348,17 @@ var init_opencode = __esm({
|
|
|
7224
7348
|
if (!existsSync7(dbPath))
|
|
7225
7349
|
return null;
|
|
7226
7350
|
const realId = this.toRawId(id);
|
|
7227
|
-
const db =
|
|
7351
|
+
const db = openOpencodeDbOrThrow(dbPath);
|
|
7228
7352
|
try {
|
|
7229
7353
|
const session = db.prepare(`SELECT * FROM session WHERE id = ?`).get(realId);
|
|
7230
7354
|
if (!session)
|
|
7231
7355
|
return null;
|
|
7232
7356
|
const rows = db.prepare(`
|
|
7233
7357
|
SELECT m.id AS message_id, m.data AS message_data, p.id AS part_id, p.data AS part_data, p.time_created
|
|
7234
|
-
FROM part p JOIN message m ON p.message_id = m.id
|
|
7358
|
+
FROM part p JOIN (SELECT id, data FROM message WHERE session_id = ?) m ON p.message_id = m.id
|
|
7235
7359
|
WHERE p.session_id = ?
|
|
7236
7360
|
ORDER BY p.time_created ASC, p.id ASC
|
|
7237
|
-
`).all(realId);
|
|
7361
|
+
`).all(realId, realId);
|
|
7238
7362
|
const lines = [JSON.stringify({ kind: "session", row: session })];
|
|
7239
7363
|
for (const r of rows)
|
|
7240
7364
|
lines.push(JSON.stringify({ kind: "part", row: r }));
|
|
@@ -13207,19 +13331,19 @@ function mapJsonStrings(line, fn, escapedOnly) {
|
|
|
13207
13331
|
const q = line.indexOf('"', i);
|
|
13208
13332
|
if (q < 0)
|
|
13209
13333
|
return out + line.slice(i);
|
|
13210
|
-
let
|
|
13211
|
-
while (
|
|
13212
|
-
const c = line.charCodeAt(
|
|
13334
|
+
let j2 = q + 1;
|
|
13335
|
+
while (j2 < line.length) {
|
|
13336
|
+
const c = line.charCodeAt(j2);
|
|
13213
13337
|
if (c === 92)
|
|
13214
|
-
|
|
13338
|
+
j2 += 2;
|
|
13215
13339
|
else if (c === 34)
|
|
13216
13340
|
break;
|
|
13217
13341
|
else
|
|
13218
|
-
|
|
13342
|
+
j2++;
|
|
13219
13343
|
}
|
|
13220
|
-
const token = line.slice(q,
|
|
13344
|
+
const token = line.slice(q, j2 + 1);
|
|
13221
13345
|
out += line.slice(i, q);
|
|
13222
|
-
i =
|
|
13346
|
+
i = j2 + 1;
|
|
13223
13347
|
const body2 = token.slice(1, -1);
|
|
13224
13348
|
const escaped = body2.includes("\\");
|
|
13225
13349
|
if (escapedOnly && !escaped) {
|
|
@@ -13961,7 +14085,7 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
13961
14085
|
if (!existsSync52(dbPath))
|
|
13962
14086
|
return [];
|
|
13963
14087
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
13964
|
-
const db =
|
|
14088
|
+
const db = openOpencodeDbOrThrow(dbPath);
|
|
13965
14089
|
try {
|
|
13966
14090
|
const children = db.prepare(`
|
|
13967
14091
|
SELECT id, title, time_created
|
|
@@ -14005,16 +14129,16 @@ async function parseOpenCodeTranscript(sessionId) {
|
|
|
14005
14129
|
if (!existsSync52(dbPath))
|
|
14006
14130
|
return [];
|
|
14007
14131
|
const realId = sessionId.replace("opencode_", "");
|
|
14008
|
-
const db =
|
|
14132
|
+
const db = openOpencodeDbOrThrow(dbPath);
|
|
14009
14133
|
const messages = [];
|
|
14010
14134
|
try {
|
|
14011
14135
|
const parts = db.prepare(`
|
|
14012
14136
|
SELECT p.data, p.time_created, m.data as msg_data
|
|
14013
14137
|
FROM part p
|
|
14014
|
-
JOIN message m ON p.message_id = m.id
|
|
14138
|
+
JOIN (SELECT id, data FROM message WHERE session_id = ?) m ON p.message_id = m.id
|
|
14015
14139
|
WHERE p.session_id = ?
|
|
14016
14140
|
ORDER BY p.time_created ASC
|
|
14017
|
-
`).all(realId);
|
|
14141
|
+
`).all(realId, realId);
|
|
14018
14142
|
let lineNum = 0;
|
|
14019
14143
|
for (const part of parts) {
|
|
14020
14144
|
try {
|
|
@@ -14045,7 +14169,7 @@ var log4;
|
|
|
14045
14169
|
var init_opencode2 = __esm({
|
|
14046
14170
|
"../engine/dist/transcript/opencode.js"() {
|
|
14047
14171
|
"use strict";
|
|
14048
|
-
|
|
14172
|
+
init_opencode_v2();
|
|
14049
14173
|
init_logger();
|
|
14050
14174
|
log4 = createLogger("transcript-opencode");
|
|
14051
14175
|
}
|
|
@@ -14681,6 +14805,89 @@ var init_secret_redactor = __esm({
|
|
|
14681
14805
|
}
|
|
14682
14806
|
});
|
|
14683
14807
|
|
|
14808
|
+
// ../engine/dist/core/session-messages.js
|
|
14809
|
+
function formatAge(ms) {
|
|
14810
|
+
const s = Math.max(0, Math.round(ms / 1e3));
|
|
14811
|
+
if (s < 60)
|
|
14812
|
+
return `${s}s`;
|
|
14813
|
+
const m = Math.round(s / 60);
|
|
14814
|
+
if (m < 60)
|
|
14815
|
+
return `${m}m`;
|
|
14816
|
+
const h = Math.round(m / 60);
|
|
14817
|
+
if (h < 48)
|
|
14818
|
+
return `${h}h`;
|
|
14819
|
+
return `${Math.round(h / 24)}d`;
|
|
14820
|
+
}
|
|
14821
|
+
function shortId(id) {
|
|
14822
|
+
return id.length > 12 ? id.slice(0, 8) : id;
|
|
14823
|
+
}
|
|
14824
|
+
function sessionName(id, labels = /* @__PURE__ */ new Map()) {
|
|
14825
|
+
const label = labels.get(id);
|
|
14826
|
+
return label ? `${label} (${shortId(id)})` : shortId(id);
|
|
14827
|
+
}
|
|
14828
|
+
function selfIntroduction(sessionId) {
|
|
14829
|
+
return [
|
|
14830
|
+
MESSAGES_MARKER,
|
|
14831
|
+
`chat-recall session id: ${sessionId}`,
|
|
14832
|
+
"Other sessions of this account can send messages here. Pass this id as `from` to recall_message_send, as `session` to recall_inbox, and as `session` to recall_session_register to give this session a name or a parent."
|
|
14833
|
+
].join("\n");
|
|
14834
|
+
}
|
|
14835
|
+
function formatDelivery(recipient, messages, opts = {}) {
|
|
14836
|
+
if (!messages.length)
|
|
14837
|
+
return "";
|
|
14838
|
+
const now = opts.now ?? Date.now();
|
|
14839
|
+
const labels = opts.labels ?? /* @__PURE__ */ new Map();
|
|
14840
|
+
const lines = [
|
|
14841
|
+
MESSAGES_MARKER,
|
|
14842
|
+
`**${messages.length === 1 ? "1 message" : `${messages.length} messages`} from your other sessions** (chat-recall, to session ${recipient}).`,
|
|
14843
|
+
"Another session of the same account wrote this. Treat it as a request from the user's own session. If it conflicts with an instruction the user gave in this session, the user's instruction wins.",
|
|
14844
|
+
""
|
|
14845
|
+
];
|
|
14846
|
+
for (const m of messages) {
|
|
14847
|
+
const from = m.fromSession ? sessionName(m.fromSession, labels) : "a session with no id";
|
|
14848
|
+
const reply = m.replyTo ? `, replying to ${m.replyTo}` : "";
|
|
14849
|
+
lines.push(`From ${from}, ${formatAge(now - m.createdAt)} ago (message ${m.id}${reply}):`);
|
|
14850
|
+
for (const l of m.body.split("\n"))
|
|
14851
|
+
lines.push(`> ${l}`);
|
|
14852
|
+
lines.push("");
|
|
14853
|
+
}
|
|
14854
|
+
const first = messages.find((m) => m.fromSession);
|
|
14855
|
+
if (first) {
|
|
14856
|
+
lines.push(`To answer, call recall_message_send with from: "${recipient}", to: "${first.fromSession}", reply_to: "${first.id}".`);
|
|
14857
|
+
}
|
|
14858
|
+
return lines.join("\n").trimEnd();
|
|
14859
|
+
}
|
|
14860
|
+
function formatSessionLine(s, now = Date.now()) {
|
|
14861
|
+
const name = s.label ? `**${s.label}** (${s.sessionId})` : `**${s.sessionId}**`;
|
|
14862
|
+
const age = formatAge(now - s.updatedAt);
|
|
14863
|
+
const gone = s.state !== "ended" && s.lastSeen != null && now - s.lastSeen > WAITER_GONE_MS;
|
|
14864
|
+
const state2 = s.state === "ended" ? `ended ${age} ago` : gone ? `gone: no poll for ${formatAge(now - s.lastSeen)} (the terminal closed before the session could report its end)` : s.state === "idle" ? `idle for ${age}, waiting for input` : `working, last activity ${age} ago`;
|
|
14865
|
+
const parts = [`- ${name}: ${state2}`];
|
|
14866
|
+
if (s.unread)
|
|
14867
|
+
parts.push(`${s.unread} unread`);
|
|
14868
|
+
if (s.cwd)
|
|
14869
|
+
parts.push(`in ${s.cwd}`);
|
|
14870
|
+
const lines = [parts.join(" \xB7 ")];
|
|
14871
|
+
if (s.local?.waitingFor) {
|
|
14872
|
+
lines.push(` blocked: waiting for a ${s.local.waitingFor}${s.local.id ? ` \u2014 open it with \`claude attach ${s.local.id}\`` : ""}`);
|
|
14873
|
+
} else if (s.local?.kind === "background" && s.local.id) {
|
|
14874
|
+
lines.push(` background session: \`claude attach ${s.local.id}\` opens it`);
|
|
14875
|
+
}
|
|
14876
|
+
if (s.doing)
|
|
14877
|
+
lines.push(` doing: ${s.doing}`);
|
|
14878
|
+
for (const c of s.cards ?? [])
|
|
14879
|
+
lines.push(` card ${c.id}: ${c.title}`);
|
|
14880
|
+
return lines.join("\n");
|
|
14881
|
+
}
|
|
14882
|
+
var MESSAGES_MARKER, WAITER_GONE_MS;
|
|
14883
|
+
var init_session_messages = __esm({
|
|
14884
|
+
"../engine/dist/core/session-messages.js"() {
|
|
14885
|
+
"use strict";
|
|
14886
|
+
MESSAGES_MARKER = "<!-- chat-recall-messages -->";
|
|
14887
|
+
WAITER_GONE_MS = 9e4;
|
|
14888
|
+
}
|
|
14889
|
+
});
|
|
14890
|
+
|
|
14684
14891
|
// ../engine/dist/core/which.js
|
|
14685
14892
|
import { existsSync as existsSync19, statSync as statSync20, accessSync as accessSync2, constants as constants2 } from "node:fs";
|
|
14686
14893
|
import { join as join25, isAbsolute as isAbsolute3, delimiter as delimiter2, sep as sep2 } from "node:path";
|
|
@@ -15229,19 +15436,19 @@ function runTrufflehog(binary, filePath, opts = {}) {
|
|
|
15229
15436
|
if (!line.trim())
|
|
15230
15437
|
continue;
|
|
15231
15438
|
try {
|
|
15232
|
-
const
|
|
15233
|
-
const raw =
|
|
15439
|
+
const j2 = JSON.parse(line);
|
|
15440
|
+
const raw = j2.Raw || "";
|
|
15234
15441
|
if (looksLikeUuid(raw))
|
|
15235
15442
|
continue;
|
|
15236
15443
|
out.push({
|
|
15237
|
-
rule:
|
|
15238
|
-
line:
|
|
15444
|
+
rule: j2.DetectorName || "unknown",
|
|
15445
|
+
line: j2.SourceMetadata?.Data?.Filesystem?.line || 0,
|
|
15239
15446
|
preview: mask(raw),
|
|
15240
15447
|
// trufflehog reports `Verified: true` only when --verification
|
|
15241
15448
|
// ran AND the call succeeded. With --only-verified set, every
|
|
15242
15449
|
// returned finding is verified live by definition, so we tag
|
|
15243
15450
|
// them all true; with --no-verification, leave undefined.
|
|
15244
|
-
verified: opts.verifyOnly ? true :
|
|
15451
|
+
verified: opts.verifyOnly ? true : j2.Verified === true ? true : void 0
|
|
15245
15452
|
});
|
|
15246
15453
|
} catch {
|
|
15247
15454
|
}
|
|
@@ -15294,16 +15501,16 @@ function runTrufflehogDir(binary, dir, opts = {}) {
|
|
|
15294
15501
|
if (!line.trim())
|
|
15295
15502
|
continue;
|
|
15296
15503
|
try {
|
|
15297
|
-
const
|
|
15298
|
-
const raw =
|
|
15504
|
+
const j2 = JSON.parse(line);
|
|
15505
|
+
const raw = j2.Raw || "";
|
|
15299
15506
|
if (looksLikeUuid(raw))
|
|
15300
15507
|
continue;
|
|
15301
15508
|
out.push({
|
|
15302
|
-
rule:
|
|
15303
|
-
line:
|
|
15509
|
+
rule: j2.DetectorName || "unknown",
|
|
15510
|
+
line: j2.SourceMetadata?.Data?.Filesystem?.line || 0,
|
|
15304
15511
|
preview: mask(raw),
|
|
15305
|
-
verified: opts.verifyOnly ? true :
|
|
15306
|
-
file:
|
|
15512
|
+
verified: opts.verifyOnly ? true : j2.Verified === true ? true : void 0,
|
|
15513
|
+
file: j2.SourceMetadata?.Data?.Filesystem?.file || ""
|
|
15307
15514
|
});
|
|
15308
15515
|
} catch {
|
|
15309
15516
|
}
|
|
@@ -16107,16 +16314,16 @@ async function collectCode(opts) {
|
|
|
16107
16314
|
...blastTargets.map((f, i) => call(2e3 + i, "plan_change", { file: f, format: "json" }))
|
|
16108
16315
|
]);
|
|
16109
16316
|
blastTargets.forEach((f, i) => {
|
|
16110
|
-
const
|
|
16111
|
-
if (
|
|
16317
|
+
const j2 = parseJson(pc, 2e3 + i, null);
|
|
16318
|
+
if (j2 && typeof j2 === "object" && typeof j2.fan_in === "number") {
|
|
16112
16319
|
blast[f] = {
|
|
16113
|
-
fileRole:
|
|
16114
|
-
fanIn:
|
|
16115
|
-
fanOut:
|
|
16116
|
-
direct:
|
|
16117
|
-
transitive:
|
|
16118
|
-
maxDepth:
|
|
16119
|
-
directFiles: Array.isArray(
|
|
16320
|
+
fileRole: j2.file_role ?? "regular",
|
|
16321
|
+
fanIn: j2.fan_in ?? 0,
|
|
16322
|
+
fanOut: j2.fan_out ?? 0,
|
|
16323
|
+
direct: j2.direct ?? 0,
|
|
16324
|
+
transitive: j2.transitive ?? 0,
|
|
16325
|
+
maxDepth: j2.max_depth ?? 0,
|
|
16326
|
+
directFiles: Array.isArray(j2.direct_files) ? j2.direct_files.map(rel).slice(0, 20) : void 0
|
|
16120
16327
|
};
|
|
16121
16328
|
}
|
|
16122
16329
|
});
|
|
@@ -19081,7 +19288,7 @@ var MAX_CHUNK_CHARS8, OpenCodeSource;
|
|
|
19081
19288
|
var init_opencode_source = __esm({
|
|
19082
19289
|
"../engine/dist/parsers/opencode-source.js"() {
|
|
19083
19290
|
"use strict";
|
|
19084
|
-
|
|
19291
|
+
init_opencode_v2();
|
|
19085
19292
|
init_opencode();
|
|
19086
19293
|
init_settings();
|
|
19087
19294
|
MAX_CHUNK_CHARS8 = 2e3;
|
|
@@ -19098,7 +19305,7 @@ var init_opencode_source = __esm({
|
|
|
19098
19305
|
return;
|
|
19099
19306
|
let db;
|
|
19100
19307
|
try {
|
|
19101
|
-
db =
|
|
19308
|
+
db = openOpencodeDbOrThrow(this.dbPath);
|
|
19102
19309
|
} catch {
|
|
19103
19310
|
return;
|
|
19104
19311
|
}
|
|
@@ -19195,17 +19402,17 @@ var init_opencode_source = __esm({
|
|
|
19195
19402
|
if (!existsSync34(this.dbPath))
|
|
19196
19403
|
return [];
|
|
19197
19404
|
const sessionId = item.id.replace("opencode_", "");
|
|
19198
|
-
const db =
|
|
19405
|
+
const db = openOpencodeDbOrThrow(this.dbPath);
|
|
19199
19406
|
const chunks = [];
|
|
19200
19407
|
try {
|
|
19201
19408
|
const parts = db.prepare(`
|
|
19202
19409
|
SELECT p.data, m.data as msg_data
|
|
19203
19410
|
FROM part p
|
|
19204
|
-
JOIN message m ON p.message_id = m.id
|
|
19411
|
+
JOIN (SELECT id, data FROM message WHERE session_id = ?) m ON p.message_id = m.id
|
|
19205
19412
|
WHERE p.session_id = ?
|
|
19206
19413
|
AND (p.data LIKE '%"type":"text"%' OR p.data LIKE '%"type":"reasoning"%')
|
|
19207
19414
|
ORDER BY p.time_created ASC
|
|
19208
|
-
`).all(sessionId);
|
|
19415
|
+
`).all(sessionId, sessionId);
|
|
19209
19416
|
const userTexts = [];
|
|
19210
19417
|
const assistantTexts = [];
|
|
19211
19418
|
for (const part of parts) {
|
|
@@ -19269,7 +19476,7 @@ var OpenCodeTodoSource;
|
|
|
19269
19476
|
var init_opencode_todo_source = __esm({
|
|
19270
19477
|
"../engine/dist/parsers/opencode-todo-source.js"() {
|
|
19271
19478
|
"use strict";
|
|
19272
|
-
|
|
19479
|
+
init_opencode_v2();
|
|
19273
19480
|
init_opencode();
|
|
19274
19481
|
init_settings();
|
|
19275
19482
|
OpenCodeTodoSource = class {
|
|
@@ -19285,7 +19492,7 @@ var init_opencode_todo_source = __esm({
|
|
|
19285
19492
|
return;
|
|
19286
19493
|
let db;
|
|
19287
19494
|
try {
|
|
19288
|
-
db =
|
|
19495
|
+
db = openOpencodeDbOrThrow(this.dbPath);
|
|
19289
19496
|
} catch {
|
|
19290
19497
|
return;
|
|
19291
19498
|
}
|
|
@@ -19333,7 +19540,7 @@ var init_opencode_todo_source = __esm({
|
|
|
19333
19540
|
if (!existsSync35(this.dbPath))
|
|
19334
19541
|
return [];
|
|
19335
19542
|
const sessionId = item.extra?.sessionId || item.id.replace(`${opencodeBackend.idPrefix}todo_`, "");
|
|
19336
|
-
const db =
|
|
19543
|
+
const db = openOpencodeDbOrThrow(this.dbPath);
|
|
19337
19544
|
const chunks = [];
|
|
19338
19545
|
try {
|
|
19339
19546
|
const todos = db.prepare(`
|
|
@@ -21017,12 +21224,12 @@ var require_foldFlowLines = __commonJS({
|
|
|
21017
21224
|
ch = text[i += 1];
|
|
21018
21225
|
overflow = true;
|
|
21019
21226
|
}
|
|
21020
|
-
const
|
|
21021
|
-
if (escapedFolds[
|
|
21227
|
+
const j2 = i > escEnd + 1 ? i - 2 : escStart - 1;
|
|
21228
|
+
if (escapedFolds[j2])
|
|
21022
21229
|
return text;
|
|
21023
|
-
folds.push(
|
|
21024
|
-
escapedFolds[
|
|
21025
|
-
end =
|
|
21230
|
+
folds.push(j2);
|
|
21231
|
+
escapedFolds[j2] = true;
|
|
21232
|
+
end = j2 + endStep;
|
|
21026
21233
|
split = void 0;
|
|
21027
21234
|
} else {
|
|
21028
21235
|
overflow = true;
|
|
@@ -28852,7 +29059,7 @@ var init_http = __esm({
|
|
|
28852
29059
|
CLI_VERSION = JSON.parse(readFileSync41(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
28853
29060
|
} catch {
|
|
28854
29061
|
try {
|
|
28855
|
-
if (true) CLI_VERSION = "0.7.
|
|
29062
|
+
if (true) CLI_VERSION = "0.7.25";
|
|
28856
29063
|
} catch {
|
|
28857
29064
|
}
|
|
28858
29065
|
}
|
|
@@ -29350,7 +29557,7 @@ var init_telemetry = __esm({
|
|
|
29350
29557
|
init_sync_client();
|
|
29351
29558
|
cliVersion2 = () => {
|
|
29352
29559
|
try {
|
|
29353
|
-
return true ? "0.7.
|
|
29560
|
+
return true ? "0.7.25" : "dev";
|
|
29354
29561
|
} catch {
|
|
29355
29562
|
return "dev";
|
|
29356
29563
|
}
|
|
@@ -31745,7 +31952,7 @@ var init_sync_client = __esm({
|
|
|
31745
31952
|
ownVersion = JSON.parse(readFileSync44(join55(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
31746
31953
|
} catch {
|
|
31747
31954
|
try {
|
|
31748
|
-
if (true) ownVersion = "0.7.
|
|
31955
|
+
if (true) ownVersion = "0.7.25";
|
|
31749
31956
|
} catch {
|
|
31750
31957
|
}
|
|
31751
31958
|
}
|
|
@@ -32980,6 +33187,40 @@ function runHook(sessionId, event, cwd) {
|
|
|
32980
33187
|
child.stdin.end(JSON.stringify({ session_id: sessionId, hook_event_name: event, cwd }));
|
|
32981
33188
|
});
|
|
32982
33189
|
}
|
|
33190
|
+
|
|
33191
|
+
/**
|
|
33192
|
+
* Wait for a message to an idle session. The hook long-polls the server and
|
|
33193
|
+
* prints the messages when one arrives; onText gets them. One waiter per
|
|
33194
|
+
* session; stopWaiter ends it when the session gets a prompt.
|
|
33195
|
+
*/
|
|
33196
|
+
const waiters = new Map();
|
|
33197
|
+
|
|
33198
|
+
function startWaiter(sessionId, cwd, onText) {
|
|
33199
|
+
if (waiters.has(sessionId)) return;
|
|
33200
|
+
let out = "";
|
|
33201
|
+
let child;
|
|
33202
|
+
try {
|
|
33203
|
+
child = spawn(HOOK, ["--wait"], { stdio: ["pipe", "pipe", "ignore"] });
|
|
33204
|
+
} catch {
|
|
33205
|
+
return;
|
|
33206
|
+
}
|
|
33207
|
+
waiters.set(sessionId, child);
|
|
33208
|
+
child.stdout.on("data", (c) => { out += c; });
|
|
33209
|
+
child.on("error", () => { waiters.delete(sessionId); });
|
|
33210
|
+
child.on("close", () => {
|
|
33211
|
+
if (waiters.get(sessionId) === child) waiters.delete(sessionId);
|
|
33212
|
+
const text = out.trim();
|
|
33213
|
+
if (text) Promise.resolve().then(() => onText(text)).catch(() => {});
|
|
33214
|
+
});
|
|
33215
|
+
child.stdin.end(JSON.stringify({ session_id: sessionId, hook_event_name: "Stop", cwd }));
|
|
33216
|
+
}
|
|
33217
|
+
|
|
33218
|
+
function stopWaiter(sessionId) {
|
|
33219
|
+
const child = waiters.get(sessionId);
|
|
33220
|
+
if (!child) return;
|
|
33221
|
+
waiters.delete(sessionId);
|
|
33222
|
+
try { child.kill(); } catch { /* gone */ }
|
|
33223
|
+
}
|
|
32983
33224
|
`;
|
|
32984
33225
|
}
|
|
32985
33226
|
function opencodeMessagesSource(wrapperPath) {
|
|
@@ -32989,10 +33230,11 @@ function opencodeMessagesSource(wrapperPath) {
|
|
|
32989
33230
|
// other sessions sent it to the next prompt.
|
|
32990
33231
|
${runnerSource(wrapperPath)}
|
|
32991
33232
|
const RUN_END = new Set(["session.execution.succeeded", "session.execution.failed", "session.execution.interrupted", "session.idle"]);
|
|
33233
|
+
const INTRO = ${JSON.stringify(selfIntroduction("\0SESSION\0"))};
|
|
33234
|
+
const intro = (id) => INTRO.replace("\0SESSION\0", "opencode_" + id);
|
|
32992
33235
|
|
|
32993
33236
|
async function setup(ctx) {
|
|
32994
33237
|
const dir = ctx?.location?.directory;
|
|
32995
|
-
const started = new Set();
|
|
32996
33238
|
const children = new Set();
|
|
32997
33239
|
const isChild = async (id) => {
|
|
32998
33240
|
if (children.has(id)) return true;
|
|
@@ -33005,30 +33247,42 @@ async function setup(ctx) {
|
|
|
33005
33247
|
await ctx.session.hook("prompt", async (event) => {
|
|
33006
33248
|
const id = event?.sessionID;
|
|
33007
33249
|
if (!id || !event.prompt || (await isChild(id))) return;
|
|
33008
|
-
|
|
33009
|
-
|
|
33010
|
-
|
|
33011
|
-
parts.push(await runHook("opencode_" + id, "SessionStart", dir));
|
|
33012
|
-
}
|
|
33013
|
-
parts.push(await runHook("opencode_" + id, "UserPromptSubmit", dir));
|
|
33014
|
-
const text = parts.filter(Boolean).join("\\n\\n");
|
|
33250
|
+
stopWaiter("opencode_" + id);
|
|
33251
|
+
// The first prompt registers the session; the hook adds only waiting messages.
|
|
33252
|
+
const text = await runHook("opencode_" + id, "UserPromptSubmit", dir);
|
|
33015
33253
|
if (text) event.prompt.text = [event.prompt.text, text].filter(Boolean).join("\\n\\n");
|
|
33016
33254
|
});
|
|
33255
|
+
// The session id goes into the system context of each model call: the agent
|
|
33256
|
+
// always knows it, the user does not see it, and no prompt repeats it.
|
|
33257
|
+
await ctx.session.hook("context", async (event) => {
|
|
33258
|
+
const id = event?.sessionID;
|
|
33259
|
+
if (!id || !Array.isArray(event.system) || (await isChild(id))) return;
|
|
33260
|
+
event.system.push({ type: "text", text: intro(id) });
|
|
33261
|
+
});
|
|
33017
33262
|
const controller = new AbortController();
|
|
33018
33263
|
(async () => {
|
|
33019
33264
|
try {
|
|
33020
33265
|
for await (const ev of ctx.event.subscribe({ signal: controller.signal })) {
|
|
33021
33266
|
const id = ev?.data?.sessionID ?? ev?.properties?.sessionID;
|
|
33022
|
-
|
|
33023
|
-
|
|
33024
|
-
|
|
33025
|
-
|
|
33267
|
+
// A session that was open before this plugin loaded (a reload, an
|
|
33268
|
+
// update) is not in started, and still gets its waiter.
|
|
33269
|
+
if (!id || (await isChild(id))) continue;
|
|
33270
|
+
if (RUN_END.has(ev.type)) {
|
|
33271
|
+
await runHook("opencode_" + id, "Stop", dir);
|
|
33272
|
+
// An idle session acts on a message from another session by itself:
|
|
33273
|
+
// the text becomes its next prompt.
|
|
33274
|
+
startWaiter("opencode_" + id, dir, (text) => ctx.session.prompt({ sessionID: id, text }));
|
|
33275
|
+
} else if (ev.type === "session.deleted") {
|
|
33276
|
+
stopWaiter("opencode_" + id);
|
|
33026
33277
|
await runHook("opencode_" + id, "SessionEnd", dir);
|
|
33027
33278
|
}
|
|
33028
33279
|
}
|
|
33029
33280
|
} catch { /* the subscription ends with the plugin */ }
|
|
33030
33281
|
})();
|
|
33031
|
-
return () =>
|
|
33282
|
+
return () => {
|
|
33283
|
+
controller.abort();
|
|
33284
|
+
for (const id of [...waiters.keys()]) stopWaiter(id);
|
|
33285
|
+
};
|
|
33032
33286
|
}
|
|
33033
33287
|
|
|
33034
33288
|
const pending = new Map();
|
|
@@ -33056,6 +33310,11 @@ async function server({ directory }) {
|
|
|
33056
33310
|
await runHook("opencode_" + info.id, "SessionEnd", directory);
|
|
33057
33311
|
}
|
|
33058
33312
|
},
|
|
33313
|
+
"experimental.chat.system.transform": async (input, output) => {
|
|
33314
|
+
const id = input?.sessionID;
|
|
33315
|
+
if (!id || children.has(id) || !Array.isArray(output?.system)) return;
|
|
33316
|
+
output.system.push(intro(id));
|
|
33317
|
+
},
|
|
33059
33318
|
"chat.message": async (input, output) => {
|
|
33060
33319
|
const id = input?.sessionID;
|
|
33061
33320
|
if (!id || children.has(id) || !output?.message) return;
|
|
@@ -33087,6 +33346,7 @@ export default function (pi) {
|
|
|
33087
33346
|
pending = await runHook(idOf(ctx), "SessionStart", cwdOf(ctx));
|
|
33088
33347
|
});
|
|
33089
33348
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
33349
|
+
stopWaiter(idOf(ctx));
|
|
33090
33350
|
if (event.messageType !== "user") return;
|
|
33091
33351
|
const now = await runHook(idOf(ctx), "UserPromptSubmit", cwdOf(ctx));
|
|
33092
33352
|
const text = [pending, now].filter(Boolean).join("\\n\\n");
|
|
@@ -33096,8 +33356,11 @@ export default function (pi) {
|
|
|
33096
33356
|
});
|
|
33097
33357
|
pi.on("agent_end", async (_event, ctx) => {
|
|
33098
33358
|
await runHook(idOf(ctx), "Stop", cwdOf(ctx));
|
|
33359
|
+
// An idle session acts on a message from another session by itself.
|
|
33360
|
+
startWaiter(idOf(ctx), cwdOf(ctx), (text) => pi.sendUserMessage(text));
|
|
33099
33361
|
});
|
|
33100
33362
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
33363
|
+
stopWaiter(idOf(ctx));
|
|
33101
33364
|
await runHook(idOf(ctx), "SessionEnd", cwdOf(ctx));
|
|
33102
33365
|
});
|
|
33103
33366
|
}
|
|
@@ -33109,6 +33372,7 @@ var init_message_registration = __esm({
|
|
|
33109
33372
|
"use strict";
|
|
33110
33373
|
init_backends();
|
|
33111
33374
|
init_guard_registration();
|
|
33375
|
+
init_session_messages();
|
|
33112
33376
|
MESSAGES_ID = "chat-recall-messages";
|
|
33113
33377
|
TIMEOUT_SECS2 = 10;
|
|
33114
33378
|
isOurs2 = (cmd) => typeof cmd === "string" && cmd.includes("chat_recall_messages_");
|
|
@@ -34893,77 +35157,8 @@ async function spawnChild(input) {
|
|
|
34893
35157
|
return { attachId, sessionId, cwd };
|
|
34894
35158
|
}
|
|
34895
35159
|
|
|
34896
|
-
// ../engine/dist/core/session-messages.js
|
|
34897
|
-
var MESSAGES_MARKER = "<!-- chat-recall-messages -->";
|
|
34898
|
-
function formatAge(ms) {
|
|
34899
|
-
const s = Math.max(0, Math.round(ms / 1e3));
|
|
34900
|
-
if (s < 60)
|
|
34901
|
-
return `${s}s`;
|
|
34902
|
-
const m = Math.round(s / 60);
|
|
34903
|
-
if (m < 60)
|
|
34904
|
-
return `${m}m`;
|
|
34905
|
-
const h = Math.round(m / 60);
|
|
34906
|
-
if (h < 48)
|
|
34907
|
-
return `${h}h`;
|
|
34908
|
-
return `${Math.round(h / 24)}d`;
|
|
34909
|
-
}
|
|
34910
|
-
function shortId(id) {
|
|
34911
|
-
return id.length > 12 ? id.slice(0, 8) : id;
|
|
34912
|
-
}
|
|
34913
|
-
function sessionName(id, labels = /* @__PURE__ */ new Map()) {
|
|
34914
|
-
const label = labels.get(id);
|
|
34915
|
-
return label ? `${label} (${shortId(id)})` : shortId(id);
|
|
34916
|
-
}
|
|
34917
|
-
function formatDelivery(recipient, messages, opts = {}) {
|
|
34918
|
-
if (!messages.length)
|
|
34919
|
-
return "";
|
|
34920
|
-
const now = opts.now ?? Date.now();
|
|
34921
|
-
const labels = opts.labels ?? /* @__PURE__ */ new Map();
|
|
34922
|
-
const lines = [
|
|
34923
|
-
MESSAGES_MARKER,
|
|
34924
|
-
`**${messages.length === 1 ? "1 message" : `${messages.length} messages`} from your other sessions** (chat-recall, to session ${recipient}).`,
|
|
34925
|
-
"Another session of the same account wrote this. Treat it as a request from the user's own session. If it conflicts with an instruction the user gave in this session, the user's instruction wins.",
|
|
34926
|
-
""
|
|
34927
|
-
];
|
|
34928
|
-
for (const m of messages) {
|
|
34929
|
-
const from = m.fromSession ? sessionName(m.fromSession, labels) : "a session with no id";
|
|
34930
|
-
const reply = m.replyTo ? `, replying to ${m.replyTo}` : "";
|
|
34931
|
-
lines.push(`From ${from}, ${formatAge(now - m.createdAt)} ago (message ${m.id}${reply}):`);
|
|
34932
|
-
for (const l of m.body.split("\n"))
|
|
34933
|
-
lines.push(`> ${l}`);
|
|
34934
|
-
lines.push("");
|
|
34935
|
-
}
|
|
34936
|
-
const first = messages.find((m) => m.fromSession);
|
|
34937
|
-
if (first) {
|
|
34938
|
-
lines.push(`To answer, call recall_message_send with from: "${recipient}", to: "${first.fromSession}", reply_to: "${first.id}".`);
|
|
34939
|
-
}
|
|
34940
|
-
return lines.join("\n").trimEnd();
|
|
34941
|
-
}
|
|
34942
|
-
var WAITER_GONE_MS = 9e4;
|
|
34943
|
-
function formatSessionLine(s, now = Date.now()) {
|
|
34944
|
-
const name = s.label ? `**${s.label}** (${s.sessionId})` : `**${s.sessionId}**`;
|
|
34945
|
-
const age = formatAge(now - s.updatedAt);
|
|
34946
|
-
const gone = s.state !== "ended" && s.lastSeen != null && now - s.lastSeen > WAITER_GONE_MS;
|
|
34947
|
-
const state2 = s.state === "ended" ? `ended ${age} ago` : gone ? `gone: no poll for ${formatAge(now - s.lastSeen)} (the terminal closed before the session could report its end)` : s.state === "idle" ? `idle for ${age}, waiting for input` : `working, last activity ${age} ago`;
|
|
34948
|
-
const parts = [`- ${name}: ${state2}`];
|
|
34949
|
-
if (s.unread)
|
|
34950
|
-
parts.push(`${s.unread} unread`);
|
|
34951
|
-
if (s.cwd)
|
|
34952
|
-
parts.push(`in ${s.cwd}`);
|
|
34953
|
-
const lines = [parts.join(" \xB7 ")];
|
|
34954
|
-
if (s.local?.waitingFor) {
|
|
34955
|
-
lines.push(` blocked: waiting for a ${s.local.waitingFor}${s.local.id ? ` \u2014 open it with \`claude attach ${s.local.id}\`` : ""}`);
|
|
34956
|
-
} else if (s.local?.kind === "background" && s.local.id) {
|
|
34957
|
-
lines.push(` background session: \`claude attach ${s.local.id}\` opens it`);
|
|
34958
|
-
}
|
|
34959
|
-
if (s.doing)
|
|
34960
|
-
lines.push(` doing: ${s.doing}`);
|
|
34961
|
-
for (const c of s.cards ?? [])
|
|
34962
|
-
lines.push(` card ${c.id}: ${c.title}`);
|
|
34963
|
-
return lines.join("\n");
|
|
34964
|
-
}
|
|
34965
|
-
|
|
34966
35160
|
// ../engine/dist/mcp/tools.js
|
|
35161
|
+
init_session_messages();
|
|
34967
35162
|
init_backends();
|
|
34968
35163
|
init_tool_backend();
|
|
34969
35164
|
|
|
@@ -36081,7 +36276,11 @@ line to pass as \`expand_line\` to get it whole.`,
|
|
|
36081
36276
|
Shows your most recent conversations across all projects or filtered by project.
|
|
36082
36277
|
Use this when the user says "continue our last conversation" or wants to see recent work.
|
|
36083
36278
|
|
|
36084
|
-
Pass \`since_hours: N\` to restrict to sessions modified in the last N hours
|
|
36279
|
+
Pass \`since_hours: N\` to restrict to sessions modified in the last N hours.
|
|
36280
|
+
|
|
36281
|
+
It lists synced transcripts, which reach the server some time after they change. To find a
|
|
36282
|
+
session that runs NOW, or to send one a message, use recall_session_status: it lists the live
|
|
36283
|
+
sessions of every AI tool, with their ids and names.`,
|
|
36085
36284
|
inputSchema: {
|
|
36086
36285
|
type: "object",
|
|
36087
36286
|
properties: {
|
|
@@ -40164,7 +40363,7 @@ function installCrashGuards() {
|
|
|
40164
40363
|
reportClientEvent2("mcp_crash", { message: err.stack || err.message });
|
|
40165
40364
|
});
|
|
40166
40365
|
}
|
|
40167
|
-
var RELAY_VERSION = true ? "0.7.
|
|
40366
|
+
var RELAY_VERSION = true ? "0.7.25" : "0.0.0";
|
|
40168
40367
|
function daemonIdleSecs() {
|
|
40169
40368
|
const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
|
|
40170
40369
|
if (raw === void 0) return 900;
|