chat-recall 0.5.3 → 0.5.5
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 +121 -40
- package/dist/cli.js.map +1 -1
- package/dist/mcp-diagnostics.d.ts +45 -0
- package/dist/mcp-diagnostics.d.ts.map +1 -0
- package/dist/mcp-diagnostics.js +96 -0
- package/dist/mcp-diagnostics.js.map +1 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +946 -677
- package/dist/mcp.js.map +1 -1
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +18 -0
- package/dist/sync-client.js.map +1 -1
- package/dist/watch.js +120 -41
- package/package.json +1 -1
- package/skills/chat-recall/SKILL.md +3 -2
package/dist/mcp.js
CHANGED
|
@@ -6149,6 +6149,24 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
6149
6149
|
}
|
|
6150
6150
|
const filesToParse = hasSubagentsDir(sessionPath) ? [sessionPath, ...getSubagentPaths(sessionPath)] : [sessionPath];
|
|
6151
6151
|
let userCount = 0;
|
|
6152
|
+
const seenPrompts = /* @__PURE__ */ new Set();
|
|
6153
|
+
const recordPrompt = (raw, line, dedupe = false) => {
|
|
6154
|
+
if (userCount >= maxMessages)
|
|
6155
|
+
return;
|
|
6156
|
+
const withoutReminders = raw.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "");
|
|
6157
|
+
if (!withoutReminders.trim() || withoutReminders.trim().length <= 10)
|
|
6158
|
+
return;
|
|
6159
|
+
const cleanedText = stripInjectedBanners(withoutReminders).trim();
|
|
6160
|
+
if (cleanedText.length < 10)
|
|
6161
|
+
return;
|
|
6162
|
+
if (dedupe && seenPrompts.has(cleanedText))
|
|
6163
|
+
return;
|
|
6164
|
+
seenPrompts.add(cleanedText);
|
|
6165
|
+
content.userMessages.push({ text: cleanedText, lineNumber: line, contentType: "user" });
|
|
6166
|
+
userCount++;
|
|
6167
|
+
if (!content.firstPrompt)
|
|
6168
|
+
content.firstPrompt = cleanedText.slice(0, 1e3);
|
|
6169
|
+
};
|
|
6152
6170
|
let assistantCount = 0;
|
|
6153
6171
|
let toolCount = 0;
|
|
6154
6172
|
let lineNum = 0;
|
|
@@ -6227,19 +6245,11 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
6227
6245
|
text = textParts.join("\n");
|
|
6228
6246
|
}
|
|
6229
6247
|
}
|
|
6230
|
-
if (text
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
|
|
6234
|
-
content
|
|
6235
|
-
text: cleanedText,
|
|
6236
|
-
lineNumber: lineNum,
|
|
6237
|
-
contentType: "user"
|
|
6238
|
-
});
|
|
6239
|
-
userCount++;
|
|
6240
|
-
if (!content.firstPrompt) {
|
|
6241
|
-
content.firstPrompt = cleanedText.slice(0, 1e3);
|
|
6242
|
-
}
|
|
6248
|
+
if (text)
|
|
6249
|
+
recordPrompt(text, lineNum);
|
|
6250
|
+
} else if (msgType === "queue-operation") {
|
|
6251
|
+
if (obj.operation === "enqueue" && typeof obj.content === "string") {
|
|
6252
|
+
recordPrompt(obj.content, lineNum, true);
|
|
6243
6253
|
}
|
|
6244
6254
|
} else if (msgType === "assistant") {
|
|
6245
6255
|
const msg = obj.message;
|
|
@@ -8541,6 +8551,9 @@ var init_generic_engine = __esm({
|
|
|
8541
8551
|
// ../engine/dist/core/backends/claude.js
|
|
8542
8552
|
import { existsSync as existsSync10, readdirSync as readdirSync6, readFileSync as readFileSync6, statSync as statSync8, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
|
|
8543
8553
|
import { join as join10, basename as basename8 } from "path";
|
|
8554
|
+
function stripReminders(text) {
|
|
8555
|
+
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
8556
|
+
}
|
|
8544
8557
|
function parseExitCode(text) {
|
|
8545
8558
|
const m = text.match(/(?:^|\n)\s*(?:exit\s+code|returncode|exit\s+status|exit)\s*[:=]\s*(\d+)\b/i);
|
|
8546
8559
|
return m ? Number(m[1]) : void 0;
|
|
@@ -8849,6 +8862,15 @@ var init_claude2 = __esm({
|
|
|
8849
8862
|
}
|
|
8850
8863
|
const tsIso = typeof obj.timestamp === "string" ? obj.timestamp : void 0;
|
|
8851
8864
|
const ts = tsIso ? Date.parse(tsIso) || mtime : mtime;
|
|
8865
|
+
if (obj.type === "queue-operation") {
|
|
8866
|
+
if (obj.operation === "enqueue" && typeof obj.content === "string") {
|
|
8867
|
+
const queued = stripReminders(obj.content);
|
|
8868
|
+
if (queued && !queued.startsWith("<task-notification")) {
|
|
8869
|
+
events.push({ kind: "user", ts, tsIso, line: lineNum, text: queued });
|
|
8870
|
+
}
|
|
8871
|
+
}
|
|
8872
|
+
continue;
|
|
8873
|
+
}
|
|
8852
8874
|
if (obj.type === "user") {
|
|
8853
8875
|
const msg = obj.message;
|
|
8854
8876
|
const content = msg?.content;
|
|
@@ -8882,9 +8904,9 @@ var init_claude2 = __esm({
|
|
|
8882
8904
|
}
|
|
8883
8905
|
}
|
|
8884
8906
|
}
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8907
|
+
const spoken = stripReminders(text);
|
|
8908
|
+
if (spoken)
|
|
8909
|
+
events.push({ kind: "user", ts, tsIso, line: lineNum, text: spoken });
|
|
8888
8910
|
for (const tr of toolResults) {
|
|
8889
8911
|
events.push({
|
|
8890
8912
|
kind: "tool_result",
|
|
@@ -10499,23 +10521,24 @@ var init_codex2 = __esm({
|
|
|
10499
10521
|
return null;
|
|
10500
10522
|
}
|
|
10501
10523
|
/**
|
|
10502
|
-
|
|
10503
|
-
|
|
10504
|
-
|
|
10505
|
-
|
|
10506
|
-
|
|
10507
|
-
|
|
10508
|
-
|
|
10509
|
-
|
|
10510
|
-
|
|
10511
|
-
|
|
10512
|
-
|
|
10513
|
-
|
|
10514
|
-
|
|
10515
|
-
|
|
10516
|
-
|
|
10517
|
-
|
|
10518
|
-
|
|
10524
|
+
* Stream a Codex JSONL rollout into canonical events. Codex separates:
|
|
10525
|
+
* - event_msg + payload.type='user_message' → user
|
|
10526
|
+
* - response_item + payload.type='message' → user OR assistant_text,
|
|
10527
|
+
* by payload.role
|
|
10528
|
+
* - response_item + payload.type='function_call' → tool_use
|
|
10529
|
+
* - response_item + payload.type='function_call_output' → tool_result
|
|
10530
|
+
*
|
|
10531
|
+
* Filters Codex's wrapper-bearing user messages (environment_context etc.).
|
|
10532
|
+
*
|
|
10533
|
+
* **Subagent fan-out:** Codex orchestrates work via `spawn_agent` calls
|
|
10534
|
+
* that produce sibling rollout files in the same YYYY/MM/DD directory.
|
|
10535
|
+
* Sub-agent rollouts carry `payload.source.subagent.thread_spawn` linking
|
|
10536
|
+
* back to the parent. The actual file edits often happen inside those
|
|
10537
|
+
* subagent rollouts — without folding their events into the parent's
|
|
10538
|
+
* stream, replay/scan would see the parent as edit-free. We append every
|
|
10539
|
+
* subagent rollout's events here so the generic engine sees one unified
|
|
10540
|
+
* stream per user-facing session.
|
|
10541
|
+
*/
|
|
10519
10542
|
readEvents(rawId) {
|
|
10520
10543
|
const located = findCodexSessionFile(this.toRawId(rawId));
|
|
10521
10544
|
if (!located)
|
|
@@ -10585,6 +10608,11 @@ var init_codex2 = __esm({
|
|
|
10585
10608
|
if (text && !isCodexInjectedWrapper2(text)) {
|
|
10586
10609
|
events.push({ kind: "user", ts, tsIso, line: lineNum, text });
|
|
10587
10610
|
}
|
|
10611
|
+
} else if (obj.type === "response_item" && payload.type === "message" && payload.role === "user") {
|
|
10612
|
+
const text = flattenContent(payload.content).trim();
|
|
10613
|
+
if (text && !isCodexInjectedWrapper2(text)) {
|
|
10614
|
+
events.push({ kind: "user", ts, tsIso, line: lineNum, text });
|
|
10615
|
+
}
|
|
10588
10616
|
} else if (obj.type === "response_item" && payload.type === "message" && payload.role === "assistant") {
|
|
10589
10617
|
const text = flattenContent(payload.content).trim();
|
|
10590
10618
|
if (text)
|
|
@@ -17008,7 +17036,9 @@ var init_extractor_version = __esm({
|
|
|
17008
17036
|
"use strict";
|
|
17009
17037
|
BASE_EXTRACTOR_VERSION = 2;
|
|
17010
17038
|
TOOL_EXTRACTOR_BUMP = {
|
|
17011
|
-
agy: 2
|
|
17039
|
+
agy: 2,
|
|
17040
|
+
claude: 1,
|
|
17041
|
+
codex: 1
|
|
17012
17042
|
};
|
|
17013
17043
|
EXTRACTOR_VERSION = BASE_EXTRACTOR_VERSION;
|
|
17014
17044
|
}
|
|
@@ -17326,7 +17356,7 @@ var init_http = __esm({
|
|
|
17326
17356
|
CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
17327
17357
|
} catch {
|
|
17328
17358
|
try {
|
|
17329
|
-
if (true) CLI_VERSION = "0.5.
|
|
17359
|
+
if (true) CLI_VERSION = "0.5.5";
|
|
17330
17360
|
} catch {
|
|
17331
17361
|
}
|
|
17332
17362
|
}
|
|
@@ -17900,6 +17930,17 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
17900
17930
|
if (res.status === 401 || res.status === 403) {
|
|
17901
17931
|
throw new Error(`server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base}`);
|
|
17902
17932
|
}
|
|
17933
|
+
if (res.status === 402) {
|
|
17934
|
+
let detail = text;
|
|
17935
|
+
try {
|
|
17936
|
+
const body2 = JSON.parse(text);
|
|
17937
|
+
detail = body2.error ?? text;
|
|
17938
|
+
if (body2.resetsAt) detail += ` (resets ${new Date(body2.resetsAt).toISOString().slice(0, 10)})`;
|
|
17939
|
+
if (body2.upgradeUrl) detail += ` \u2014 ${body2.upgradeUrl}`;
|
|
17940
|
+
} catch {
|
|
17941
|
+
}
|
|
17942
|
+
throw new Error(`sync paused by the server: ${detail}`);
|
|
17943
|
+
}
|
|
17903
17944
|
if (!retryable) throw new Error(`sync failed: HTTP ${res.status} ${text}`);
|
|
17904
17945
|
if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
|
|
17905
17946
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
@@ -18784,7 +18825,7 @@ var init_sync_client = __esm({
|
|
|
18784
18825
|
ownVersion = JSON.parse(readFileSync32(join41(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
18785
18826
|
} catch {
|
|
18786
18827
|
try {
|
|
18787
|
-
if (true) ownVersion = "0.5.
|
|
18828
|
+
if (true) ownVersion = "0.5.5";
|
|
18788
18829
|
} catch {
|
|
18789
18830
|
}
|
|
18790
18831
|
}
|
|
@@ -19625,6 +19666,14 @@ async function collectCode(opts) {
|
|
|
19625
19666
|
agentPrompt: manifestPrompt(v.violation_type ?? "", file, v.line ?? null, v.description ?? "")
|
|
19626
19667
|
});
|
|
19627
19668
|
}
|
|
19669
|
+
{
|
|
19670
|
+
const before = findings.length;
|
|
19671
|
+
const own = findings.filter((f) => !f.file || !isGenerated(f.file));
|
|
19672
|
+
if (own.length !== before) {
|
|
19673
|
+
findings.splice(0, before, ...own);
|
|
19674
|
+
log6(`dropped ${before - own.length} finding(s) in vendored/generated files`);
|
|
19675
|
+
}
|
|
19676
|
+
}
|
|
19628
19677
|
const godSet = new Set((coup?.god_modules ?? []).map((m) => rel(m.file)));
|
|
19629
19678
|
const cloneSet = /* @__PURE__ */ new Set();
|
|
19630
19679
|
for (const g of clones?.groups ?? [])
|
|
@@ -19710,7 +19759,9 @@ async function collectCode(opts) {
|
|
|
19710
19759
|
}
|
|
19711
19760
|
for (const g of clones?.groups ?? []) {
|
|
19712
19761
|
if ((g.count ?? 0) >= 3 || (g.lines ?? 0) >= 12) {
|
|
19713
|
-
const fns = (g.functions ?? []).filter((x) => x && typeof x === "object");
|
|
19762
|
+
const fns = (g.functions ?? []).filter((x) => x && typeof x === "object").filter((x) => !isGenerated(rel(x.file)));
|
|
19763
|
+
if (fns.length < 2)
|
|
19764
|
+
continue;
|
|
19714
19765
|
const names = [...new Set(fns.map((x) => x.name))];
|
|
19715
19766
|
const locs = fns.map((x) => rel(x.file)).slice(0, 5);
|
|
19716
19767
|
pushAction((g.lines ?? 0) * (g.count ?? 0) >= 150 ? 1 : 2, "duplication", `${names.join(", ")} copy-pasted ${g.count}\xD7 (${g.lines} lines each)`, "Extract one shared implementation and replace the copies.", locs.map((f) => ({ file: f })), clonePrompt(names, g.lines ?? 0, g.count ?? 0, locs));
|
|
@@ -19729,10 +19780,14 @@ async function collectCode(opts) {
|
|
|
19729
19780
|
}
|
|
19730
19781
|
for (const m of (coup?.god_modules ?? []).slice(0, 5)) {
|
|
19731
19782
|
const file = rel(m.file);
|
|
19783
|
+
if (isGenerated(file))
|
|
19784
|
+
continue;
|
|
19732
19785
|
pushAction(2, "modularity", `God module ${file} (fan-in ${m.fan_in}, fan-out ${m.fan_out})`, "Split into cohesive sub-modules; introduce interfaces to cut fan-out.", [{ file }], couplingPrompt(file, m.fan_in ?? 0, m.fan_out ?? 0, Math.round((m.instability ?? 0) * 100) / 100));
|
|
19733
19786
|
}
|
|
19734
19787
|
for (const c of (cyc?.cycles ?? []).slice(0, 5)) {
|
|
19735
|
-
const chain = (c.files ?? []).map(rel);
|
|
19788
|
+
const chain = (c.files ?? []).map(rel).filter((f) => !isGenerated(f));
|
|
19789
|
+
if (chain.length < 2)
|
|
19790
|
+
continue;
|
|
19736
19791
|
pushAction(2, "architecture", `Circular dependency (${chain.length} files)`, "Break the cycle: extract the shared type/interface into a separate module.", chain.slice(0, 4).map((f) => ({ file: f })), cyclePrompt(chain.slice(0, 6)));
|
|
19737
19792
|
}
|
|
19738
19793
|
for (const h of hotspotsAll.slice(0, 5)) {
|
|
@@ -19871,7 +19926,31 @@ var init_collector = __esm({
|
|
|
19871
19926
|
"migration_parity",
|
|
19872
19927
|
"manifest_compliance"
|
|
19873
19928
|
];
|
|
19874
|
-
GENERATED = [
|
|
19929
|
+
GENERATED = [
|
|
19930
|
+
"generated/",
|
|
19931
|
+
"__generated__/",
|
|
19932
|
+
".pb.go",
|
|
19933
|
+
".gen.",
|
|
19934
|
+
"_pb2.py",
|
|
19935
|
+
"/gen/",
|
|
19936
|
+
".g.dart",
|
|
19937
|
+
"/node_modules/",
|
|
19938
|
+
"/vendor/",
|
|
19939
|
+
"/third_party/",
|
|
19940
|
+
"/site-packages/",
|
|
19941
|
+
".lock",
|
|
19942
|
+
"/dist/",
|
|
19943
|
+
"/build/",
|
|
19944
|
+
"/out/",
|
|
19945
|
+
"/target/",
|
|
19946
|
+
"/.next/",
|
|
19947
|
+
"/coverage/",
|
|
19948
|
+
".min.js",
|
|
19949
|
+
".min.css",
|
|
19950
|
+
".bundle.js",
|
|
19951
|
+
"-bundle.js",
|
|
19952
|
+
".map"
|
|
19953
|
+
];
|
|
19875
19954
|
CF_RE = /\b(if|for|while|switch|case|catch|elif|when|loop|&&|\|\||\?)\b|\?/g;
|
|
19876
19955
|
DEPTH = 2;
|
|
19877
19956
|
MCP_OUT_MAX_BYTES = 64 * 1024 * 1024;
|
|
@@ -20362,6 +20441,46 @@ var init_service_installer = __esm({
|
|
|
20362
20441
|
|
|
20363
20442
|
// src/mcp.ts
|
|
20364
20443
|
import { config } from "dotenv";
|
|
20444
|
+
|
|
20445
|
+
// src/mcp-diagnostics.ts
|
|
20446
|
+
async function buildHttpError(path, res) {
|
|
20447
|
+
const status = res.status;
|
|
20448
|
+
let body = null;
|
|
20449
|
+
try {
|
|
20450
|
+
body = await res.clone().json();
|
|
20451
|
+
} catch {
|
|
20452
|
+
}
|
|
20453
|
+
const str = (k) => typeof body?.[k] === "string" ? body[k] : "";
|
|
20454
|
+
if (status === 402) {
|
|
20455
|
+
const parts = [str("error") || "payment required"];
|
|
20456
|
+
if (str("detail")) parts.push(str("detail"));
|
|
20457
|
+
if (str("feature")) {
|
|
20458
|
+
parts.push(`This is the "${str("feature")}" capability${str("requires") ? `, on the ${str("requires")} plan` : ""}.`);
|
|
20459
|
+
}
|
|
20460
|
+
if (str("upgradeUrl")) parts.push(`Upgrade: ${str("upgradeUrl")}`);
|
|
20461
|
+
if (str("checkoutHint")) parts.push(str("checkoutHint"));
|
|
20462
|
+
if (str("resendHint")) parts.push(str("resendHint"));
|
|
20463
|
+
parts.push("Nothing has been deleted. The free plan keeps sync and recent-history search working.");
|
|
20464
|
+
return new Error(`server ${path}: ${parts.join(" ")}`);
|
|
20465
|
+
}
|
|
20466
|
+
const hint = status === 401 || status === 403 ? "auth failed \u2014 re-run `chat-recall login <server-url>`" : status === 404 ? "not found \u2014 the id may be wrong, or the server is older than this CLI" : status === 429 ? "rate limited \u2014 retry in a moment" : status >= 500 ? "server error \u2014 check the chat-recall server logs" : str("error") || str("detail") || "request rejected";
|
|
20467
|
+
return new Error(`server ${path}: HTTP ${status} (${hint})`);
|
|
20468
|
+
}
|
|
20469
|
+
function stalenessBanner(state) {
|
|
20470
|
+
if (!state || state.entitled) return null;
|
|
20471
|
+
const since = state.periodEnd ? new Date(state.periodEnd).toISOString().slice(0, 10) : null;
|
|
20472
|
+
const days = state.periodEnd ? Math.max(0, Math.floor((Date.now() - state.periodEnd) / 864e5)) : null;
|
|
20473
|
+
const reason = state.status === "trialing" ? "the trial has ended" : state.status === "past_due" ? "a payment has not gone through" : "the subscription has lapsed";
|
|
20474
|
+
return [
|
|
20475
|
+
`\u26A0 FREE PLAN \u2014 ${reason}.`,
|
|
20476
|
+
"Search and lists cover only the recent window (default 7 days); older history is stored but locked.",
|
|
20477
|
+
since ? `The plan lapsed ${since}${days !== null ? ` (${days} days ago)` : ""}.` : "",
|
|
20478
|
+
"Do not tell the user their older work does not exist; say it is locked behind the free plan and unlocks on upgrade.",
|
|
20479
|
+
"Sync continues under a monthly quota, export always works, and nothing has been deleted."
|
|
20480
|
+
].filter(Boolean).join(" ");
|
|
20481
|
+
}
|
|
20482
|
+
|
|
20483
|
+
// src/mcp.ts
|
|
20365
20484
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
20366
20485
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20367
20486
|
import {
|
|
@@ -20699,10 +20818,6 @@ function remoteCredentials() {
|
|
|
20699
20818
|
return null;
|
|
20700
20819
|
}
|
|
20701
20820
|
}
|
|
20702
|
-
function httpError(path, status) {
|
|
20703
|
-
const hint = status === 401 || status === 403 ? "auth failed \u2014 re-run `chat-recall login <server-url>`" : status === 404 ? "not found \u2014 the id may be wrong, or the server is older than this CLI" : status === 429 ? "rate limited \u2014 retry in a moment" : status >= 500 ? "server error \u2014 check the chat-recall server logs" : "request rejected";
|
|
20704
|
-
return new Error(`server ${path}: HTTP ${status} (${hint})`);
|
|
20705
|
-
}
|
|
20706
20821
|
async function remotePost(path, body) {
|
|
20707
20822
|
const cred = remoteCredentials();
|
|
20708
20823
|
if (!cred) throw new Error('scope "server" needs a login \u2014 run `chat-recall login <server-url>` first.');
|
|
@@ -20711,7 +20826,7 @@ async function remotePost(path, body) {
|
|
|
20711
20826
|
headers: { "content-type": "application/json", authorization: `Bearer ${cred.token}` },
|
|
20712
20827
|
body: JSON.stringify(body)
|
|
20713
20828
|
});
|
|
20714
|
-
if (!res.ok) throw
|
|
20829
|
+
if (!res.ok) throw await buildHttpError(path, res);
|
|
20715
20830
|
return res.json();
|
|
20716
20831
|
}
|
|
20717
20832
|
async function remoteGet(path) {
|
|
@@ -20720,7 +20835,7 @@ async function remoteGet(path) {
|
|
|
20720
20835
|
const res = await fetch(cred.base + path, {
|
|
20721
20836
|
headers: { authorization: `Bearer ${cred.token}` }
|
|
20722
20837
|
});
|
|
20723
|
-
if (!res.ok) throw
|
|
20838
|
+
if (!res.ok) throw await buildHttpError(path, res);
|
|
20724
20839
|
return res.json();
|
|
20725
20840
|
}
|
|
20726
20841
|
async function remotePatch(path, body) {
|
|
@@ -20731,7 +20846,7 @@ async function remotePatch(path, body) {
|
|
|
20731
20846
|
headers: { "content-type": "application/json", authorization: `Bearer ${cred.token}` },
|
|
20732
20847
|
body: JSON.stringify(body)
|
|
20733
20848
|
});
|
|
20734
|
-
if (!res.ok) throw
|
|
20849
|
+
if (!res.ok) throw await buildHttpError(path, res);
|
|
20735
20850
|
return res.json();
|
|
20736
20851
|
}
|
|
20737
20852
|
function requireRemote() {
|
|
@@ -20777,7 +20892,7 @@ Re-run with a longer prefix or the full id.`;
|
|
|
20777
20892
|
}
|
|
20778
20893
|
return { status: res.status, data: null, message };
|
|
20779
20894
|
}
|
|
20780
|
-
if (!res.ok) throw
|
|
20895
|
+
if (!res.ok) throw await buildHttpError(path, res);
|
|
20781
20896
|
return { status: res.status, data: await res.json() };
|
|
20782
20897
|
}
|
|
20783
20898
|
var RecallSearchSchema = z.object({
|
|
@@ -20915,7 +21030,12 @@ var RecallTaskUpdateSchema = z.object({
|
|
|
20915
21030
|
status: z.enum(TASK_STATUSES).optional(),
|
|
20916
21031
|
assignee: z.string().optional().describe("Reassign to this user id (sub); empty string unassigns"),
|
|
20917
21032
|
title: z.string().optional(),
|
|
20918
|
-
comment: z.string().optional().describe("Add a comment to the task")
|
|
21033
|
+
comment: z.string().optional().describe("Add a comment to the task"),
|
|
21034
|
+
linked_session_id: z.string().nullable().optional().describe("Session id to attach to the task (null detaches). Pass YOUR OWN current session id when you start working on the task.")
|
|
21035
|
+
});
|
|
21036
|
+
var RecallTaskCommentSchema = z.object({
|
|
21037
|
+
task_id: z.string().describe("Task id (t_\u2026) from recall_tasks"),
|
|
21038
|
+
body: z.string().describe("The comment text")
|
|
20919
21039
|
});
|
|
20920
21040
|
var RecallKGQuerySchema = z.object({
|
|
20921
21041
|
entity: z.string().describe('Entity name to query (e.g., "Alice", "chat-recall", "PostgreSQL")'),
|
|
@@ -21053,12 +21173,47 @@ var server = new Server(
|
|
|
21053
21173
|
}
|
|
21054
21174
|
}
|
|
21055
21175
|
);
|
|
21176
|
+
var LEAN_TOOLS = /* @__PURE__ */ new Set([
|
|
21177
|
+
// Resume and cold start — the reason most people reach for this at all.
|
|
21178
|
+
"recall_smart_resume",
|
|
21179
|
+
"recall_wake_up",
|
|
21180
|
+
"recall_recent",
|
|
21181
|
+
// Find things.
|
|
21182
|
+
"recall_search",
|
|
21183
|
+
"recall_memory_search",
|
|
21184
|
+
"recall_user_prompts",
|
|
21185
|
+
// Read one session.
|
|
21186
|
+
"recall_context",
|
|
21187
|
+
"recall_summary",
|
|
21188
|
+
"recall_show",
|
|
21189
|
+
// What changed.
|
|
21190
|
+
"recall_edits_timeline",
|
|
21191
|
+
"recall_diff",
|
|
21192
|
+
"recall_commits",
|
|
21193
|
+
// Project state and tasks.
|
|
21194
|
+
"recall_project_context",
|
|
21195
|
+
"recall_tasks",
|
|
21196
|
+
"recall_task_create",
|
|
21197
|
+
"recall_task_update",
|
|
21198
|
+
// Durable memory.
|
|
21199
|
+
"recall_kg_query",
|
|
21200
|
+
"recall_kg_add",
|
|
21201
|
+
"recall_decision_record",
|
|
21202
|
+
"recall_diary_write",
|
|
21203
|
+
"recall_diary_read",
|
|
21204
|
+
// Health, and the one that pays out on day one.
|
|
21205
|
+
"recall_status",
|
|
21206
|
+
"recall_index",
|
|
21207
|
+
"recall_security_summary"
|
|
21208
|
+
]);
|
|
21209
|
+
function toolProfile() {
|
|
21210
|
+
return (process.env.CHAT_RECALL_MCP_PROFILE || "").toLowerCase() === "full" ? "full" : "lean";
|
|
21211
|
+
}
|
|
21056
21212
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
21057
|
-
|
|
21058
|
-
|
|
21059
|
-
|
|
21060
|
-
|
|
21061
|
-
description: `Search for relevant past sessions to resume.
|
|
21213
|
+
const all = [
|
|
21214
|
+
{
|
|
21215
|
+
name: "recall_search",
|
|
21216
|
+
description: `Search for relevant past sessions to resume.
|
|
21062
21217
|
|
|
21063
21218
|
Find past conversations matching your current task. Returns session IDs that
|
|
21064
21219
|
can be used with \`claude --resume <session_id>\`.
|
|
@@ -21069,45 +21224,45 @@ Three modes on one tool:
|
|
|
21069
21224
|
first prompt as the search text, excludes itself, groups hits by project).
|
|
21070
21225
|
- \`include_outcome: true\` \u2014 append a per-result outcome one-liner (shipped /
|
|
21071
21226
|
interrupted / abandoned + edit stats) to judge whether each hit is worth resuming.`,
|
|
21072
|
-
|
|
21073
|
-
|
|
21074
|
-
|
|
21075
|
-
|
|
21076
|
-
|
|
21077
|
-
|
|
21078
|
-
|
|
21079
|
-
|
|
21080
|
-
|
|
21081
|
-
|
|
21082
|
-
|
|
21083
|
-
}
|
|
21227
|
+
inputSchema: {
|
|
21228
|
+
type: "object",
|
|
21229
|
+
properties: {
|
|
21230
|
+
query: { type: "string", description: `What you're looking for (e.g., "OAuth implementation"). Required unless like_session is set.` },
|
|
21231
|
+
like_session: { type: "string", description: "Find sessions similar to this session id instead of a free-text query." },
|
|
21232
|
+
include_outcome: { type: "boolean", default: false, description: "Append per-result outcome one-liners (status + edit stats)." },
|
|
21233
|
+
top_k: { type: "number", default: 5, description: "Number of results to return" },
|
|
21234
|
+
project_filter: { type: "string", description: "Optional filter by project path substring" },
|
|
21235
|
+
skip_ranking: { type: "boolean", default: false, description: "Skip Claude ranking for faster results" },
|
|
21236
|
+
provider: { type: "string", enum: ["ollama", "gemini"], default: "ollama", description: "Embedding provider" },
|
|
21237
|
+
scope: { type: "string", enum: ["local", "server"], default: "local", description: "Accepted for back-compat; search always runs against the synced server." }
|
|
21084
21238
|
}
|
|
21085
|
-
}
|
|
21086
|
-
|
|
21087
|
-
|
|
21088
|
-
|
|
21239
|
+
}
|
|
21240
|
+
},
|
|
21241
|
+
{
|
|
21242
|
+
name: "recall_index",
|
|
21243
|
+
description: `Index all Claude Code sessions for semantic search.
|
|
21089
21244
|
|
|
21090
21245
|
Scans ~/.claude/projects/ and creates embeddings for all sessions.
|
|
21091
21246
|
By default, only indexes new or changed sessions.`,
|
|
21092
|
-
|
|
21093
|
-
|
|
21094
|
-
|
|
21095
|
-
|
|
21096
|
-
|
|
21097
|
-
}
|
|
21098
|
-
}
|
|
21099
|
-
},
|
|
21100
|
-
{
|
|
21101
|
-
name: "recall_status",
|
|
21102
|
-
description: "Show index status and statistics: synced sessions, chunks, freshness, top projects, plus the full memory-system breakdown (items/chunks per source type, per AI tool, link count).",
|
|
21103
|
-
inputSchema: {
|
|
21104
|
-
type: "object",
|
|
21105
|
-
properties: {}
|
|
21247
|
+
inputSchema: {
|
|
21248
|
+
type: "object",
|
|
21249
|
+
properties: {
|
|
21250
|
+
force: { type: "boolean", default: false, description: "Force re-index all sessions" },
|
|
21251
|
+
provider: { type: "string", enum: ["ollama", "gemini"], default: "ollama", description: "Embedding provider" }
|
|
21106
21252
|
}
|
|
21107
|
-
}
|
|
21108
|
-
|
|
21109
|
-
|
|
21110
|
-
|
|
21253
|
+
}
|
|
21254
|
+
},
|
|
21255
|
+
{
|
|
21256
|
+
name: "recall_status",
|
|
21257
|
+
description: "Show index status and statistics: synced sessions, chunks, freshness, top projects, plus the full memory-system breakdown (items/chunks per source type, per AI tool, link count).",
|
|
21258
|
+
inputSchema: {
|
|
21259
|
+
type: "object",
|
|
21260
|
+
properties: {}
|
|
21261
|
+
}
|
|
21262
|
+
},
|
|
21263
|
+
{
|
|
21264
|
+
name: "recall_show",
|
|
21265
|
+
description: `Get conversation content from a specific session \u2014 or the full text of a plan.
|
|
21111
21266
|
|
|
21112
21267
|
Use this after recall_search to get full context from a session. Also accepts a
|
|
21113
21268
|
plan id (the plan filename without .md, as returned by
|
|
@@ -21116,57 +21271,57 @@ recall_memory_search(source_types:['plan'])) and renders the complete plan text.
|
|
|
21116
21271
|
Set \`from_end: N\` to fetch the last N messages (no line-number guessing).
|
|
21117
21272
|
Set \`include_code: true\` to keep code blocks instead of redacting them \u2014 useful
|
|
21118
21273
|
when the user is asking "what did we change?" and the diffs/SQL/commands matter.`,
|
|
21119
|
-
|
|
21120
|
-
|
|
21121
|
-
|
|
21122
|
-
|
|
21123
|
-
|
|
21124
|
-
|
|
21125
|
-
|
|
21126
|
-
|
|
21127
|
-
|
|
21128
|
-
|
|
21129
|
-
|
|
21130
|
-
|
|
21131
|
-
|
|
21132
|
-
|
|
21133
|
-
|
|
21274
|
+
inputSchema: {
|
|
21275
|
+
type: "object",
|
|
21276
|
+
properties: {
|
|
21277
|
+
session_id: { type: "string", description: "Session ID from search results, or a plan id (filename without .md)" },
|
|
21278
|
+
around_line: { type: "number", description: "Optional line number to show context around" },
|
|
21279
|
+
max_messages: { type: "number", default: 10, description: "Maximum messages to return" },
|
|
21280
|
+
from_end: { type: "number", description: "Return the last N messages (alternative to around_line)." },
|
|
21281
|
+
include_code: { type: "boolean", default: false, description: "Keep code blocks in assistant messages." }
|
|
21282
|
+
},
|
|
21283
|
+
required: ["session_id"]
|
|
21284
|
+
}
|
|
21285
|
+
},
|
|
21286
|
+
{
|
|
21287
|
+
name: "recall_recent",
|
|
21288
|
+
description: `List recent Claude Code sessions.
|
|
21134
21289
|
|
|
21135
21290
|
Shows your most recent conversations across all projects or filtered by project.
|
|
21136
21291
|
Use this when the user says "continue our last conversation" or wants to see recent work.
|
|
21137
21292
|
|
|
21138
21293
|
Pass \`since_hours: N\` to restrict to sessions modified in the last N hours.`,
|
|
21139
|
-
|
|
21140
|
-
|
|
21141
|
-
|
|
21142
|
-
|
|
21143
|
-
|
|
21144
|
-
|
|
21145
|
-
|
|
21146
|
-
}
|
|
21294
|
+
inputSchema: {
|
|
21295
|
+
type: "object",
|
|
21296
|
+
properties: {
|
|
21297
|
+
project_filter: { type: "string", description: 'Filter by project name (e.g., "inco", "poly")' },
|
|
21298
|
+
limit: { type: "number", default: 10, description: "Number of recent sessions to show" },
|
|
21299
|
+
since_hours: { type: "number", description: "Only include sessions modified in the last N hours." },
|
|
21300
|
+
scope: { type: "string", enum: ["local", "server"], default: "local", description: "server = synced cross-device history (needs chat-recall login)." }
|
|
21147
21301
|
}
|
|
21148
|
-
}
|
|
21149
|
-
|
|
21150
|
-
|
|
21151
|
-
|
|
21302
|
+
}
|
|
21303
|
+
},
|
|
21304
|
+
{
|
|
21305
|
+
name: "recall_rename_session",
|
|
21306
|
+
description: `Give a conversation a memorable name \u2014 or rename it \u2014 so you (and the user) can find and resume it later.
|
|
21152
21307
|
|
|
21153
21308
|
Mirrors Claude Code's session naming (\`/rename\`). The name replaces the auto-generated summary in
|
|
21154
21309
|
recall_recent and the web UI. Use it when the user says "name this conversation X", "call this session Y",
|
|
21155
21310
|
or "rename this to Z". Pass an empty string to clear the name and revert to the auto title.
|
|
21156
21311
|
|
|
21157
21312
|
The name persists across re-syncs and summary regeneration (it's stored separately from the AI summary).`,
|
|
21158
|
-
|
|
21159
|
-
|
|
21160
|
-
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21164
|
-
|
|
21165
|
-
|
|
21166
|
-
|
|
21167
|
-
|
|
21168
|
-
|
|
21169
|
-
|
|
21313
|
+
inputSchema: {
|
|
21314
|
+
type: "object",
|
|
21315
|
+
properties: {
|
|
21316
|
+
session_id: { type: "string", description: "Session ID to name (from recall_recent / recall_search)." },
|
|
21317
|
+
name: { type: "string", description: "The name to give this conversation. Empty string clears it." }
|
|
21318
|
+
},
|
|
21319
|
+
required: ["session_id", "name"]
|
|
21320
|
+
}
|
|
21321
|
+
},
|
|
21322
|
+
{
|
|
21323
|
+
name: "recall_edits_timeline",
|
|
21324
|
+
description: `Chronological list of file edits across recent sessions, spanning every AI tool
|
|
21170
21325
|
chat-recall indexes \u2014 Claude Code, Gemini CLI, OpenCode, Codex and Antigravity.
|
|
21171
21326
|
|
|
21172
21327
|
Returns rows shaped like (timestamp, tool, session_id, project, file, op) sorted newest
|
|
@@ -21179,28 +21334,28 @@ two hours of edits across every session and every AI tool.
|
|
|
21179
21334
|
|
|
21180
21335
|
Pass \`group_by: "session"\` (with \`pattern\` + a wide \`since_hours\`, e.g. 720) to
|
|
21181
21336
|
aggregate per session instead \u2014 "which sessions edited auth.rs in the last month?".`,
|
|
21182
|
-
|
|
21183
|
-
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
|
|
21188
|
-
|
|
21189
|
-
|
|
21190
|
-
|
|
21191
|
-
|
|
21192
|
-
|
|
21193
|
-
|
|
21194
|
-
|
|
21195
|
-
|
|
21196
|
-
|
|
21197
|
-
|
|
21198
|
-
}
|
|
21337
|
+
inputSchema: {
|
|
21338
|
+
type: "object",
|
|
21339
|
+
properties: {
|
|
21340
|
+
since_hours: { type: "number", default: 24, description: "Time window in hours" },
|
|
21341
|
+
limit: { type: "number", default: 100, description: "Maximum edit rows to return" },
|
|
21342
|
+
pattern: { type: "string", description: "Optional substring filter on file path" },
|
|
21343
|
+
project_filter: { type: "string", description: "Filter by encoded project directory name" },
|
|
21344
|
+
include_reads: { type: "boolean", default: false, description: "Include Read tool_uses too" },
|
|
21345
|
+
tools: {
|
|
21346
|
+
type: "array",
|
|
21347
|
+
items: { type: "string", enum: ["claude", "gemini", "opencode", "codex"] },
|
|
21348
|
+
description: "Restrict to specific AI tools. Default: all four."
|
|
21349
|
+
},
|
|
21350
|
+
group_by_repo: { type: "boolean", default: false, description: "Group results by detected git repo root." },
|
|
21351
|
+
view: { type: "string", enum: ["timeline", "summary"], default: "timeline", description: "timeline = chronological edit rows; summary = aggregated rollup over the same window" },
|
|
21352
|
+
group_by: { type: "string", enum: ["session"], description: '"session" = aggregate edits per session (which sessions touched files matching pattern).' }
|
|
21199
21353
|
}
|
|
21200
|
-
}
|
|
21201
|
-
|
|
21202
|
-
|
|
21203
|
-
|
|
21354
|
+
}
|
|
21355
|
+
},
|
|
21356
|
+
{
|
|
21357
|
+
name: "recall_context",
|
|
21358
|
+
description: `Get structured context from a session for continuation.
|
|
21204
21359
|
|
|
21205
21360
|
Returns:
|
|
21206
21361
|
- Your requests/inputs
|
|
@@ -21210,17 +21365,17 @@ Returns:
|
|
|
21210
21365
|
- Summary if available
|
|
21211
21366
|
|
|
21212
21367
|
Use this to understand what happened in a session before resuming.`,
|
|
21213
|
-
|
|
21214
|
-
|
|
21215
|
-
|
|
21216
|
-
|
|
21217
|
-
|
|
21218
|
-
|
|
21219
|
-
|
|
21220
|
-
|
|
21221
|
-
|
|
21222
|
-
|
|
21223
|
-
|
|
21368
|
+
inputSchema: {
|
|
21369
|
+
type: "object",
|
|
21370
|
+
properties: {
|
|
21371
|
+
session_id: { type: "string", description: "Session ID to get context from" }
|
|
21372
|
+
},
|
|
21373
|
+
required: ["session_id"]
|
|
21374
|
+
}
|
|
21375
|
+
},
|
|
21376
|
+
{
|
|
21377
|
+
name: "recall_summary",
|
|
21378
|
+
description: `Get the summary for a session \u2014 including its OUTCOME classification.
|
|
21224
21379
|
|
|
21225
21380
|
By default returns a *rich* summary that combines the AI summary (when available)
|
|
21226
21381
|
with the structured outcome derived from the transcript itself: status (shipped /
|
|
@@ -21231,18 +21386,18 @@ markers, and the last assistant claim paired with the user's reaction to it
|
|
|
21231
21386
|
This is the triage call when scanning a session list \u2014 it answers the question
|
|
21232
21387
|
the AI summary doesn't: did this work actually land?
|
|
21233
21388
|
Pass \`rich: false\` to fall back to the legacy single-line AI summary only.`,
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
|
|
21237
|
-
|
|
21238
|
-
|
|
21239
|
-
|
|
21240
|
-
|
|
21241
|
-
|
|
21242
|
-
|
|
21243
|
-
|
|
21244
|
-
|
|
21245
|
-
|
|
21389
|
+
inputSchema: {
|
|
21390
|
+
type: "object",
|
|
21391
|
+
properties: {
|
|
21392
|
+
session_id: { type: "string", description: "Session ID to get summary for" },
|
|
21393
|
+
rich: { type: "boolean", default: true, description: "Include structured outcome alongside AI summary" }
|
|
21394
|
+
},
|
|
21395
|
+
required: ["session_id"]
|
|
21396
|
+
}
|
|
21397
|
+
},
|
|
21398
|
+
{
|
|
21399
|
+
name: "recall_diff",
|
|
21400
|
+
description: `Replay a session's Edit/Write/MultiEdit/NotebookEdit tool calls into a unified
|
|
21246
21401
|
diff per file. Lets you see what the agent actually changed \u2014 not just that it
|
|
21247
21402
|
edited, but how \u2014 without grepping the raw transcript.
|
|
21248
21403
|
|
|
@@ -21253,21 +21408,21 @@ Pass \`file\` to focus on a single absolute path. Pass \`context_only: true\` fo
|
|
|
21253
21408
|
just the per-file stats (lines added/removed) when you don't need the diff body.
|
|
21254
21409
|
Pass \`files_only: true\` for just the list of files the session touched (grouped
|
|
21255
21410
|
by extension, with tools used) \u2014 "which files did session X actually touch?".`,
|
|
21256
|
-
|
|
21257
|
-
|
|
21258
|
-
|
|
21259
|
-
|
|
21260
|
-
|
|
21261
|
-
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
|
|
21266
|
-
|
|
21267
|
-
|
|
21268
|
-
|
|
21269
|
-
|
|
21270
|
-
|
|
21411
|
+
inputSchema: {
|
|
21412
|
+
type: "object",
|
|
21413
|
+
properties: {
|
|
21414
|
+
session_id: { type: "string", description: "Session ID to replay" },
|
|
21415
|
+
file: { type: "string", description: "Absolute file path to focus on (optional)" },
|
|
21416
|
+
context_only: { type: "boolean", default: false, description: "Skip diff bodies, return stats only" },
|
|
21417
|
+
files_only: { type: "boolean", default: false, description: "Return just the file list (no diffs/stats)" },
|
|
21418
|
+
max_diff_chars: { type: "number", default: 4e3, description: "Truncate each per-file unified diff" }
|
|
21419
|
+
},
|
|
21420
|
+
required: ["session_id"]
|
|
21421
|
+
}
|
|
21422
|
+
},
|
|
21423
|
+
{
|
|
21424
|
+
name: "recall_commits",
|
|
21425
|
+
description: `Find git commits that landed during a session's edit window, grouped by repo.
|
|
21271
21426
|
|
|
21272
21427
|
Multi-repo aware: a session that touched ~/code/personal/k8s_gpu and
|
|
21273
21428
|
~/code/personal/munbot returns commits from each repo, with overlap shown
|
|
@@ -21275,18 +21430,18 @@ between commit-files and session-touched-files.
|
|
|
21275
21430
|
|
|
21276
21431
|
Use this to verify "shipped" claims \u2014 if the session edited 18 files but no
|
|
21277
21432
|
matching commit exists, work probably stayed local.`,
|
|
21278
|
-
|
|
21279
|
-
|
|
21280
|
-
|
|
21281
|
-
|
|
21282
|
-
|
|
21283
|
-
|
|
21284
|
-
|
|
21285
|
-
|
|
21286
|
-
|
|
21287
|
-
|
|
21288
|
-
|
|
21289
|
-
|
|
21433
|
+
inputSchema: {
|
|
21434
|
+
type: "object",
|
|
21435
|
+
properties: {
|
|
21436
|
+
session_id: { type: "string", description: "Session ID to look up commits for" },
|
|
21437
|
+
buffer_minutes: { type: "number", default: 30, description: "Window padding on each side" }
|
|
21438
|
+
},
|
|
21439
|
+
required: ["session_id"]
|
|
21440
|
+
}
|
|
21441
|
+
},
|
|
21442
|
+
{
|
|
21443
|
+
name: "recall_markers",
|
|
21444
|
+
description: `Tag every user prompt in a session with sentiment / corrective markers:
|
|
21290
21445
|
|
|
21291
21446
|
\u2022 interrupt \u2014 user hit ESC mid-response
|
|
21292
21447
|
\u2022 frustrated \u2014 caps, profanity, "wtf", "ffs"
|
|
@@ -21298,43 +21453,43 @@ matching commit exists, work probably stayed local.`,
|
|
|
21298
21453
|
|
|
21299
21454
|
Returns per-prompt markers + a session-level summary count. Use this to spot
|
|
21300
21455
|
sessions where things went sideways before reading the whole transcript.`,
|
|
21301
|
-
|
|
21302
|
-
|
|
21303
|
-
|
|
21304
|
-
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21308
|
-
|
|
21309
|
-
|
|
21310
|
-
|
|
21311
|
-
|
|
21312
|
-
|
|
21456
|
+
inputSchema: {
|
|
21457
|
+
type: "object",
|
|
21458
|
+
properties: {
|
|
21459
|
+
session_id: { type: "string", description: "Session ID to mark prompts in" },
|
|
21460
|
+
limit: { type: "number", default: 200, description: "Maximum prompts to return" }
|
|
21461
|
+
},
|
|
21462
|
+
required: ["session_id"]
|
|
21463
|
+
}
|
|
21464
|
+
},
|
|
21465
|
+
{
|
|
21466
|
+
name: "recall_memory_search",
|
|
21467
|
+
description: `Search across all memory types: sessions, plans, tasks, CLAUDE.md files, history, paste cache, and agent diaries.
|
|
21313
21468
|
|
|
21314
21469
|
Returns results from any memory source, ranked by relevance. Use source_types to filter.
|
|
21315
21470
|
Plans and tasks are found here (source_types: ['plan', 'task']); read a full plan
|
|
21316
21471
|
with recall_show (pass the plan id).`,
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
|
|
21321
|
-
|
|
21322
|
-
|
|
21323
|
-
|
|
21324
|
-
|
|
21325
|
-
|
|
21326
|
-
},
|
|
21327
|
-
project_filter: { type: "string", description: "Filter by project path" },
|
|
21328
|
-
provider: { type: "string", enum: ["ollama", "gemini"], default: "ollama" },
|
|
21329
|
-
scope: { type: "string", enum: ["local", "server"], default: "local", description: "server = synced cross-device history (needs chat-recall login)." },
|
|
21330
|
-
semantic: { type: "boolean", default: false, description: "Also run the pgvector semantic tier, not just keyword FTS. Needs an embedder configured server-side; ignored otherwise." }
|
|
21472
|
+
inputSchema: {
|
|
21473
|
+
type: "object",
|
|
21474
|
+
properties: {
|
|
21475
|
+
query: { type: "string", description: "What you're looking for across all memory types" },
|
|
21476
|
+
top_k: { type: "number", default: 10, description: "Number of results" },
|
|
21477
|
+
source_types: {
|
|
21478
|
+
type: "array",
|
|
21479
|
+
items: { type: "string", enum: ["session", "plan", "task", "claude_md", "paste", "history", "diary"] },
|
|
21480
|
+
description: "Filter by source types (default: all)"
|
|
21331
21481
|
},
|
|
21332
|
-
|
|
21333
|
-
|
|
21334
|
-
|
|
21335
|
-
|
|
21336
|
-
|
|
21337
|
-
|
|
21482
|
+
project_filter: { type: "string", description: "Filter by project path" },
|
|
21483
|
+
provider: { type: "string", enum: ["ollama", "gemini"], default: "ollama" },
|
|
21484
|
+
scope: { type: "string", enum: ["local", "server"], default: "local", description: "server = synced cross-device history (needs chat-recall login)." },
|
|
21485
|
+
semantic: { type: "boolean", default: false, description: "Also run the pgvector semantic tier, not just keyword FTS. Needs an embedder configured server-side; ignored otherwise." }
|
|
21486
|
+
},
|
|
21487
|
+
required: ["query"]
|
|
21488
|
+
}
|
|
21489
|
+
},
|
|
21490
|
+
{
|
|
21491
|
+
name: "recall_smart_resume",
|
|
21492
|
+
description: `Get structured resume context for a session.
|
|
21338
21493
|
|
|
21339
21494
|
Returns:
|
|
21340
21495
|
- What was done (completed work, decisions made)
|
|
@@ -21344,17 +21499,17 @@ Returns:
|
|
|
21344
21499
|
- Resume command
|
|
21345
21500
|
|
|
21346
21501
|
Use this instead of recall_context for a more actionable summary when resuming work.`,
|
|
21347
|
-
|
|
21348
|
-
|
|
21349
|
-
|
|
21350
|
-
|
|
21351
|
-
|
|
21352
|
-
|
|
21353
|
-
|
|
21354
|
-
|
|
21355
|
-
|
|
21356
|
-
|
|
21357
|
-
|
|
21502
|
+
inputSchema: {
|
|
21503
|
+
type: "object",
|
|
21504
|
+
properties: {
|
|
21505
|
+
session_id: { type: "string", description: "Session ID to resume" }
|
|
21506
|
+
},
|
|
21507
|
+
required: ["session_id"]
|
|
21508
|
+
}
|
|
21509
|
+
},
|
|
21510
|
+
{
|
|
21511
|
+
name: "recall_project_context",
|
|
21512
|
+
description: `Get the full project dossier as markdown \u2014 rich project context.
|
|
21358
21513
|
|
|
21359
21514
|
Aggregates everything the index knows about one project into a single report:
|
|
21360
21515
|
overview (from CLAUDE.md), tech stack (KG uses), architecture / deployment / security
|
|
@@ -21369,20 +21524,20 @@ Accepts EITHER a project path / name substring (e.g. "munbot", "chat-recall",
|
|
|
21369
21524
|
- "user:<custom>" (declared in ~/.chat-recall/projects.json)
|
|
21370
21525
|
|
|
21371
21526
|
Use at the START of a new session to understand what's been happening in a project.`,
|
|
21372
|
-
|
|
21373
|
-
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
21379
|
-
|
|
21380
|
-
|
|
21381
|
-
|
|
21382
|
-
|
|
21383
|
-
|
|
21384
|
-
|
|
21385
|
-
|
|
21527
|
+
inputSchema: {
|
|
21528
|
+
type: "object",
|
|
21529
|
+
properties: {
|
|
21530
|
+
project_path: { type: "string", description: "Project path, name substring, or project_id (git:/ws:/git-local:/user:)" },
|
|
21531
|
+
limit: { type: "number", default: 5, description: "Number of recent sessions to include" },
|
|
21532
|
+
tasks: { type: "number", default: 20, description: "Max open tasks to list" },
|
|
21533
|
+
plans: { type: "number", default: 20, description: "Max plans to list" }
|
|
21534
|
+
},
|
|
21535
|
+
required: ["project_path"]
|
|
21536
|
+
}
|
|
21537
|
+
},
|
|
21538
|
+
{
|
|
21539
|
+
name: "recall_weekly_digest",
|
|
21540
|
+
description: `Get a weekly activity digest across all projects.
|
|
21386
21541
|
|
|
21387
21542
|
Returns:
|
|
21388
21543
|
- Session count, total cost, coding time
|
|
@@ -21392,16 +21547,16 @@ Returns:
|
|
|
21392
21547
|
- Git activity summary
|
|
21393
21548
|
|
|
21394
21549
|
Use to understand overall productivity and spending.`,
|
|
21395
|
-
|
|
21396
|
-
|
|
21397
|
-
|
|
21398
|
-
|
|
21399
|
-
}
|
|
21550
|
+
inputSchema: {
|
|
21551
|
+
type: "object",
|
|
21552
|
+
properties: {
|
|
21553
|
+
weeks_back: { type: "number", default: 0, description: "0 = current week, 1 = last week" }
|
|
21400
21554
|
}
|
|
21401
|
-
}
|
|
21402
|
-
|
|
21403
|
-
|
|
21404
|
-
|
|
21555
|
+
}
|
|
21556
|
+
},
|
|
21557
|
+
{
|
|
21558
|
+
name: "recall_team_activity",
|
|
21559
|
+
description: `See what each teammate did, grouped by project \u2014 the team activity view.
|
|
21405
21560
|
|
|
21406
21561
|
Returns a per-member \xD7 per-project rollup (session counts + last activity) for
|
|
21407
21562
|
your team. Scoped to what you're allowed to see: your own work plus teammates'
|
|
@@ -21409,210 +21564,236 @@ work on projects they've shared into the team (private projects never appear).
|
|
|
21409
21564
|
|
|
21410
21565
|
Use for "what has the team been working on", "what did <teammate> do on <project>",
|
|
21411
21566
|
or standup/status. Filter by project, by member, or by recency (since_days).`,
|
|
21412
|
-
|
|
21413
|
-
|
|
21414
|
-
|
|
21415
|
-
|
|
21416
|
-
|
|
21417
|
-
|
|
21418
|
-
}
|
|
21567
|
+
inputSchema: {
|
|
21568
|
+
type: "object",
|
|
21569
|
+
properties: {
|
|
21570
|
+
project: { type: "string", description: "Filter to one project_id" },
|
|
21571
|
+
member: { type: "string", description: "Filter to one teammate (user id / sub)" },
|
|
21572
|
+
since_days: { type: "number", description: "Only activity in the last N days" }
|
|
21419
21573
|
}
|
|
21420
|
-
}
|
|
21421
|
-
|
|
21422
|
-
|
|
21423
|
-
|
|
21574
|
+
}
|
|
21575
|
+
},
|
|
21576
|
+
{
|
|
21577
|
+
name: "recall_tasks",
|
|
21578
|
+
description: `List collaborative team tasks (the shared task board).
|
|
21424
21579
|
|
|
21425
21580
|
Team-visible tasks with status, assignee, and project. Use for "what's on the
|
|
21426
21581
|
team's plate", "my tasks", or to find a task id to update. Filter by mine /
|
|
21427
21582
|
project / status.`,
|
|
21428
|
-
|
|
21429
|
-
|
|
21430
|
-
|
|
21431
|
-
|
|
21432
|
-
|
|
21433
|
-
|
|
21434
|
-
}
|
|
21435
|
-
}
|
|
21436
|
-
},
|
|
21437
|
-
{
|
|
21438
|
-
name: "recall_task_create",
|
|
21439
|
-
description: `Create a collaborative team task. Optionally assign it to a teammate and
|
|
21440
|
-
attach it to a project. Returns the new task id.`,
|
|
21441
|
-
inputSchema: {
|
|
21442
|
-
type: "object",
|
|
21443
|
-
properties: {
|
|
21444
|
-
title: { type: "string", description: "Task title" },
|
|
21445
|
-
description: { type: "string" },
|
|
21446
|
-
project: { type: "string", description: "project_id this task belongs to" },
|
|
21447
|
-
assignee: { type: "string", description: "Teammate user id (sub) to assign" }
|
|
21448
|
-
},
|
|
21449
|
-
required: ["title"]
|
|
21450
|
-
}
|
|
21451
|
-
},
|
|
21452
|
-
{
|
|
21453
|
-
name: "recall_task_update",
|
|
21454
|
-
description: `Update a team task: change status, reassign, rename, and/or add a comment.
|
|
21455
|
-
Pass the task id (t_\u2026) from recall_tasks.`,
|
|
21456
|
-
inputSchema: {
|
|
21457
|
-
type: "object",
|
|
21458
|
-
properties: {
|
|
21459
|
-
id: { type: "string", description: "Task id (t_\u2026)" },
|
|
21460
|
-
status: { type: "string", enum: [...TASK_STATUSES] },
|
|
21461
|
-
assignee: { type: "string", description: "Reassign to this user id (sub)" },
|
|
21462
|
-
title: { type: "string" },
|
|
21463
|
-
comment: { type: "string", description: "Add a comment" }
|
|
21464
|
-
},
|
|
21465
|
-
required: ["id"]
|
|
21583
|
+
inputSchema: {
|
|
21584
|
+
type: "object",
|
|
21585
|
+
properties: {
|
|
21586
|
+
mine: { type: "boolean", description: "Only tasks assigned to me" },
|
|
21587
|
+
project: { type: "string", description: "Filter to one project_id" },
|
|
21588
|
+
status: { type: "string", enum: [...TASK_STATUSES], description: "Filter by status" }
|
|
21466
21589
|
}
|
|
21467
|
-
}
|
|
21468
|
-
|
|
21469
|
-
|
|
21470
|
-
|
|
21471
|
-
|
|
21590
|
+
}
|
|
21591
|
+
},
|
|
21592
|
+
{
|
|
21593
|
+
name: "recall_task_create",
|
|
21594
|
+
description: `Create a collaborative team task. Optionally assign it to a teammate and
|
|
21595
|
+
attach it to a project. Returns the new task id.
|
|
21596
|
+
|
|
21597
|
+
When you then START working on a task, use recall_task_update to set status
|
|
21598
|
+
'in_progress' and link your current session (linked_session_id) \u2014 that is what
|
|
21599
|
+
lets the board verify the work actually shipped.`,
|
|
21600
|
+
inputSchema: {
|
|
21601
|
+
type: "object",
|
|
21602
|
+
properties: {
|
|
21603
|
+
title: { type: "string", description: "Task title" },
|
|
21604
|
+
description: { type: "string" },
|
|
21605
|
+
project: { type: "string", description: "project_id this task belongs to" },
|
|
21606
|
+
assignee: { type: "string", description: "Teammate user id (sub) to assign" }
|
|
21607
|
+
},
|
|
21608
|
+
required: ["title"]
|
|
21609
|
+
}
|
|
21610
|
+
},
|
|
21611
|
+
{
|
|
21612
|
+
name: "recall_task_update",
|
|
21613
|
+
description: `Update a team task: change status, reassign, rename, link a session, and/or
|
|
21614
|
+
add a comment. Pass the task id (t_\u2026) from recall_tasks.
|
|
21615
|
+
|
|
21616
|
+
WORKFLOW \u2014 do this whenever the user asks you to work on a task from the board:
|
|
21617
|
+
1. When you start, set status 'in_progress' AND pass your own current session id
|
|
21618
|
+
as linked_session_id (the session id you know from your own context; this MCP
|
|
21619
|
+
server cannot see it). The board uses that link to show whether the linked
|
|
21620
|
+
session actually shipped \u2014 files, diff stats, commits.
|
|
21621
|
+
2. When you finish, set status 'done'.`,
|
|
21622
|
+
inputSchema: {
|
|
21623
|
+
type: "object",
|
|
21624
|
+
properties: {
|
|
21625
|
+
id: { type: "string", description: "Task id (t_\u2026)" },
|
|
21626
|
+
status: { type: "string", enum: [...TASK_STATUSES] },
|
|
21627
|
+
assignee: { type: "string", description: "Reassign to this user id (sub)" },
|
|
21628
|
+
title: { type: "string" },
|
|
21629
|
+
comment: { type: "string", description: "Add a comment" },
|
|
21630
|
+
linked_session_id: { type: "string", description: "Session id to attach \u2014 pass YOUR OWN current session id when you start working on this task, so the board can check whether the work shipped. Null detaches." }
|
|
21631
|
+
},
|
|
21632
|
+
required: ["id"]
|
|
21633
|
+
}
|
|
21634
|
+
},
|
|
21635
|
+
{
|
|
21636
|
+
name: "recall_task_comment",
|
|
21637
|
+
description: `Leave a progress note on a team task \u2014 a comment visible to everyone on the
|
|
21638
|
+
board. Use it to record what you did, what is blocked, or why a status changed,
|
|
21639
|
+
without editing the task itself. Pass the task id (t_\u2026) from recall_tasks.`,
|
|
21640
|
+
inputSchema: {
|
|
21641
|
+
type: "object",
|
|
21642
|
+
properties: {
|
|
21643
|
+
task_id: { type: "string", description: "Task id (t_\u2026) from recall_tasks" },
|
|
21644
|
+
body: { type: "string", description: "The comment text" }
|
|
21645
|
+
},
|
|
21646
|
+
required: ["task_id", "body"]
|
|
21647
|
+
}
|
|
21648
|
+
},
|
|
21649
|
+
// ── Knowledge Graph Tools ──────────────────────────────────
|
|
21650
|
+
{
|
|
21651
|
+
name: "recall_kg_query",
|
|
21652
|
+
description: `Query the knowledge graph for an entity's relationships.
|
|
21472
21653
|
|
|
21473
21654
|
Returns typed facts with temporal validity. E.g. "chat-recall" \u2192 uses TypeScript, has source FTS5.
|
|
21474
21655
|
Filter by date with as_of to see what was true at a specific point in time.
|
|
21475
21656
|
Use this to VERIFY facts before asserting them.`,
|
|
21476
|
-
|
|
21477
|
-
|
|
21478
|
-
|
|
21479
|
-
|
|
21480
|
-
|
|
21481
|
-
|
|
21482
|
-
|
|
21483
|
-
|
|
21484
|
-
|
|
21485
|
-
|
|
21486
|
-
|
|
21487
|
-
|
|
21488
|
-
|
|
21657
|
+
inputSchema: {
|
|
21658
|
+
type: "object",
|
|
21659
|
+
properties: {
|
|
21660
|
+
entity: { type: "string", description: 'Entity to query (e.g., "Alice", "chat-recall")' },
|
|
21661
|
+
as_of: { type: "string", description: "Date filter (YYYY-MM-DD, optional)" },
|
|
21662
|
+
direction: { type: "string", enum: ["outgoing", "incoming", "both"], default: "both" }
|
|
21663
|
+
},
|
|
21664
|
+
required: ["entity"]
|
|
21665
|
+
}
|
|
21666
|
+
},
|
|
21667
|
+
{
|
|
21668
|
+
name: "recall_kg_add",
|
|
21669
|
+
description: `Add a fact to the knowledge graph. Subject \u2192 predicate \u2192 object with optional time window.
|
|
21489
21670
|
|
|
21490
21671
|
E.g. ("chat-recall", "uses", "LanceDB", valid_from="2024-01-15")`,
|
|
21491
|
-
|
|
21492
|
-
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21499
|
-
|
|
21500
|
-
|
|
21501
|
-
|
|
21502
|
-
|
|
21503
|
-
|
|
21504
|
-
|
|
21505
|
-
|
|
21506
|
-
|
|
21507
|
-
|
|
21508
|
-
|
|
21509
|
-
|
|
21510
|
-
|
|
21511
|
-
|
|
21512
|
-
|
|
21513
|
-
|
|
21514
|
-
|
|
21672
|
+
inputSchema: {
|
|
21673
|
+
type: "object",
|
|
21674
|
+
properties: {
|
|
21675
|
+
subject: { type: "string", description: "The entity doing/being something" },
|
|
21676
|
+
predicate: { type: "string", description: 'Relationship type (e.g., "uses", "works_on", "prefers")' },
|
|
21677
|
+
object: { type: "string", description: "The entity being connected to" },
|
|
21678
|
+
valid_from: { type: "string", description: "When this became true (YYYY-MM-DD, optional)" },
|
|
21679
|
+
source_session: { type: "string", description: "Session ID where this was learned (optional)" }
|
|
21680
|
+
},
|
|
21681
|
+
required: ["subject", "predicate", "object"]
|
|
21682
|
+
}
|
|
21683
|
+
},
|
|
21684
|
+
{
|
|
21685
|
+
name: "recall_kg_invalidate",
|
|
21686
|
+
description: `Mark a fact as no longer true. Use when things change \u2014 tools replaced, decisions reversed, people leave.`,
|
|
21687
|
+
inputSchema: {
|
|
21688
|
+
type: "object",
|
|
21689
|
+
properties: {
|
|
21690
|
+
subject: { type: "string", description: "Entity" },
|
|
21691
|
+
predicate: { type: "string", description: "Relationship" },
|
|
21692
|
+
object: { type: "string", description: "Connected entity" },
|
|
21693
|
+
ended: { type: "string", description: "When it stopped being true (YYYY-MM-DD, default: today)" }
|
|
21694
|
+
},
|
|
21695
|
+
required: ["subject", "predicate", "object"]
|
|
21696
|
+
}
|
|
21697
|
+
},
|
|
21698
|
+
{
|
|
21699
|
+
name: "recall_kg_timeline",
|
|
21700
|
+
description: `Get chronological timeline of facts. Shows the story of an entity (or everything) in order.`,
|
|
21701
|
+
inputSchema: {
|
|
21702
|
+
type: "object",
|
|
21703
|
+
properties: {
|
|
21704
|
+
entity: { type: "string", description: "Entity to get timeline for (optional)" },
|
|
21705
|
+
limit: { type: "number", default: 50 }
|
|
21515
21706
|
}
|
|
21516
|
-
}
|
|
21707
|
+
}
|
|
21708
|
+
},
|
|
21709
|
+
{
|
|
21710
|
+
name: "recall_kg_stats",
|
|
21711
|
+
description: "Knowledge graph overview: entities, triples, current vs expired facts, relationship types.",
|
|
21712
|
+
inputSchema: {
|
|
21713
|
+
type: "object",
|
|
21714
|
+
properties: {}
|
|
21715
|
+
}
|
|
21716
|
+
},
|
|
21717
|
+
// ── Diary Tools ────────────────────────────────────────────
|
|
21718
|
+
{
|
|
21719
|
+
name: "recall_diary_write",
|
|
21720
|
+
description: `Write to your agent diary. Record observations, decisions, what you worked on, what matters.
|
|
21721
|
+
|
|
21722
|
+
Each agent gets their own persistent diary across sessions. Use this at the end of sessions
|
|
21723
|
+
or when you learn something important that should persist.`,
|
|
21724
|
+
inputSchema: {
|
|
21725
|
+
type: "object",
|
|
21726
|
+
properties: {
|
|
21727
|
+
agent_name: { type: "string", description: "Your name \u2014 each agent gets their own diary" },
|
|
21728
|
+
entry: { type: "string", description: "What happened, what you learned, what matters" },
|
|
21729
|
+
topic: { type: "string", default: "general", description: "Topic tag" },
|
|
21730
|
+
session_id: { type: "string", description: "Current session ID (for linking)" },
|
|
21731
|
+
project_path: { type: "string", description: "Project path (for context)" }
|
|
21732
|
+
},
|
|
21733
|
+
required: ["agent_name", "entry"]
|
|
21734
|
+
}
|
|
21735
|
+
},
|
|
21736
|
+
{
|
|
21737
|
+
name: "recall_diary_read",
|
|
21738
|
+
description: `Read your recent diary entries. See what past versions of yourself recorded across sessions.`,
|
|
21739
|
+
inputSchema: {
|
|
21740
|
+
type: "object",
|
|
21741
|
+
properties: {
|
|
21742
|
+
agent_name: { type: "string", description: "Agent name to read diary for" },
|
|
21743
|
+
last_n: { type: "number", default: 10, description: "Number of recent entries" }
|
|
21744
|
+
},
|
|
21745
|
+
required: ["agent_name"]
|
|
21746
|
+
}
|
|
21747
|
+
},
|
|
21748
|
+
// ── Code intelligence (codeindex companion) ──
|
|
21749
|
+
// Registered ONLY when the codeindex binary is on PATH: recall_code_index
|
|
21750
|
+
// runs the analyzer locally, and the other three are its server-side
|
|
21751
|
+
// browse companions — without the binary the family is dead surface.
|
|
21752
|
+
...codeindexAvailable() ? [
|
|
21517
21753
|
{
|
|
21518
|
-
name: "
|
|
21519
|
-
description: `
|
|
21754
|
+
name: "recall_code_index",
|
|
21755
|
+
description: `Index a code repository with codeindex and sync its findings/hotspots/actions to your chat-recall server. Runs the codeindex analyzer LOCALLY (needs the repo files + git history), then ships the result. Use before recall_code_findings/actions if a repo hasn't been indexed yet.`,
|
|
21520
21756
|
inputSchema: {
|
|
21521
21757
|
type: "object",
|
|
21522
|
-
properties: {
|
|
21523
|
-
entity: { type: "string", description: "Entity to get timeline for (optional)" },
|
|
21524
|
-
limit: { type: "number", default: 50 }
|
|
21525
|
-
}
|
|
21758
|
+
properties: { path: { type: "string", description: "Repo path (default: cwd)" } }
|
|
21526
21759
|
}
|
|
21527
21760
|
},
|
|
21528
21761
|
{
|
|
21529
|
-
name: "
|
|
21530
|
-
description:
|
|
21531
|
-
inputSchema: {
|
|
21532
|
-
type: "object",
|
|
21533
|
-
properties: {}
|
|
21534
|
-
}
|
|
21762
|
+
name: "recall_code_projects",
|
|
21763
|
+
description: `List code-indexed projects on your server with health score, finding count, and label (poc/production/engineering).`,
|
|
21764
|
+
inputSchema: { type: "object", properties: {} }
|
|
21535
21765
|
},
|
|
21536
|
-
// ── Diary Tools ────────────────────────────────────────────
|
|
21537
21766
|
{
|
|
21538
|
-
name: "
|
|
21539
|
-
description: `
|
|
21540
|
-
|
|
21541
|
-
Each agent gets their own persistent diary across sessions. Use this at the end of sessions
|
|
21542
|
-
or when you learn something important that should persist.`,
|
|
21767
|
+
name: "recall_code_findings",
|
|
21768
|
+
description: `List code findings (security / hardcoded literals / copy-paste clones / reinvention / dead code / coupling / cycles). Each finding carries a concrete, ready-to-run agent prompt that references codeindex tools. Filter by project/severity/category.`,
|
|
21543
21769
|
inputSchema: {
|
|
21544
21770
|
type: "object",
|
|
21545
21771
|
properties: {
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
|
|
21549
|
-
|
|
21550
|
-
|
|
21551
|
-
|
|
21552
|
-
|
|
21772
|
+
project: { type: "string", description: "Project id (omit for all)" },
|
|
21773
|
+
severity: { type: "string", enum: ["critical", "high", "medium", "low", "info"] },
|
|
21774
|
+
category: { type: "string", description: "security|literal|clone|duplication|dead_code|coupling|cycle" },
|
|
21775
|
+
limit: { type: "number", default: 50 },
|
|
21776
|
+
view: { type: "string", enum: ["findings", "summary", "hotspots", "file-sessions"], default: "findings", description: "findings = the list; summary = counts by severity/category; hotspots = churn-ranked files; file-sessions = which sessions touched `file`" },
|
|
21777
|
+
file: { type: "string", description: "view=file-sessions only: repo-relative path" }
|
|
21778
|
+
}
|
|
21553
21779
|
}
|
|
21554
21780
|
},
|
|
21555
21781
|
{
|
|
21556
|
-
name: "
|
|
21557
|
-
description: `
|
|
21782
|
+
name: "recall_code_actions",
|
|
21783
|
+
description: `The ranked, actionable plan for a codebase \u2014 prioritised tasks synthesised from the findings, each with a ready agent prompt. This is the "what should I fix next" list. Filter by project/status.`,
|
|
21558
21784
|
inputSchema: {
|
|
21559
21785
|
type: "object",
|
|
21560
21786
|
properties: {
|
|
21561
|
-
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
required: ["agent_name"]
|
|
21565
|
-
}
|
|
21566
|
-
},
|
|
21567
|
-
// ── Code intelligence (codeindex companion) ──
|
|
21568
|
-
// Registered ONLY when the codeindex binary is on PATH: recall_code_index
|
|
21569
|
-
// runs the analyzer locally, and the other three are its server-side
|
|
21570
|
-
// browse companions — without the binary the family is dead surface.
|
|
21571
|
-
...codeindexAvailable() ? [
|
|
21572
|
-
{
|
|
21573
|
-
name: "recall_code_index",
|
|
21574
|
-
description: `Index a code repository with codeindex and sync its findings/hotspots/actions to your chat-recall server. Runs the codeindex analyzer LOCALLY (needs the repo files + git history), then ships the result. Use before recall_code_findings/actions if a repo hasn't been indexed yet.`,
|
|
21575
|
-
inputSchema: {
|
|
21576
|
-
type: "object",
|
|
21577
|
-
properties: { path: { type: "string", description: "Repo path (default: cwd)" } }
|
|
21578
|
-
}
|
|
21579
|
-
},
|
|
21580
|
-
{
|
|
21581
|
-
name: "recall_code_projects",
|
|
21582
|
-
description: `List code-indexed projects on your server with health score, finding count, and label (poc/production/engineering).`,
|
|
21583
|
-
inputSchema: { type: "object", properties: {} }
|
|
21584
|
-
},
|
|
21585
|
-
{
|
|
21586
|
-
name: "recall_code_findings",
|
|
21587
|
-
description: `List code findings (security / hardcoded literals / copy-paste clones / reinvention / dead code / coupling / cycles). Each finding carries a concrete, ready-to-run agent prompt that references codeindex tools. Filter by project/severity/category.`,
|
|
21588
|
-
inputSchema: {
|
|
21589
|
-
type: "object",
|
|
21590
|
-
properties: {
|
|
21591
|
-
project: { type: "string", description: "Project id (omit for all)" },
|
|
21592
|
-
severity: { type: "string", enum: ["critical", "high", "medium", "low", "info"] },
|
|
21593
|
-
category: { type: "string", description: "security|literal|clone|duplication|dead_code|coupling|cycle" },
|
|
21594
|
-
limit: { type: "number", default: 50 },
|
|
21595
|
-
view: { type: "string", enum: ["findings", "summary", "hotspots", "file-sessions"], default: "findings", description: "findings = the list; summary = counts by severity/category; hotspots = churn-ranked files; file-sessions = which sessions touched `file`" },
|
|
21596
|
-
file: { type: "string", description: "view=file-sessions only: repo-relative path" }
|
|
21597
|
-
}
|
|
21598
|
-
}
|
|
21599
|
-
},
|
|
21600
|
-
{
|
|
21601
|
-
name: "recall_code_actions",
|
|
21602
|
-
description: `The ranked, actionable plan for a codebase \u2014 prioritised tasks synthesised from the findings, each with a ready agent prompt. This is the "what should I fix next" list. Filter by project/status.`,
|
|
21603
|
-
inputSchema: {
|
|
21604
|
-
type: "object",
|
|
21605
|
-
properties: {
|
|
21606
|
-
project: { type: "string", description: "Project id (omit for all)" },
|
|
21607
|
-
status: { type: "string", enum: ["suggested", "queued", "done", "dismissed"] },
|
|
21608
|
-
limit: { type: "number", default: 30 }
|
|
21609
|
-
}
|
|
21787
|
+
project: { type: "string", description: "Project id (omit for all)" },
|
|
21788
|
+
status: { type: "string", enum: ["suggested", "queued", "done", "dismissed"] },
|
|
21789
|
+
limit: { type: "number", default: 30 }
|
|
21610
21790
|
}
|
|
21611
21791
|
}
|
|
21612
|
-
|
|
21613
|
-
|
|
21614
|
-
|
|
21615
|
-
|
|
21792
|
+
}
|
|
21793
|
+
] : [],
|
|
21794
|
+
{
|
|
21795
|
+
name: "recall_recommendations",
|
|
21796
|
+
description: `Actionable recommendations, two scopes on one tool:
|
|
21616
21797
|
|
|
21617
21798
|
- scope "account" (default) \u2014 from YOUR chat-recall data: leaked secrets found by
|
|
21618
21799
|
the scanner + session behaviour (unresolved/abandoned). Returns concrete
|
|
@@ -21622,21 +21803,21 @@ or when you learn something important that should persist.`,
|
|
|
21622
21803
|
a skill, set a project label, or reset a POC db. Reasons over BOTH the code
|
|
21623
21804
|
findings and how sessions in this project went (failed/abandoned, recurring
|
|
21624
21805
|
corrections). Each has rationale + evidence + an apply-action.`,
|
|
21625
|
-
|
|
21626
|
-
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21630
|
-
}
|
|
21806
|
+
inputSchema: {
|
|
21807
|
+
type: "object",
|
|
21808
|
+
properties: {
|
|
21809
|
+
scope: { type: "string", enum: ["account", "project"], default: "account", description: "account = your chat-recall data; project = one code-indexed project" },
|
|
21810
|
+
project: { type: "string", description: 'Project id (from recall_code_projects). Required when scope is "project".' }
|
|
21631
21811
|
}
|
|
21632
|
-
}
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
|
|
21638
|
-
|
|
21639
|
-
|
|
21812
|
+
}
|
|
21813
|
+
},
|
|
21814
|
+
// ── Aggregated views over the recommendation engines ──
|
|
21815
|
+
// Registered UNGATED, unlike the recall_code_* family: they read findings
|
|
21816
|
+
// the SERVER already holds, so a machine without the codeindex binary can
|
|
21817
|
+
// still see them. Both degrade to account scope when no project is indexed.
|
|
21818
|
+
{
|
|
21819
|
+
name: "recall_claude_suggestions",
|
|
21820
|
+
description: `Every finding that turns into an agent-instruction change, in one list \u2014 the
|
|
21640
21821
|
"what should I tell Claude about this?" view.
|
|
21641
21822
|
|
|
21642
21823
|
Merges the CLAUDE.md rules and skill installs from BOTH recommendation engines:
|
|
@@ -21648,18 +21829,18 @@ paste.
|
|
|
21648
21829
|
This is the read side. To apply one, use the apply rail the recommendation
|
|
21649
21830
|
already names (recall_recommendations documents it) \u2014 this tool never edits a
|
|
21650
21831
|
CLAUDE.md itself.`,
|
|
21651
|
-
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
|
|
21656
|
-
|
|
21657
|
-
}
|
|
21832
|
+
inputSchema: {
|
|
21833
|
+
type: "object",
|
|
21834
|
+
properties: {
|
|
21835
|
+
project: { type: "string", description: "Limit to one code-indexed project id (from recall_code_projects)" },
|
|
21836
|
+
include_projects: { type: "boolean", default: true, description: "Also fan out over code-indexed projects. false = account scope only." },
|
|
21837
|
+
kind: { type: "string", enum: [...INSTRUCTION_KINDS], description: "rule = a CLAUDE.md line; skill = a skill to install. Omit for both." }
|
|
21658
21838
|
}
|
|
21659
|
-
}
|
|
21660
|
-
|
|
21661
|
-
|
|
21662
|
-
|
|
21839
|
+
}
|
|
21840
|
+
},
|
|
21841
|
+
{
|
|
21842
|
+
name: "recall_improvements",
|
|
21843
|
+
description: `Every improvement worth doing, ranked highest-priority first \u2014 the "what should
|
|
21663
21844
|
I fix next, across everything" view.
|
|
21664
21845
|
|
|
21665
21846
|
Merges the ranked code actions (recall_code_actions) with the non-instruction
|
|
@@ -21670,273 +21851,322 @@ severity; both are mapped onto one scale so a single ordered list is honest.
|
|
|
21670
21851
|
Set \`create_tasks: true\` to open one task per improvement on the shared team
|
|
21671
21852
|
board (recall_tasks). It is off by default \u2014 this reads unless you ask it to
|
|
21672
21853
|
write.`,
|
|
21673
|
-
|
|
21674
|
-
|
|
21675
|
-
|
|
21676
|
-
|
|
21677
|
-
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
}
|
|
21854
|
+
inputSchema: {
|
|
21855
|
+
type: "object",
|
|
21856
|
+
properties: {
|
|
21857
|
+
project: { type: "string", description: "Limit to one code-indexed project id" },
|
|
21858
|
+
min_severity: { type: "string", enum: [...SEVERITIES], default: "low", description: "Drop anything below this severity" },
|
|
21859
|
+
limit: { type: "number", default: 30, description: "Maximum improvements to return, after ranking" },
|
|
21860
|
+
create_tasks: { type: "boolean", default: false, description: "Create one team task per returned improvement" },
|
|
21861
|
+
assignee: { type: "string", description: "create_tasks only: teammate user id (sub) to assign each task to" }
|
|
21682
21862
|
}
|
|
21683
|
-
}
|
|
21684
|
-
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
|
|
21863
|
+
}
|
|
21864
|
+
},
|
|
21865
|
+
// ── User-prompts / decision-record ──
|
|
21866
|
+
{
|
|
21867
|
+
name: "recall_user_prompts",
|
|
21868
|
+
description: `List the human-typed prompts from a session (or recent sessions). Tool results
|
|
21688
21869
|
and system banners are stripped \u2014 you get only what the user actually wrote. Useful for "what was
|
|
21689
21870
|
I asking yesterday?" or "what did I tell the agent in this session?".`,
|
|
21690
|
-
|
|
21691
|
-
|
|
21692
|
-
|
|
21693
|
-
|
|
21694
|
-
|
|
21695
|
-
|
|
21696
|
-
}
|
|
21871
|
+
inputSchema: {
|
|
21872
|
+
type: "object",
|
|
21873
|
+
properties: {
|
|
21874
|
+
session_id: { type: "string", description: "If set, only that session's prompts" },
|
|
21875
|
+
since_days: { type: "number", default: 7 },
|
|
21876
|
+
limit: { type: "number", default: 50 }
|
|
21697
21877
|
}
|
|
21698
|
-
}
|
|
21699
|
-
|
|
21700
|
-
|
|
21701
|
-
|
|
21878
|
+
}
|
|
21879
|
+
},
|
|
21880
|
+
{
|
|
21881
|
+
name: "recall_decision_record",
|
|
21882
|
+
description: `Record an explicit decision so it shows up in wake-up context. Writes a KG triple
|
|
21702
21883
|
(subject \u2192 decided \u2192 decision) plus a diary entry. Use this when you and the user agree on
|
|
21703
21884
|
something non-obvious that future sessions should remember.`,
|
|
21704
|
-
|
|
21705
|
-
|
|
21706
|
-
|
|
21707
|
-
|
|
21708
|
-
|
|
21709
|
-
|
|
21710
|
-
|
|
21711
|
-
|
|
21712
|
-
|
|
21713
|
-
|
|
21714
|
-
|
|
21715
|
-
|
|
21716
|
-
|
|
21717
|
-
|
|
21718
|
-
|
|
21719
|
-
|
|
21885
|
+
inputSchema: {
|
|
21886
|
+
type: "object",
|
|
21887
|
+
properties: {
|
|
21888
|
+
subject: { type: "string", description: "What the decision is about" },
|
|
21889
|
+
decision: { type: "string", description: "The decision itself" },
|
|
21890
|
+
reason: { type: "string", description: "Why this was decided" },
|
|
21891
|
+
importance: { type: "number", minimum: 1, maximum: 5, default: 4 },
|
|
21892
|
+
session_id: { type: "string" },
|
|
21893
|
+
agent_name: { type: "string", default: "agent" }
|
|
21894
|
+
},
|
|
21895
|
+
required: ["subject", "decision"]
|
|
21896
|
+
}
|
|
21897
|
+
},
|
|
21898
|
+
{
|
|
21899
|
+
name: "recall_analytics_summary",
|
|
21900
|
+
description: `Cross-tool spend & activity overview. Returns total sessions, total cost,
|
|
21720
21901
|
weekly delta, top tools/projects/models, and how many sessions had unknown pricing
|
|
21721
21902
|
(Gemini/Ollama/custom). Same data as the web Dashboard, available to the agent so it
|
|
21722
21903
|
can answer "how much have I spent this week" without you opening the UI.
|
|
21723
21904
|
|
|
21724
21905
|
\`view: "patterns"\` returns behavioural patterns across sessions instead of the spend rollup.`,
|
|
21725
|
-
|
|
21726
|
-
|
|
21727
|
-
|
|
21728
|
-
|
|
21729
|
-
}
|
|
21906
|
+
inputSchema: {
|
|
21907
|
+
type: "object",
|
|
21908
|
+
properties: {
|
|
21909
|
+
view: { type: "string", enum: ["summary", "patterns"], default: "summary", description: "summary = spend/activity rollup; patterns = behavioural patterns across sessions" }
|
|
21730
21910
|
}
|
|
21731
|
-
}
|
|
21732
|
-
|
|
21733
|
-
|
|
21734
|
-
|
|
21911
|
+
}
|
|
21912
|
+
},
|
|
21913
|
+
{
|
|
21914
|
+
name: "recall_wake_up",
|
|
21915
|
+
description: `Build startup context for an AI session: identity blurb + the top
|
|
21735
21916
|
classifier-flagged facts (decisions/preferences/milestones at importance >=4) +
|
|
21736
21917
|
current knowledge-graph facts. Replaces a manual context dump. Call this once at
|
|
21737
21918
|
the start of a session to "remember who you are and what's true right now".`,
|
|
21738
|
-
|
|
21739
|
-
|
|
21740
|
-
|
|
21741
|
-
|
|
21742
|
-
|
|
21743
|
-
|
|
21744
|
-
|
|
21745
|
-
}
|
|
21919
|
+
inputSchema: {
|
|
21920
|
+
type: "object",
|
|
21921
|
+
properties: {
|
|
21922
|
+
max_facts: { type: "number", default: 10 },
|
|
21923
|
+
max_kg_facts: { type: "number", default: 15 },
|
|
21924
|
+
identity: { type: "string" },
|
|
21925
|
+
project_filter: { type: "string", description: "Scope facts and KG entities to a project (substring match). Without it, facts are global." }
|
|
21746
21926
|
}
|
|
21747
|
-
}
|
|
21748
|
-
|
|
21749
|
-
|
|
21750
|
-
|
|
21927
|
+
}
|
|
21928
|
+
},
|
|
21929
|
+
{
|
|
21930
|
+
name: "recall_set",
|
|
21931
|
+
description: `Persist a small key/value pair across sessions. Use this for
|
|
21751
21932
|
state that doesn't fit the diary (narrative) or knowledge graph (entity-relationship facts) \u2014
|
|
21752
21933
|
things like "current PR url", "branch I'm working on", "user's preferred test runner".
|
|
21753
21934
|
Scope namespaces keys so per-project state doesn't collide.`,
|
|
21754
|
-
|
|
21755
|
-
|
|
21756
|
-
|
|
21757
|
-
|
|
21758
|
-
|
|
21759
|
-
|
|
21760
|
-
|
|
21761
|
-
|
|
21762
|
-
|
|
21763
|
-
|
|
21764
|
-
|
|
21765
|
-
|
|
21766
|
-
|
|
21935
|
+
inputSchema: {
|
|
21936
|
+
type: "object",
|
|
21937
|
+
properties: {
|
|
21938
|
+
key: { type: "string", description: "Key name" },
|
|
21939
|
+
value: { type: "string", description: "Value to store. JSON-encode if structured." },
|
|
21940
|
+
scope: { type: "string", default: "default", description: "Namespace" }
|
|
21941
|
+
},
|
|
21942
|
+
required: ["key", "value"]
|
|
21943
|
+
}
|
|
21944
|
+
},
|
|
21945
|
+
{
|
|
21946
|
+
name: "recall_get",
|
|
21947
|
+
description: `Read a key/value pair previously written with recall_set \u2014 or, when \`key\` is
|
|
21767
21948
|
omitted, LIST the recorded keys (in one scope, or across all scopes when \`scope\` is
|
|
21768
21949
|
also omitted). Use the list mode to discover what state has been recorded without
|
|
21769
21950
|
remembering specific keys.`,
|
|
21770
|
-
|
|
21771
|
-
|
|
21772
|
-
|
|
21773
|
-
|
|
21774
|
-
|
|
21775
|
-
|
|
21776
|
-
}
|
|
21951
|
+
inputSchema: {
|
|
21952
|
+
type: "object",
|
|
21953
|
+
properties: {
|
|
21954
|
+
key: { type: "string", description: "Key name. Omit to list keys instead." },
|
|
21955
|
+
scope: { type: "string", description: 'Namespace (default "default" when reading; omit to list across all scopes)' },
|
|
21956
|
+
limit: { type: "number", default: 50, description: "Max entries in list mode" }
|
|
21777
21957
|
}
|
|
21778
|
-
}
|
|
21779
|
-
|
|
21780
|
-
|
|
21781
|
-
|
|
21782
|
-
|
|
21958
|
+
}
|
|
21959
|
+
},
|
|
21960
|
+
// ── Security / Secret Findings Tools ─────────────────────────
|
|
21961
|
+
{
|
|
21962
|
+
name: "recall_security_summary",
|
|
21963
|
+
description: `Get a security overview from the synced chat-recall server.
|
|
21783
21964
|
|
|
21784
21965
|
Returns the action-required list of distinct leaked secrets (grouped by redacted
|
|
21785
21966
|
preview), plus per-detector totals and top rules. Use this when the user asks
|
|
21786
21967
|
"do we have any leaked secrets?" or "security findings" or "what should I rotate".
|
|
21787
21968
|
|
|
21788
21969
|
Call this first; then call recall_security_session for specific sessions.`,
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
|
|
21796
|
-
|
|
21797
|
-
}
|
|
21970
|
+
inputSchema: {
|
|
21971
|
+
type: "object",
|
|
21972
|
+
properties: {
|
|
21973
|
+
include_dismissed: { type: "boolean", default: false, description: "Show previously dismissed findings" },
|
|
21974
|
+
top_k: { type: "number", default: 20, description: "Max distinct secrets to list" },
|
|
21975
|
+
group_by: { type: "string", enum: ["detector", "rule", "project", "trend", "sessions"], default: "detector", description: "detector = action-required view; rule/project = grouped counts; trend = daily counts; sessions = one row per session with findings" },
|
|
21976
|
+
days: { type: "number", default: 30, description: "group_by=trend only: window in days (1-365)" },
|
|
21977
|
+
min_detectors: { type: "number", description: "group_by=sessions only: require N detectors agreeing" }
|
|
21798
21978
|
}
|
|
21799
|
-
}
|
|
21800
|
-
|
|
21801
|
-
|
|
21802
|
-
|
|
21979
|
+
}
|
|
21980
|
+
},
|
|
21981
|
+
{
|
|
21982
|
+
name: "recall_security_session",
|
|
21983
|
+
description: `Get secret findings for a specific session.
|
|
21803
21984
|
|
|
21804
21985
|
Use after recall_search or recall_security_summary to show exactly which lines
|
|
21805
21986
|
in a session matched which detector.`,
|
|
21806
|
-
|
|
21807
|
-
|
|
21808
|
-
|
|
21809
|
-
|
|
21810
|
-
|
|
21811
|
-
|
|
21812
|
-
|
|
21813
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21987
|
+
inputSchema: {
|
|
21988
|
+
type: "object",
|
|
21989
|
+
properties: {
|
|
21990
|
+
session_id: { type: "string", description: "Session ID from search results" }
|
|
21991
|
+
},
|
|
21992
|
+
required: ["session_id"]
|
|
21993
|
+
}
|
|
21994
|
+
},
|
|
21995
|
+
{
|
|
21996
|
+
name: "recall_security_dismiss",
|
|
21997
|
+
description: `Mark a secret finding as rotated, false_positive, or dismissed.
|
|
21817
21998
|
|
|
21818
21999
|
Use when the user confirms a key was rotated or that the match is not a real
|
|
21819
22000
|
secret. The dismissal syncs across devices.`,
|
|
21820
|
-
|
|
21821
|
-
|
|
21822
|
-
|
|
21823
|
-
|
|
21824
|
-
|
|
21825
|
-
|
|
21826
|
-
|
|
21827
|
-
|
|
21828
|
-
|
|
21829
|
-
|
|
21830
|
-
|
|
21831
|
-
|
|
21832
|
-
|
|
22001
|
+
inputSchema: {
|
|
22002
|
+
type: "object",
|
|
22003
|
+
properties: {
|
|
22004
|
+
preview: { type: "string", description: "Masked secret preview from the security dashboard" },
|
|
22005
|
+
status: { type: "string", enum: ["rotated", "false_positive", "dismissed", "undismissed"], description: "Resolution status, or `undismissed` to put the finding back on the action-required list" },
|
|
22006
|
+
reason: { type: "string", description: "Optional note" }
|
|
22007
|
+
},
|
|
22008
|
+
required: ["preview", "status"]
|
|
22009
|
+
}
|
|
22010
|
+
},
|
|
22011
|
+
{
|
|
22012
|
+
name: "recall_security_rules",
|
|
22013
|
+
description: `List tenant custom secret-detection rules, or test a regex in the sandbox.
|
|
21833
22014
|
|
|
21834
22015
|
Tenant rules are configured in the chat-recall dashboard; this tool exposes them
|
|
21835
22016
|
to the agent and lets you test new regexes without persisting them.`,
|
|
21836
|
-
|
|
21837
|
-
|
|
21838
|
-
|
|
21839
|
-
|
|
21840
|
-
|
|
21841
|
-
|
|
21842
|
-
|
|
21843
|
-
}
|
|
22017
|
+
inputSchema: {
|
|
22018
|
+
type: "object",
|
|
22019
|
+
properties: {
|
|
22020
|
+
action: { type: "string", enum: ["list", "test"], default: "list", description: "list = existing rules; test = regex sandbox" },
|
|
22021
|
+
name: { type: "string", description: "For test: rule name" },
|
|
22022
|
+
regex: { type: "string", description: "For test: regex to evaluate" },
|
|
22023
|
+
sample: { type: "string", description: "For test: text to match against" }
|
|
21844
22024
|
}
|
|
21845
|
-
}
|
|
21846
|
-
|
|
21847
|
-
|
|
21848
|
-
|
|
22025
|
+
}
|
|
22026
|
+
},
|
|
22027
|
+
{
|
|
22028
|
+
name: "recall_subagent_search",
|
|
22029
|
+
description: `Search inside SUBAGENT transcripts \u2014 the explore/compact/aside sub-tasks that run within a session and whose work never appears in the main conversation.
|
|
21849
22030
|
|
|
21850
22031
|
Use when a session's own turns don't contain what you remember: the finding may have come from a subagent. Indexed server-side, so it works across devices.`,
|
|
21851
|
-
|
|
21852
|
-
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
|
|
21856
|
-
|
|
21857
|
-
|
|
21858
|
-
|
|
21859
|
-
|
|
21860
|
-
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
|
|
21864
|
-
|
|
22032
|
+
inputSchema: {
|
|
22033
|
+
type: "object",
|
|
22034
|
+
properties: {
|
|
22035
|
+
query: { type: "string", description: "Text to find inside subagent transcripts" },
|
|
22036
|
+
session_id: { type: "string", description: "Restrict to one session" },
|
|
22037
|
+
kind: { type: "string", description: "Restrict to one subagent kind" },
|
|
22038
|
+
limit: { type: "number", default: 20 }
|
|
22039
|
+
},
|
|
22040
|
+
required: ["query"]
|
|
22041
|
+
}
|
|
22042
|
+
},
|
|
22043
|
+
{
|
|
22044
|
+
name: "recall_redundant_files",
|
|
22045
|
+
description: `Before creating a file, check whether you have written one like it before. Scores the filename against every file touched in your synced history.
|
|
21865
22046
|
|
|
21866
22047
|
Answers "have I built this already?" \u2014 the reinvention check.`,
|
|
21867
|
-
|
|
21868
|
-
|
|
21869
|
-
|
|
21870
|
-
|
|
21871
|
-
|
|
21872
|
-
|
|
21873
|
-
|
|
21874
|
-
|
|
21875
|
-
|
|
21876
|
-
|
|
21877
|
-
|
|
21878
|
-
|
|
21879
|
-
|
|
22048
|
+
inputSchema: {
|
|
22049
|
+
type: "object",
|
|
22050
|
+
properties: {
|
|
22051
|
+
filename: { type: "string", description: "Filename you are about to create" },
|
|
22052
|
+
project: { type: "string", description: "Restrict to one project" },
|
|
22053
|
+
limit: { type: "number", default: 20 }
|
|
22054
|
+
},
|
|
22055
|
+
required: ["filename"]
|
|
22056
|
+
}
|
|
22057
|
+
},
|
|
22058
|
+
{
|
|
22059
|
+
name: "recall_heal_audit",
|
|
22060
|
+
description: `Report how many of your sessions are DAMAGED \u2014 the rendered conversation is thinner than the shrink-protected raw archive, which happens when an upstream tool truncates a transcript in place (a resume/compaction rewrite, or a script mirroring a shorter file over a longer one).
|
|
21880
22061
|
|
|
21881
22062
|
This is the authoritative "0 remaining" check. Read-only by default; apply=true heals, and healing only ever makes a conversation FULLER.`,
|
|
21882
|
-
|
|
21883
|
-
|
|
21884
|
-
|
|
21885
|
-
|
|
21886
|
-
|
|
21887
|
-
}
|
|
22063
|
+
inputSchema: {
|
|
22064
|
+
type: "object",
|
|
22065
|
+
properties: {
|
|
22066
|
+
since_hours: { type: "number", description: "Bound the scan to the last N hours" },
|
|
22067
|
+
apply: { type: "boolean", default: false, description: "false = audit only; true = heal now" }
|
|
21888
22068
|
}
|
|
21889
|
-
}
|
|
21890
|
-
|
|
21891
|
-
|
|
21892
|
-
|
|
22069
|
+
}
|
|
22070
|
+
},
|
|
22071
|
+
{
|
|
22072
|
+
name: "recall_memory_item",
|
|
22073
|
+
description: `Fetch ONE memory item, its full text, or its links \u2014 or browse a whole source type.
|
|
21893
22074
|
|
|
21894
22075
|
Complements recall_memory_search: search finds candidates, this reads the specific item. mode=browse lists a type (e.g. every skill, every plan) without a query.`,
|
|
21895
|
-
|
|
21896
|
-
|
|
21897
|
-
|
|
21898
|
-
|
|
21899
|
-
|
|
21900
|
-
|
|
21901
|
-
|
|
21902
|
-
|
|
21903
|
-
|
|
21904
|
-
}
|
|
21905
|
-
},
|
|
21906
|
-
{
|
|
21907
|
-
name: "recall_regenerate_summary",
|
|
21908
|
-
description: "Force a fresh AI summary for one session \u2014 use when its stored summary is missing, stale, or plainly wrong.",
|
|
21909
|
-
inputSchema: {
|
|
21910
|
-
type: "object",
|
|
21911
|
-
properties: { session_id: { type: "string" } },
|
|
21912
|
-
required: ["session_id"]
|
|
21913
|
-
}
|
|
21914
|
-
},
|
|
21915
|
-
{
|
|
21916
|
-
name: "recall_outcome_summary",
|
|
21917
|
-
description: 'Aggregate session outcomes (shipped / interrupted / abandoned / in_progress) over the last N days \u2014 "how much of my work actually landed?".',
|
|
21918
|
-
inputSchema: {
|
|
21919
|
-
type: "object",
|
|
21920
|
-
properties: { days: { type: "number", default: 7, description: "1-90" } }
|
|
21921
|
-
}
|
|
21922
|
-
},
|
|
21923
|
-
{
|
|
21924
|
-
name: "recall_shares",
|
|
21925
|
-
description: "Which projects are shared into your team. scope=mine for your own shares, scope=all for every share visible to you. Private by default \u2014 nothing is visible to teammates until shared.",
|
|
21926
|
-
inputSchema: {
|
|
21927
|
-
type: "object",
|
|
21928
|
-
properties: { scope: { type: "string", enum: ["mine", "all"], default: "mine" } }
|
|
21929
|
-
}
|
|
21930
|
-
},
|
|
21931
|
-
{
|
|
21932
|
-
name: "recall_reclassify",
|
|
21933
|
-
description: "Re-run the memory classifier over already-indexed chunks so classifier improvements reach old data. Idempotent \u2014 only rewrites tags that actually changed.",
|
|
21934
|
-
inputSchema: { type: "object", properties: {} }
|
|
22076
|
+
inputSchema: {
|
|
22077
|
+
type: "object",
|
|
22078
|
+
properties: {
|
|
22079
|
+
source_type: { type: "string", enum: ["session", "plan", "task", "claude_md", "paste", "history", "diary"] },
|
|
22080
|
+
id: { type: "string", description: "Item id. Omit with mode=browse." },
|
|
22081
|
+
mode: { type: "string", enum: ["item", "content", "links", "browse"], default: "item", description: "item = metadata, content = full text, links = related items, browse = list the type" },
|
|
22082
|
+
limit: { type: "number", default: 50, description: "browse mode only" }
|
|
22083
|
+
},
|
|
22084
|
+
required: ["source_type"]
|
|
21935
22085
|
}
|
|
21936
|
-
|
|
21937
|
-
|
|
22086
|
+
},
|
|
22087
|
+
{
|
|
22088
|
+
name: "recall_regenerate_summary",
|
|
22089
|
+
description: "Force a fresh AI summary for one session \u2014 use when its stored summary is missing, stale, or plainly wrong.",
|
|
22090
|
+
inputSchema: {
|
|
22091
|
+
type: "object",
|
|
22092
|
+
properties: { session_id: { type: "string" } },
|
|
22093
|
+
required: ["session_id"]
|
|
22094
|
+
}
|
|
22095
|
+
},
|
|
22096
|
+
{
|
|
22097
|
+
name: "recall_outcome_summary",
|
|
22098
|
+
description: 'Aggregate session outcomes (shipped / interrupted / abandoned / in_progress) over the last N days \u2014 "how much of my work actually landed?".',
|
|
22099
|
+
inputSchema: {
|
|
22100
|
+
type: "object",
|
|
22101
|
+
properties: { days: { type: "number", default: 7, description: "1-90" } }
|
|
22102
|
+
}
|
|
22103
|
+
},
|
|
22104
|
+
{
|
|
22105
|
+
name: "recall_shares",
|
|
22106
|
+
description: "Which projects are shared into your team. scope=mine for your own shares, scope=all for every share visible to you. Private by default \u2014 nothing is visible to teammates until shared.",
|
|
22107
|
+
inputSchema: {
|
|
22108
|
+
type: "object",
|
|
22109
|
+
properties: { scope: { type: "string", enum: ["mine", "all"], default: "mine" } }
|
|
22110
|
+
}
|
|
22111
|
+
},
|
|
22112
|
+
{
|
|
22113
|
+
name: "recall_reclassify",
|
|
22114
|
+
description: "Re-run the memory classifier over already-indexed chunks so classifier improvements reach old data. Idempotent \u2014 only rewrites tags that actually changed.",
|
|
22115
|
+
inputSchema: { type: "object", properties: {} }
|
|
22116
|
+
}
|
|
22117
|
+
];
|
|
22118
|
+
if (toolProfile() === "full") return { tools: all };
|
|
22119
|
+
const lean = all.filter((t) => LEAN_TOOLS.has(t.name));
|
|
22120
|
+
const hidden = all.length - lean.length;
|
|
22121
|
+
if (hidden > 0) {
|
|
22122
|
+
lean.push({
|
|
22123
|
+
name: "recall_help",
|
|
22124
|
+
description: `List the ${hidden} additional chat-recall tools that are not registered in this profile (analytics, knowledge-graph navigation, code intelligence, sharing, security triage, maintenance). They all still WORK if called by name. Set CHAT_RECALL_MCP_PROFILE=full to register every tool up front.`,
|
|
22125
|
+
inputSchema: { type: "object", properties: {} }
|
|
22126
|
+
});
|
|
22127
|
+
}
|
|
22128
|
+
return { tools: lean };
|
|
21938
22129
|
});
|
|
22130
|
+
var syncStateCache = null;
|
|
22131
|
+
var SYNC_STATE_TTL_MS = 5 * 60 * 1e3;
|
|
22132
|
+
async function syncState() {
|
|
22133
|
+
if (syncStateCache && Date.now() - syncStateCache.at < SYNC_STATE_TTL_MS) return syncStateCache.state;
|
|
22134
|
+
let state = null;
|
|
22135
|
+
try {
|
|
22136
|
+
const cred = remoteCredentials();
|
|
22137
|
+
if (cred) {
|
|
22138
|
+
const res = await fetch(cred.base + "/api/billing", {
|
|
22139
|
+
headers: { authorization: `Bearer ${cred.token}` }
|
|
22140
|
+
});
|
|
22141
|
+
if (res.ok) {
|
|
22142
|
+
const b = await res.json();
|
|
22143
|
+
if (typeof b.entitled === "boolean") {
|
|
22144
|
+
state = {
|
|
22145
|
+
entitled: b.entitled,
|
|
22146
|
+
status: typeof b.status === "string" ? b.status : "unknown",
|
|
22147
|
+
periodEnd: typeof b.currentPeriodEnd === "number" ? b.currentPeriodEnd : null
|
|
22148
|
+
};
|
|
22149
|
+
}
|
|
22150
|
+
}
|
|
22151
|
+
}
|
|
22152
|
+
} catch {
|
|
22153
|
+
}
|
|
22154
|
+
syncStateCache = { at: Date.now(), state };
|
|
22155
|
+
return state;
|
|
22156
|
+
}
|
|
21939
22157
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
22158
|
+
const result = await dispatchTool(request);
|
|
22159
|
+
try {
|
|
22160
|
+
const banner = stalenessBanner(await syncState());
|
|
22161
|
+
if (!banner) return result;
|
|
22162
|
+
const content = result.content;
|
|
22163
|
+
if (!Array.isArray(content) || !content.length) return result;
|
|
22164
|
+
return { ...result, content: [{ type: "text", text: banner }, ...content] };
|
|
22165
|
+
} catch {
|
|
22166
|
+
return result;
|
|
22167
|
+
}
|
|
22168
|
+
});
|
|
22169
|
+
async function dispatchTool(request) {
|
|
21940
22170
|
const { name, arguments: args } = request.params;
|
|
21941
22171
|
try {
|
|
21942
22172
|
if (/^recall_code_(index|projects|findings|actions)$/.test(name) && !codeindexAvailable()) {
|
|
@@ -22809,6 +23039,7 @@ ${lines.join("\n")}` }] };
|
|
|
22809
23039
|
if (params.status) patch.status = params.status;
|
|
22810
23040
|
if (params.assignee !== void 0) patch.assigneeSub = params.assignee || null;
|
|
22811
23041
|
if (params.title) patch.title = params.title;
|
|
23042
|
+
if (params.linked_session_id !== void 0) patch.linkedSessionId = params.linked_session_id;
|
|
22812
23043
|
let did = false;
|
|
22813
23044
|
if (Object.keys(patch).length > 0) {
|
|
22814
23045
|
await remotePatch(`/api/tasks/${encodeURIComponent(params.id)}`, patch);
|
|
@@ -22818,9 +23049,18 @@ ${lines.join("\n")}` }] };
|
|
|
22818
23049
|
await remotePost(`/api/tasks/${encodeURIComponent(params.id)}/comments`, { body: params.comment });
|
|
22819
23050
|
did = true;
|
|
22820
23051
|
}
|
|
22821
|
-
if (!did) return { content: [{ type: "text", text: "Nothing to update \u2014 pass status, assignee, title, and/or comment." }] };
|
|
23052
|
+
if (!did) return { content: [{ type: "text", text: "Nothing to update \u2014 pass status, assignee, title, linked_session_id, and/or comment." }] };
|
|
22822
23053
|
return { content: [{ type: "text", text: `Updated task ${params.id}.` }] };
|
|
22823
23054
|
}
|
|
23055
|
+
case "recall_task_comment": {
|
|
23056
|
+
const params = RecallTaskCommentSchema.parse(args);
|
|
23057
|
+
requireRemote();
|
|
23058
|
+
const { comment } = await remotePost(
|
|
23059
|
+
`/api/tasks/${encodeURIComponent(params.task_id)}/comments`,
|
|
23060
|
+
{ body: params.body }
|
|
23061
|
+
);
|
|
23062
|
+
return { content: [{ type: "text", text: `Commented on task ${comment.taskId} (comment ${comment.id}).` }] };
|
|
23063
|
+
}
|
|
22824
23064
|
// ── Knowledge Graph Handlers ─────────────────────────────────
|
|
22825
23065
|
case "recall_kg_query": {
|
|
22826
23066
|
const params = RecallKGQuerySchema.parse(args);
|
|
@@ -23524,6 +23764,12 @@ ${row.value}`
|
|
|
23524
23764
|
max_facts: params.max_facts,
|
|
23525
23765
|
max_kg_facts: params.max_kg_facts
|
|
23526
23766
|
});
|
|
23767
|
+
const ot = wake.openTasks;
|
|
23768
|
+
if (ot && ot.total > 0) {
|
|
23769
|
+
lines.push("## Task board");
|
|
23770
|
+
lines.push(` ${ot.total} open task(s)${ot.auto ? ` \u2014 ${ot.auto} auto-filed from code findings` : ""}. List them with recall_tasks; when you start one, set it in_progress and pass your session id as linked_session_id.`);
|
|
23771
|
+
lines.push("");
|
|
23772
|
+
}
|
|
23527
23773
|
if (wake.highFacts.length > 0) {
|
|
23528
23774
|
lines.push("## High-importance facts");
|
|
23529
23775
|
for (const c of wake.highFacts) lines.push(` [${c.type}] ${c.text}`);
|
|
@@ -23807,6 +24053,29 @@ ${JSON.stringify(r, null, 2)}
|
|
|
23807
24053
|
if (r.error) return { content: [{ type: "text", text: `Reclassify unavailable: ${r.error}` }] };
|
|
23808
24054
|
return { content: [{ type: "text", text: `${r.message ?? "Reclassify complete"} \u2014 scanned ${r.scanned ?? 0}, updated ${r.updated ?? 0}.` }] };
|
|
23809
24055
|
}
|
|
24056
|
+
case "recall_help": {
|
|
24057
|
+
const lines = [
|
|
24058
|
+
"# chat-recall tools not registered in this profile",
|
|
24059
|
+
"",
|
|
24060
|
+
"They all still work \u2014 call them by name. To register every tool up front,",
|
|
24061
|
+
"set CHAT_RECALL_MCP_PROFILE=full and restart the MCP server.",
|
|
24062
|
+
""
|
|
24063
|
+
];
|
|
24064
|
+
const groups = [
|
|
24065
|
+
["Aggregate views", ["recall_weekly_digest", "recall_analytics_summary", "recall_team_activity", "recall_outcome_summary"]],
|
|
24066
|
+
["Task board", ["recall_task_comment"]],
|
|
24067
|
+
["Knowledge graph", ["recall_kg_timeline", "recall_kg_stats", "recall_kg_invalidate"]],
|
|
24068
|
+
["Session detail", ["recall_markers", "recall_subagent_search", "recall_memory_item", "recall_rename_session", "recall_regenerate_summary"]],
|
|
24069
|
+
["Code intelligence", ["recall_code_index", "recall_code_projects", "recall_code_findings", "recall_code_actions"]],
|
|
24070
|
+
["Recommendations", ["recall_recommendations", "recall_improvements", "recall_claude_suggestions", "recall_redundant_files"]],
|
|
24071
|
+
["Security triage", ["recall_security_session", "recall_security_dismiss", "recall_security_rules"]],
|
|
24072
|
+
["State + maintenance", ["recall_set", "recall_get", "recall_shares", "recall_reclassify", "recall_heal_audit"]]
|
|
24073
|
+
];
|
|
24074
|
+
for (const [label, names] of groups) {
|
|
24075
|
+
lines.push(`## ${label}`, names.map((n) => `- ${n}`).join("\n"), "");
|
|
24076
|
+
}
|
|
24077
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
24078
|
+
}
|
|
23810
24079
|
default:
|
|
23811
24080
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }] };
|
|
23812
24081
|
}
|
|
@@ -23818,7 +24087,7 @@ ${JSON.stringify(r, null, 2)}
|
|
|
23818
24087
|
reportClientEvent("tool_error", { tool: name, message: msg });
|
|
23819
24088
|
return { content: [{ type: "text", text: `Error: ${msg}` }] };
|
|
23820
24089
|
}
|
|
23821
|
-
}
|
|
24090
|
+
}
|
|
23822
24091
|
function runIndexChild(force) {
|
|
23823
24092
|
return new Promise((resolve2) => {
|
|
23824
24093
|
let cliPath;
|