chat-recall 0.5.26 → 0.5.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/cli.js +192 -113
- package/dist/cli.js.map +1 -1
- package/dist/init-progress.d.ts +52 -0
- package/dist/init-progress.d.ts.map +1 -0
- package/dist/init-progress.js +98 -0
- package/dist/init-progress.js.map +1 -0
- package/dist/init-report.d.ts +38 -0
- package/dist/init-report.d.ts.map +1 -0
- package/dist/init-report.js +53 -0
- package/dist/init-report.js.map +1 -0
- package/dist/mcp.js +152 -12
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +8 -2
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +6 -6
- package/package.json +1 -1
- package/skills/chat-recall/SKILL.md +2 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/chat-recall)
|
|
5
5
|
[](https://www.npmjs.com/package/chat-recall)
|
|
6
6
|
[](https://registry.modelcontextprotocol.io/v0/servers?search=chat-recall)
|
|
7
|
-
[](https://smithery.ai/
|
|
7
|
+
[](https://smithery.ai/servers/munhq/chat-recall)
|
|
8
8
|
[](https://glama.ai/mcp/servers/munhq/chat-recall)
|
|
9
9
|
|
|
10
10
|
[](cursor://anysphere.cursor-deeplink/mcp/install?name=chat-recall&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIi1wIiwiY2hhdC1yZWNhbGwiLCJjaGF0LXJlY2FsbC1tY3AiXX0=)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
> One memory across every AI coding tool you use. Claude Code, Gemini CLI, Codex, OpenCode, Antigravity and Cursor share a single searchable history — and the agent can search it itself.
|
|
16
16
|
|
|
17
|
-
Your coding agents each keep their own transcripts, in their own format, in their own directory, and none of them can read another's. `chat-recall` indexes all of them into one place, redacts secrets on the way, and exposes the result to your agent through **
|
|
17
|
+
Your coding agents each keep their own transcripts, in their own format, in their own directory, and none of them can read another's. `chat-recall` indexes all of them into one place, redacts secrets on the way, and exposes the result to your agent through **61 MCP tools** so it can recall its own past work instead of you re-explaining it.
|
|
18
18
|
|
|
19
19
|
That cross-tool part is the point. A single tool's built-in history stops at its own boundary; this does not.
|
|
20
20
|
|
|
@@ -95,7 +95,7 @@ Exclusions live on the machine that holds the data, so the CLI owns them; they a
|
|
|
95
95
|
## Four things it actually does
|
|
96
96
|
|
|
97
97
|
1. **Cross-tool unified memory.** One index, one search, one UI over Claude Code (`~/.claude/projects/`), Gemini CLI (`~/.gemini/tmp/`), Codex (`~/.codex/`), OpenCode (`~/.local/share/opencode/`), Antigravity and Cursor (`~/.cursor/` for the CLI, `~/.config/Cursor/` for the IDE). Sessions, plans, tasks, CLAUDE.md files, paste cache, shell history and agent diaries all share one pluggable `MemorySource` interface.
|
|
98
|
-
2. **The agent recalls itself.**
|
|
98
|
+
2. **The agent recalls itself.** 61 MCP tools, so Claude Code can `recall_smart_resume`, `recall_search` (with `like_session` to find similar work), `recall_edits_timeline`, `recall_subagent_search` and `recall_redundant_files` rather than asking you what happened last time. It writes back too, via `recall_decision_record`, `recall_kg_add` and `recall_set`.
|
|
99
99
|
3. **Warns before you redo work.** A `UserPromptSubmit` hook searches for similar past sessions on every prompt and injects a short "you have done this before, in session X" note into the agent's context.
|
|
100
100
|
4. **Temporal knowledge graph.** Decisions and tool mentions become entity-relationship triples with `valid_from`/`valid_to` windows, so you can ask what was decided in March and whether it still holds.
|
|
101
101
|
|
|
@@ -218,7 +218,7 @@ codeindex is open source (MIT) at [github.com/munhq/codeindex](https://github.co
|
|
|
218
218
|
| **Paste** | `~/.claude/paste-cache/*.txt` | Large pasted blobs |
|
|
219
219
|
| **Diary** | `~/.chat-recall/index/diary/<agent>/*.json` | What the agent told its future self via `recall_diary_write` |
|
|
220
220
|
|
|
221
|
-
## MCP tools (
|
|
221
|
+
## MCP tools (61, including 4 code-intelligence tools that register when the companion binary is installed)
|
|
222
222
|
|
|
223
223
|
**Search & retrieve** — `recall_search`, `recall_memory_search`, `recall_recent`, `recall_show`, `recall_context`, `recall_summary`, `recall_smart_resume`, `recall_project_context`, `recall_weekly_digest`, `recall_analytics_summary`, `recall_wake_up`.
|
|
224
224
|
|
package/dist/cli.js
CHANGED
|
@@ -7134,13 +7134,13 @@ async function parseCodexSubagents(sessionPath) {
|
|
|
7134
7134
|
if (meta?.type !== "session_meta")
|
|
7135
7135
|
continue;
|
|
7136
7136
|
const payload = meta.payload || {};
|
|
7137
|
-
const
|
|
7138
|
-
if (!
|
|
7137
|
+
const spawn4 = payload.source?.subagent?.thread_spawn;
|
|
7138
|
+
if (!spawn4)
|
|
7139
7139
|
continue;
|
|
7140
|
-
if (
|
|
7140
|
+
if (spawn4.parent_thread_id !== parentId)
|
|
7141
7141
|
continue;
|
|
7142
7142
|
const id = fileName.replace(/\.jsonl$/i, "");
|
|
7143
|
-
const role = String(
|
|
7143
|
+
const role = String(spawn4.agent_role || payload.agent_role || "").toLowerCase();
|
|
7144
7144
|
const kind = role.includes("compact") ? "compact" : role.includes("aside") ? "aside" : role.includes("worker") || role.includes("explore") ? "explore" : "other";
|
|
7145
7145
|
let messages = [];
|
|
7146
7146
|
try {
|
|
@@ -7152,8 +7152,8 @@ async function parseCodexSubagents(sessionPath) {
|
|
|
7152
7152
|
subagents.push({
|
|
7153
7153
|
id,
|
|
7154
7154
|
kind,
|
|
7155
|
-
agentType:
|
|
7156
|
-
description:
|
|
7155
|
+
agentType: spawn4.agent_role || payload.agent_role,
|
|
7156
|
+
description: spawn4.agent_nickname || payload.agent_nickname,
|
|
7157
7157
|
filePath,
|
|
7158
7158
|
messageCount: messages.length,
|
|
7159
7159
|
toolUseCount,
|
|
@@ -9781,8 +9781,8 @@ var init_codex2 = __esm({
|
|
|
9781
9781
|
} catch {
|
|
9782
9782
|
continue;
|
|
9783
9783
|
}
|
|
9784
|
-
const
|
|
9785
|
-
if (!
|
|
9784
|
+
const spawn4 = meta?.payload?.source?.subagent?.thread_spawn;
|
|
9785
|
+
if (!spawn4 || spawn4.parent_thread_id !== parentUuid)
|
|
9786
9786
|
continue;
|
|
9787
9787
|
events.push(...this.parseRollout(path));
|
|
9788
9788
|
}
|
|
@@ -9975,10 +9975,10 @@ var init_codex2 = __esm({
|
|
|
9975
9975
|
const meta = JSON.parse(first);
|
|
9976
9976
|
const payload = meta?.payload || {};
|
|
9977
9977
|
projectPath = payload.cwd || "";
|
|
9978
|
-
const
|
|
9979
|
-
if (
|
|
9978
|
+
const spawn4 = payload.source?.subagent?.thread_spawn;
|
|
9979
|
+
if (spawn4 || payload.agent_role || payload.agent_nickname) {
|
|
9980
9980
|
isSubagent = true;
|
|
9981
|
-
parentId =
|
|
9981
|
+
parentId = spawn4?.parent_thread_id || null;
|
|
9982
9982
|
}
|
|
9983
9983
|
}
|
|
9984
9984
|
} catch {
|
|
@@ -19418,7 +19418,7 @@ function pruneLedgerTargets(configuredServers) {
|
|
|
19418
19418
|
return 0;
|
|
19419
19419
|
}
|
|
19420
19420
|
const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
|
|
19421
|
-
console.error(`[sync]
|
|
19421
|
+
console.error(`[sync] tidied local bookkeeping: ${rows} already-synced marker(s) for ${names.length} server(s) you no longer sync to (${names.join(", ")}) moved to ${side}. Nothing was uploaded there; the file is kept so logging back in re-ships nothing.`);
|
|
19422
19422
|
persistNow(data);
|
|
19423
19423
|
return names.length;
|
|
19424
19424
|
}
|
|
@@ -19730,7 +19730,7 @@ var init_http = __esm({
|
|
|
19730
19730
|
CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19731
19731
|
} catch {
|
|
19732
19732
|
try {
|
|
19733
|
-
if (true) CLI_VERSION = "0.5.
|
|
19733
|
+
if (true) CLI_VERSION = "0.5.28";
|
|
19734
19734
|
} catch {
|
|
19735
19735
|
}
|
|
19736
19736
|
}
|
|
@@ -20242,7 +20242,7 @@ var init_telemetry = __esm({
|
|
|
20242
20242
|
init_sync_client();
|
|
20243
20243
|
cliVersion2 = () => {
|
|
20244
20244
|
try {
|
|
20245
|
-
return true ? "0.5.
|
|
20245
|
+
return true ? "0.5.28" : "dev";
|
|
20246
20246
|
} catch {
|
|
20247
20247
|
return "dev";
|
|
20248
20248
|
}
|
|
@@ -20253,6 +20253,18 @@ var init_telemetry = __esm({
|
|
|
20253
20253
|
});
|
|
20254
20254
|
|
|
20255
20255
|
// ../engine/dist/core/collector-health.js
|
|
20256
|
+
var collector_health_exports = {};
|
|
20257
|
+
__export(collector_health_exports, {
|
|
20258
|
+
CRASHLOOP_RESTARTS: () => CRASHLOOP_RESTARTS,
|
|
20259
|
+
STALE_AFTER_MS: () => STALE_AFTER_MS,
|
|
20260
|
+
collectorHealthPath: () => collectorHealthPath,
|
|
20261
|
+
judgeHealth: () => judgeHealth,
|
|
20262
|
+
progressLine: () => progressLine,
|
|
20263
|
+
readCollectorHealth: () => readCollectorHealth,
|
|
20264
|
+
reportWalkProgress: () => reportWalkProgress,
|
|
20265
|
+
updateCollectorHealth: () => updateCollectorHealth,
|
|
20266
|
+
writeCollectorHealth: () => writeCollectorHealth
|
|
20267
|
+
});
|
|
20256
20268
|
import { readFileSync as readFileSync34, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8 } from "node:fs";
|
|
20257
20269
|
import { join as join42, dirname as dirname17 } from "node:path";
|
|
20258
20270
|
function progressLine(h) {
|
|
@@ -22238,7 +22250,7 @@ var init_sync_client = __esm({
|
|
|
22238
22250
|
ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22239
22251
|
} catch {
|
|
22240
22252
|
try {
|
|
22241
|
-
if (true) ownVersion = "0.5.
|
|
22253
|
+
if (true) ownVersion = "0.5.28";
|
|
22242
22254
|
} catch {
|
|
22243
22255
|
}
|
|
22244
22256
|
}
|
|
@@ -22410,6 +22422,43 @@ var init_which = __esm({
|
|
|
22410
22422
|
}
|
|
22411
22423
|
});
|
|
22412
22424
|
|
|
22425
|
+
// src/init-report.ts
|
|
22426
|
+
var init_report_exports = {};
|
|
22427
|
+
__export(init_report_exports, {
|
|
22428
|
+
createInitReporter: () => createInitReporter
|
|
22429
|
+
});
|
|
22430
|
+
function createInitReporter(opts) {
|
|
22431
|
+
let painted = false;
|
|
22432
|
+
const clear = () => {
|
|
22433
|
+
if (painted && opts.tty) opts.write(`\r${" ".repeat(INSTALLING.length)}\r`);
|
|
22434
|
+
painted = false;
|
|
22435
|
+
};
|
|
22436
|
+
return {
|
|
22437
|
+
start() {
|
|
22438
|
+
if (painted) return;
|
|
22439
|
+
if (opts.tty) {
|
|
22440
|
+
opts.write(INSTALLING);
|
|
22441
|
+
painted = true;
|
|
22442
|
+
} else opts.line(INSTALLING);
|
|
22443
|
+
},
|
|
22444
|
+
warn(text) {
|
|
22445
|
+
clear();
|
|
22446
|
+
opts.line(text);
|
|
22447
|
+
},
|
|
22448
|
+
done(text) {
|
|
22449
|
+
clear();
|
|
22450
|
+
opts.line(text);
|
|
22451
|
+
}
|
|
22452
|
+
};
|
|
22453
|
+
}
|
|
22454
|
+
var INSTALLING;
|
|
22455
|
+
var init_init_report = __esm({
|
|
22456
|
+
"src/init-report.ts"() {
|
|
22457
|
+
"use strict";
|
|
22458
|
+
INSTALLING = "Installing\u2026";
|
|
22459
|
+
}
|
|
22460
|
+
});
|
|
22461
|
+
|
|
22413
22462
|
// ../engine/dist/core/mcp-clients.js
|
|
22414
22463
|
var mcp_clients_exports = {};
|
|
22415
22464
|
__export(mcp_clients_exports, {
|
|
@@ -23957,6 +24006,66 @@ var init_toolkit_pull = __esm({
|
|
|
23957
24006
|
}
|
|
23958
24007
|
});
|
|
23959
24008
|
|
|
24009
|
+
// src/init-progress.ts
|
|
24010
|
+
var init_progress_exports = {};
|
|
24011
|
+
__export(init_progress_exports, {
|
|
24012
|
+
handOffLine: () => handOffLine,
|
|
24013
|
+
progressLine: () => progressLine2,
|
|
24014
|
+
renderBar: () => renderBar,
|
|
24015
|
+
renderCount: () => renderCount,
|
|
24016
|
+
spawnDetachedSync: () => spawnDetachedSync,
|
|
24017
|
+
watchFirstSync: () => watchFirstSync
|
|
24018
|
+
});
|
|
24019
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
24020
|
+
function renderBar(done, total, width = 12) {
|
|
24021
|
+
if (total <= 0) return "\u2591".repeat(width);
|
|
24022
|
+
const ratio = Math.max(0, Math.min(1, done / total));
|
|
24023
|
+
const filled = Math.round(ratio * width);
|
|
24024
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
24025
|
+
}
|
|
24026
|
+
function renderCount(done, total) {
|
|
24027
|
+
const n = (x) => x.toLocaleString("en-US");
|
|
24028
|
+
return `${n(done)}/${n(total)}`;
|
|
24029
|
+
}
|
|
24030
|
+
function progressLine2(snap) {
|
|
24031
|
+
if (!snap || snap.total <= 0) return "starting\u2026";
|
|
24032
|
+
if (snap.complete) return `${renderCount(snap.done, snap.total)} indexed`;
|
|
24033
|
+
return `${renderBar(snap.done, snap.total)} ${renderCount(snap.done, snap.total)}`;
|
|
24034
|
+
}
|
|
24035
|
+
function handOffLine(snap) {
|
|
24036
|
+
const where = snap && snap.total > 0 ? `${renderCount(snap.done, snap.total)} so far` : "started";
|
|
24037
|
+
return `${where} \u2014 continuing in the background`;
|
|
24038
|
+
}
|
|
24039
|
+
async function watchFirstSync(deps) {
|
|
24040
|
+
const handOffAfterMs = deps.handOffAfterMs ?? 2e4;
|
|
24041
|
+
const pollMs = deps.pollMs ?? 400;
|
|
24042
|
+
const started = deps.now();
|
|
24043
|
+
deps.startWorker();
|
|
24044
|
+
let snap = null;
|
|
24045
|
+
for (; ; ) {
|
|
24046
|
+
snap = deps.readProgress();
|
|
24047
|
+
if (snap?.complete) return { finished: true, snapshot: snap };
|
|
24048
|
+
if (deps.now() - started >= handOffAfterMs) return { finished: false, snapshot: snap };
|
|
24049
|
+
deps.draw(progressLine2(snap));
|
|
24050
|
+
await deps.sleep(pollMs);
|
|
24051
|
+
}
|
|
24052
|
+
}
|
|
24053
|
+
function spawnDetachedSync(extraArgs = []) {
|
|
24054
|
+
const entry = process.argv[1];
|
|
24055
|
+
if (!entry) return;
|
|
24056
|
+
const child = spawn2(process.execPath, [entry, "sync", ...extraArgs], {
|
|
24057
|
+
detached: true,
|
|
24058
|
+
stdio: "ignore",
|
|
24059
|
+
windowsHide: true
|
|
24060
|
+
});
|
|
24061
|
+
child.unref();
|
|
24062
|
+
}
|
|
24063
|
+
var init_init_progress = __esm({
|
|
24064
|
+
"src/init-progress.ts"() {
|
|
24065
|
+
"use strict";
|
|
24066
|
+
}
|
|
24067
|
+
});
|
|
24068
|
+
|
|
23960
24069
|
// src/repair.ts
|
|
23961
24070
|
var repair_exports = {};
|
|
23962
24071
|
__export(repair_exports, {
|
|
@@ -24572,7 +24681,7 @@ __export(collector_exports, {
|
|
|
24572
24681
|
isSecretRule: () => isSecretRule,
|
|
24573
24682
|
resolveCodeindexBin: () => resolveCodeindexBin
|
|
24574
24683
|
});
|
|
24575
|
-
import { spawn as
|
|
24684
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
24576
24685
|
import { execSync as execSync4 } from "node:child_process";
|
|
24577
24686
|
import { readFileSync as readFileSync44 } from "node:fs";
|
|
24578
24687
|
import { join as join53, basename as basename28 } from "node:path";
|
|
@@ -24587,7 +24696,7 @@ async function resolveCodeindexBin(autoInstall = true) {
|
|
|
24587
24696
|
}
|
|
24588
24697
|
function runMcp(binPath, workspace, calls, timeoutMs = 18e4) {
|
|
24589
24698
|
return new Promise((resolve3, reject) => {
|
|
24590
|
-
const p =
|
|
24699
|
+
const p = spawn3(binPath, ["--mcp", "--workspace", workspace], { stdio: ["pipe", "pipe", "ignore"] });
|
|
24591
24700
|
const res = /* @__PURE__ */ new Map();
|
|
24592
24701
|
let pending = "";
|
|
24593
24702
|
let failed = false;
|
|
@@ -25892,7 +26001,7 @@ var init_intent_drain = __esm({
|
|
|
25892
26001
|
ownVersion2 = JSON.parse(readFileSync46(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25893
26002
|
} catch {
|
|
25894
26003
|
try {
|
|
25895
|
-
if (true) ownVersion2 = "0.5.
|
|
26004
|
+
if (true) ownVersion2 = "0.5.28";
|
|
25896
26005
|
} catch {
|
|
25897
26006
|
}
|
|
25898
26007
|
}
|
|
@@ -27603,6 +27712,7 @@ var DEFAULT_ALLOW = [
|
|
|
27603
27712
|
"recall_task_create",
|
|
27604
27713
|
"recall_task_update",
|
|
27605
27714
|
"recall_task_comment",
|
|
27715
|
+
"recall_task_policy",
|
|
27606
27716
|
"recall_help",
|
|
27607
27717
|
"recall_smart_resume",
|
|
27608
27718
|
"recall_project_context",
|
|
@@ -27653,7 +27763,6 @@ var DEFAULT_ALLOW = [
|
|
|
27653
27763
|
"recall_toolkit_status",
|
|
27654
27764
|
"recall_toolkit_sync"
|
|
27655
27765
|
];
|
|
27656
|
-
var SELF_HOST_DOCS = "https://github.com/munhq/chat-recall/blob/main/docs/SELF_HOSTING.md";
|
|
27657
27766
|
function enforceNodeVersion() {
|
|
27658
27767
|
const required = Number(/(\d+)/.exec(String(pkgEngines))?.[1] ?? 0);
|
|
27659
27768
|
const found = Number(process.versions.node.split(".")[0]);
|
|
@@ -27669,8 +27778,13 @@ program.name("chat-recall").description("Semantic search for Claude Code session
|
|
|
27669
27778
|
program.command("init").description("Set up chat-recall: connect to your server, configure MCP, ship your local sessions").option("--server <url>", "chat-recall server URL to connect this machine to").option("--token <token>", "Self-host device token (skips the interactive OIDC login)").option("--skip-mcp", "Skip MCP server configuration").option("--skip-sync", "Skip the first session sync").option("--with-codeindex", "Force-download the codeindex binary during init. Default behavior is to detect an already-installed codeindex on PATH and register it as an MCP server.").option("--skip-codeindex", "Skip the codeindex companion entirely (no detection, no registration).").option("--skip-service", "Skip installing the per-user background sync service (Linux/macOS/Windows). By default init installs it so new conversations ship automatically.").option("--yes", "Do not pause before the first upload. The scope summary still prints.", false).option("--prompt-json", "Print the device prompt as one JSON line on stdout, then continue", false).action(async (options) => {
|
|
27670
27779
|
try {
|
|
27671
27780
|
console.log(chalk.bold("chat-recall init") + chalk.dim(` v${pkgVersion}`));
|
|
27672
|
-
|
|
27673
|
-
|
|
27781
|
+
const { createInitReporter: createInitReporter2 } = await Promise.resolve().then(() => (init_init_report(), init_report_exports));
|
|
27782
|
+
const rep = createInitReporter2({
|
|
27783
|
+
tty: process.stdout.isTTY === true,
|
|
27784
|
+
write: (t) => process.stdout.write(t),
|
|
27785
|
+
line: (t) => console.log(t)
|
|
27786
|
+
});
|
|
27787
|
+
rep.start();
|
|
27674
27788
|
const clis = [
|
|
27675
27789
|
{ name: "Gemini CLI", cmd: "gemini", available: false },
|
|
27676
27790
|
{ name: "Claude CLI", cmd: "claude", available: false },
|
|
@@ -27686,12 +27800,9 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27686
27800
|
} catch {
|
|
27687
27801
|
}
|
|
27688
27802
|
}
|
|
27689
|
-
|
|
27690
|
-
|
|
27691
|
-
|
|
27692
|
-
}
|
|
27693
|
-
console.log();
|
|
27694
|
-
console.log(chalk.bold("2. Connecting to your server..."));
|
|
27803
|
+
const foundTools = clis.filter((c) => c.available).map((c) => c.name.replace(/ (CLI|Code)$/, ""));
|
|
27804
|
+
if (!foundTools.length) rep.warn(chalk.yellow("No AI tools detected \u2014 chat-recall indexes their transcripts, so there is nothing to ship yet."));
|
|
27805
|
+
const serverBad = (text) => rep.warn(`${chalk.yellow("Not connected")} \u2014 ${text}`);
|
|
27695
27806
|
let target = firstTarget();
|
|
27696
27807
|
let deadTarget = false;
|
|
27697
27808
|
if (options.server) {
|
|
@@ -27699,25 +27810,20 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27699
27810
|
await runLogin(options.server, { token: options.token, fromInit: true, promptJson: options.promptJson });
|
|
27700
27811
|
target = firstTarget();
|
|
27701
27812
|
} catch (e) {
|
|
27702
|
-
|
|
27703
|
-
console.log(` ${chalk.dim(`Run ${chalk.bold(`chat-recall login ${options.server}`)} when ready, or self-host: ${SELF_HOST_DOCS}`)}`);
|
|
27813
|
+
serverBad(describeProbeError(e));
|
|
27704
27814
|
}
|
|
27705
27815
|
} else if (!target) {
|
|
27706
|
-
console.log(` Connecting to ${chalk.bold(DEFAULT_SERVER)} \u2014 sign in to approve this machine.`);
|
|
27707
|
-
console.log(` ${chalk.dim(`Prefer your own server? ${chalk.bold("--server <url>")}. Self-hosting is free: ${SELF_HOST_DOCS}`)}`);
|
|
27708
27816
|
try {
|
|
27709
27817
|
await runLogin(DEFAULT_SERVER, { token: options.token, fromInit: true, promptJson: options.promptJson });
|
|
27710
27818
|
target = firstTarget();
|
|
27711
27819
|
} catch (e) {
|
|
27712
|
-
|
|
27713
|
-
console.log(` ${chalk.dim(`Run ${chalk.bold("chat-recall login <server-url>")} when ready, or self-host: ${SELF_HOST_DOCS}`)}`);
|
|
27820
|
+
serverBad(describeProbeError(e));
|
|
27714
27821
|
}
|
|
27715
27822
|
}
|
|
27716
27823
|
if (target && !options.server) {
|
|
27717
27824
|
const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
27718
27825
|
const probe = await probeServer2(target.base, { timeoutMs: 1e4 });
|
|
27719
27826
|
if (probeOk2(probe)) {
|
|
27720
|
-
console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
|
|
27721
27827
|
} else if (probe.kind === "moved" || probe.kind === "not_api") {
|
|
27722
27828
|
const retired = target.base;
|
|
27723
27829
|
console.log(` ${chalk.yellow("The saved server no longer serves chat-recall")} \u2192 ${retired}`);
|
|
@@ -27732,7 +27838,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27732
27838
|
target = firstTarget();
|
|
27733
27839
|
if (target) console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
|
|
27734
27840
|
} catch (e) {
|
|
27735
|
-
|
|
27841
|
+
serverBad(describeProbeError(e));
|
|
27736
27842
|
console.log(` ${chalk.dim(`Run ${chalk.bold(`chat-recall login ${DEFAULT_SERVER}`)} when ready, then ${chalk.bold(`chat-recall logout ${retired}`)}.`)}`);
|
|
27737
27843
|
deadTarget = true;
|
|
27738
27844
|
}
|
|
@@ -27741,11 +27847,8 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27741
27847
|
console.log(` ${probeAdvice2(probe, target.base)}`);
|
|
27742
27848
|
}
|
|
27743
27849
|
} else if (target) {
|
|
27744
|
-
console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
|
|
27745
27850
|
}
|
|
27746
|
-
console.log();
|
|
27747
27851
|
if (!options.skipMcp) {
|
|
27748
|
-
console.log(chalk.bold("3. Configuring MCP server..."));
|
|
27749
27852
|
const projectRoot = join60(import.meta.dirname, "..");
|
|
27750
27853
|
let mcpBinOnPath = false;
|
|
27751
27854
|
mcpBinOnPath = isOnPath("chat-recall-mcp");
|
|
@@ -27764,19 +27867,20 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27764
27867
|
{ ...launch, env: MCP_ENV, alwaysAllow: DEFAULT_ALLOW },
|
|
27765
27868
|
{ extraIds: detectedClients }
|
|
27766
27869
|
);
|
|
27767
|
-
|
|
27768
|
-
|
|
27769
|
-
|
|
27870
|
+
const ok = results.filter((r) => r.state !== "unparseable");
|
|
27871
|
+
const bad = results.filter((r) => r.state === "unparseable");
|
|
27872
|
+
if (ok.length) {
|
|
27873
|
+
}
|
|
27874
|
+
for (const r of bad) {
|
|
27875
|
+
rep.warn(`${chalk.yellow(`${r.label} config left alone \u2014 the file does not parse`)} ${chalk.dim(r.path)}`);
|
|
27876
|
+
}
|
|
27877
|
+
if (process.env.CHAT_RECALL_VERBOSE) {
|
|
27770
27878
|
}
|
|
27771
|
-
console.log(chalk.dim(` Launch: ${launch.command}${launch.args ? " " + launch.args.join(" ") : ""}`));
|
|
27772
27879
|
} else {
|
|
27773
|
-
console.log(chalk.bold("3. Skipping MCP configuration (--skip-mcp)"));
|
|
27774
27880
|
}
|
|
27775
|
-
console.log();
|
|
27776
27881
|
const skipCodeindex = options.skipCodeindex === true;
|
|
27777
27882
|
const forceInstall = options.withCodeindex === true || process.env.CHAT_RECALL_WITH_CODEINDEX === "1";
|
|
27778
27883
|
if (skipCodeindex) {
|
|
27779
|
-
console.log(chalk.bold("4. Skipping codeindex companion (--skip-codeindex)"));
|
|
27780
27884
|
} else {
|
|
27781
27885
|
const {
|
|
27782
27886
|
checkCodeindexStatus: checkCodeindexStatus2,
|
|
@@ -27786,64 +27890,46 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27786
27890
|
} = await Promise.resolve().then(() => (init_companions(), companions_exports));
|
|
27787
27891
|
const detected = checkCodeindexStatus2();
|
|
27788
27892
|
if (detected.installed && !forceInstall) {
|
|
27789
|
-
console.log(chalk.bold("4. Detected codeindex companion"));
|
|
27790
|
-
console.log(` ${chalk.green("codeindex")}: ${detected.path}`);
|
|
27791
27893
|
if (!options.skipMcp) {
|
|
27792
27894
|
const mcpJsonPath = join60(homedir22(), ".mcp.json");
|
|
27793
27895
|
const reg = registerCodeindexMcp2(mcpJsonPath, detected.path);
|
|
27794
|
-
if (reg.added) console.log(` ${chalk.green("codeindex MCP server registered")} in ${mcpJsonPath}`);
|
|
27795
|
-
else console.log(` codeindex MCP server: ${chalk.green("already registered")}`);
|
|
27796
27896
|
}
|
|
27797
27897
|
} else if (forceInstall) {
|
|
27798
|
-
console.log(chalk.bold("4. Installing codeindex companion (--with-codeindex)..."));
|
|
27799
27898
|
try {
|
|
27800
27899
|
const result = await installCodeindex2({ force: true });
|
|
27801
27900
|
if (result.installed) {
|
|
27802
27901
|
const sizeMb = result.size ? `${(result.size / 1024 / 1024).toFixed(1)} MB` : "?";
|
|
27803
|
-
console.log(` ${chalk.green("codeindex installed")} (${sizeMb}) \u2192 ${result.path}`);
|
|
27804
27902
|
if (!options.skipMcp) {
|
|
27805
27903
|
const mcpJsonPath = join60(homedir22(), ".mcp.json");
|
|
27806
27904
|
const reg = registerCodeindexMcp2(mcpJsonPath, CODEINDEX_BIN_PATH2);
|
|
27807
|
-
if (reg.added) console.log(` ${chalk.green("codeindex MCP server registered")} in ${mcpJsonPath}`);
|
|
27808
27905
|
}
|
|
27809
27906
|
} else if (!result.prebuiltAvailable) {
|
|
27810
|
-
|
|
27907
|
+
rep.warn(`${chalk.yellow("codeindex")}: ${result.unsupportedReason}`);
|
|
27811
27908
|
}
|
|
27812
27909
|
} catch (err) {
|
|
27813
27910
|
const msg = String(err);
|
|
27814
|
-
|
|
27911
|
+
rep.warn(`${chalk.yellow("codeindex install failed")}: ${msg}`);
|
|
27815
27912
|
if (msg.includes("404")) {
|
|
27816
27913
|
console.log(chalk.dim(" The codeindex release returned 404. If the repo is private,"));
|
|
27817
27914
|
console.log(chalk.dim(" authenticate `gh` to it, or build from source."));
|
|
27818
27915
|
}
|
|
27819
27916
|
}
|
|
27820
27917
|
} else {
|
|
27821
|
-
console.log(chalk.bold("4. codeindex companion: not installed"));
|
|
27822
|
-
console.log(chalk.dim(" codeindex is a separate MCP server for code-level lookup \u2014"));
|
|
27823
|
-
console.log(chalk.dim(" find_symbol, plan_change, get_change_impact, etc."));
|
|
27824
|
-
console.log(chalk.dim(" To install: `chat-recall init --with-codeindex`"));
|
|
27825
|
-
console.log(chalk.dim(" Or grab the binary from https://github.com/munhq/codeindex"));
|
|
27826
27918
|
}
|
|
27827
27919
|
}
|
|
27828
|
-
console.log();
|
|
27829
|
-
console.log(chalk.bold("Installing chat-recall skills into your AI tools..."));
|
|
27830
27920
|
try {
|
|
27831
27921
|
const { installSkills: installSkills2 } = await Promise.resolve().then(() => (init_install_skills(), install_skills_exports));
|
|
27832
27922
|
const r = installSkills2();
|
|
27833
27923
|
const hits = r.perTarget.filter((t) => t.installed.length > 0);
|
|
27834
27924
|
if (hits.length) {
|
|
27835
|
-
|
|
27925
|
+
const skills = Math.max(...hits.map((t) => t.installed.length));
|
|
27836
27926
|
} else {
|
|
27837
|
-
console.log(chalk.dim(" No supported AI tools detected \u2014 skills not installed."));
|
|
27838
27927
|
}
|
|
27839
27928
|
const userOwned = [...new Set(r.perTarget.flatMap((t) => t.skippedUserOwned))];
|
|
27840
|
-
if (userOwned.length) console.log(chalk.yellow(` Kept your existing skill(s) of the same name: ${userOwned.join(", ")}`));
|
|
27841
27929
|
} catch (err) {
|
|
27842
|
-
|
|
27930
|
+
rep.warn(`${chalk.yellow("Skill install failed")} \u2014 ${err instanceof Error ? err.message : err}`);
|
|
27843
27931
|
}
|
|
27844
|
-
console.log();
|
|
27845
27932
|
if (!options.skipMcp && firstTarget()) {
|
|
27846
|
-
console.log(chalk.bold("Installing your other MCP servers from your account..."));
|
|
27847
27933
|
try {
|
|
27848
27934
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
27849
27935
|
const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
|
|
@@ -27879,66 +27965,59 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27879
27965
|
const written = report.outcomes.filter((o) => o.status === "written");
|
|
27880
27966
|
const present = report.outcomes.filter((o) => o.status === "present").length;
|
|
27881
27967
|
if (answered === 0) {
|
|
27882
|
-
|
|
27968
|
+
rep.warn(chalk.yellow("Could not ask your server what MCP servers are on your account"));
|
|
27883
27969
|
for (const f of askFailed) console.log(` ${chalk.dim(f)}`);
|
|
27884
27970
|
console.log(` ${chalk.dim("Re-run `chat-recall toolkit pull` once the server answers.")}`);
|
|
27885
27971
|
} else if (written.length === 0 && present === 0) {
|
|
27886
|
-
console.log(chalk.dim(" Nothing on your account to install yet."));
|
|
27887
27972
|
} else {
|
|
27888
|
-
console.log(` ${chalk.green(`Installed ${written.length}`)} ${chalk.dim(`(${present} already present)`)}`);
|
|
27889
27973
|
const envVars = [...new Set(written.flatMap((o) => o.needsEnv || []))].sort();
|
|
27890
27974
|
if (envVars.length) {
|
|
27891
|
-
|
|
27975
|
+
rep.warn(`${chalk.yellow("Set these env vars \u2014 their values were never uploaded:")} ${envVars.join(", ")}`);
|
|
27892
27976
|
}
|
|
27893
27977
|
}
|
|
27894
27978
|
} catch (err) {
|
|
27895
|
-
|
|
27979
|
+
rep.warn(`${chalk.yellow("Could not install account MCPs")} \u2014 ${err instanceof Error ? err.message : err}`);
|
|
27896
27980
|
console.log(` ${chalk.dim("Re-run `chat-recall toolkit pull` later.")}`);
|
|
27897
27981
|
}
|
|
27898
|
-
console.log();
|
|
27899
27982
|
}
|
|
27900
27983
|
if (deadTarget) {
|
|
27901
|
-
console.log(chalk.bold("
|
|
27984
|
+
console.log(chalk.bold("6. Skipping first sync \u2014 the saved server is not serving chat-recall"));
|
|
27902
27985
|
console.log(` ${chalk.dim(`Re-point with the two commands above, then run ${chalk.bold("chat-recall sync")}.`)}`);
|
|
27903
27986
|
} else if (!options.skipSync && firstTarget()) {
|
|
27904
|
-
|
|
27905
|
-
|
|
27906
|
-
|
|
27907
|
-
|
|
27908
|
-
|
|
27909
|
-
|
|
27910
|
-
|
|
27911
|
-
|
|
27987
|
+
const { watchFirstSync: watchFirstSync2, spawnDetachedSync: spawnDetachedSync2, handOffLine: handOffLine2, progressLine: renderProgress } = await Promise.resolve().then(() => (init_init_progress(), init_progress_exports));
|
|
27988
|
+
const { readCollectorHealth: readCollectorHealth2 } = await Promise.resolve().then(() => (init_collector_health(), collector_health_exports));
|
|
27989
|
+
const label = (text) => `${chalk.bold("6. Indexing")} ${text}`;
|
|
27990
|
+
const tty = process.stdout.isTTY === true;
|
|
27991
|
+
const outcome = await watchFirstSync2({
|
|
27992
|
+
startWorker: () => spawnDetachedSync2(),
|
|
27993
|
+
readProgress: () => {
|
|
27994
|
+
const p = readCollectorHealth2()?.progress;
|
|
27995
|
+
return p ? { done: p.done, total: p.total, complete: p.complete } : null;
|
|
27996
|
+
},
|
|
27997
|
+
// In place on a terminal; a single final line when piped, so a log or
|
|
27998
|
+
// a CI transcript does not collect one line per poll.
|
|
27999
|
+
draw: (text) => {
|
|
28000
|
+
if (tty) process.stdout.write(`\r${label(text)} `);
|
|
28001
|
+
},
|
|
28002
|
+
now: () => Date.now(),
|
|
28003
|
+
sleep: (ms) => new Promise((r) => setTimeout(r, ms))
|
|
28004
|
+
});
|
|
28005
|
+
if (tty) process.stdout.write("\r");
|
|
28006
|
+
if (outcome.finished) {
|
|
28007
|
+
console.log(label(chalk.green(renderProgress(outcome.snapshot))));
|
|
28008
|
+
} else {
|
|
28009
|
+
console.log(label(chalk.dim(handOffLine2(outcome.snapshot))));
|
|
28010
|
+
console.log(` ${chalk.dim("watch it with: " + chalk.bold("chat-recall status"))}`);
|
|
28011
|
+
}
|
|
28012
|
+
const failed = Object.entries(readCollectorHealth2()?.targets ?? {}).filter(([, t]) => (t.failures ?? 0) > 0 && t.lastError);
|
|
28013
|
+
for (const [server, t] of failed) {
|
|
28014
|
+
console.log(` ${chalk.yellow("sync error")} ${chalk.dim(server)}: ${t.lastError}`);
|
|
27912
28015
|
}
|
|
27913
28016
|
} else if (!options.skipSync) {
|
|
27914
|
-
console.log(chalk.bold("5. Skipping first sync (not logged in)"));
|
|
27915
28017
|
} else {
|
|
27916
|
-
console.log(chalk.bold("5. Skipping first sync (--skip-sync)"));
|
|
27917
28018
|
}
|
|
27918
|
-
console.log();
|
|
27919
|
-
console.log(chalk.bold("6. Background sync"));
|
|
27920
|
-
console.log(chalk.dim(" Runs via the MCP server while Claude Code is open (no extra service to install)."));
|
|
27921
|
-
console.log(chalk.dim(" Always-on / headless? Opt in with `chat-recall watch --install-service`."));
|
|
27922
28019
|
void options.skipService;
|
|
27923
|
-
|
|
27924
|
-
console.log(chalk.green.bold("Setup complete!"));
|
|
27925
|
-
console.log();
|
|
27926
|
-
console.log(`chat-recall MCP tools (${DEFAULT_ALLOW.length}):`);
|
|
27927
|
-
for (let i = 0; i < DEFAULT_ALLOW.length; i += 3) {
|
|
27928
|
-
console.log(" " + DEFAULT_ALLOW.slice(i, i + 3).join(", "));
|
|
27929
|
-
}
|
|
27930
|
-
if (!skipCodeindex) {
|
|
27931
|
-
const { checkCodeindexStatus: checkCodeindexStatus2 } = await Promise.resolve().then(() => (init_companions(), companions_exports));
|
|
27932
|
-
if (checkCodeindexStatus2().installed) {
|
|
27933
|
-
console.log();
|
|
27934
|
-
console.log("codeindex MCP tools (16): status, search, find_symbol, find_word, get_outline,");
|
|
27935
|
-
console.log(" get_tree, get_imports, get_imported_by, find_callers, plan_change,");
|
|
27936
|
-
console.log(" get_hot_files, index_workspace, analyze, read_file, read_symbol,");
|
|
27937
|
-
console.log(" get_change_impact");
|
|
27938
|
-
}
|
|
27939
|
-
}
|
|
27940
|
-
console.log();
|
|
27941
|
-
console.log(`${chalk.dim("Background sync is running \u2014 new conversations ship automatically. Manage it with `chat-recall service status|uninstall`.")}`);
|
|
28020
|
+
rep.done(chalk.green.bold("\u2713 Done"));
|
|
27942
28021
|
} catch (err) {
|
|
27943
28022
|
console.error(chalk.red("Error:"), err);
|
|
27944
28023
|
process.exit(1);
|
|
@@ -29850,13 +29929,13 @@ async function runLogin(serverUrl, opts) {
|
|
|
29850
29929
|
return;
|
|
29851
29930
|
}
|
|
29852
29931
|
console.log();
|
|
29853
|
-
console.log(chalk.bold("
|
|
29932
|
+
console.log(chalk.bold("Open this to approve the machine:"));
|
|
29854
29933
|
console.log(" " + chalk.cyan(p.url));
|
|
29855
|
-
|
|
29856
|
-
|
|
29857
|
-
|
|
29858
|
-
console.log(chalk.dim(
|
|
29859
|
-
console.log(chalk.dim("
|
|
29934
|
+
if (openBrowser(p.url)) {
|
|
29935
|
+
console.log(chalk.dim(" (tried to open it for you \u2014 if no window appeared, use the link above)"));
|
|
29936
|
+
}
|
|
29937
|
+
console.log(chalk.dim(` If the page asks for a code: ${chalk.bold(p.userCode)}`));
|
|
29938
|
+
console.log(chalk.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
|
|
29860
29939
|
};
|
|
29861
29940
|
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base2, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
|
|
29862
29941
|
const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
|