chat-recall 0.5.20 → 0.5.22
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 +184 -162
- package/dist/cli.js.map +1 -1
- package/dist/install-report.d.ts +21 -0
- package/dist/install-report.d.ts.map +1 -0
- package/dist/install-report.js +76 -0
- package/dist/install-report.js.map +1 -0
- package/dist/mcp.js +29 -4
- package/dist/server-probe.d.ts +20 -0
- package/dist/server-probe.d.ts.map +1 -1
- package/dist/server-probe.js +69 -3
- package/dist/server-probe.js.map +1 -1
- package/dist/watch.js +5 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -19727,7 +19727,7 @@ var init_http = __esm({
|
|
|
19727
19727
|
CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19728
19728
|
} catch {
|
|
19729
19729
|
try {
|
|
19730
|
-
if (true) CLI_VERSION = "0.5.
|
|
19730
|
+
if (true) CLI_VERSION = "0.5.22";
|
|
19731
19731
|
} catch {
|
|
19732
19732
|
}
|
|
19733
19733
|
}
|
|
@@ -20239,7 +20239,7 @@ var init_telemetry = __esm({
|
|
|
20239
20239
|
init_sync_client();
|
|
20240
20240
|
cliVersion2 = () => {
|
|
20241
20241
|
try {
|
|
20242
|
-
return true ? "0.5.
|
|
20242
|
+
return true ? "0.5.22" : "dev";
|
|
20243
20243
|
} catch {
|
|
20244
20244
|
return "dev";
|
|
20245
20245
|
}
|
|
@@ -22066,7 +22066,7 @@ var init_sync_client = __esm({
|
|
|
22066
22066
|
ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22067
22067
|
} catch {
|
|
22068
22068
|
try {
|
|
22069
|
-
if (true) ownVersion = "0.5.
|
|
22069
|
+
if (true) ownVersion = "0.5.22";
|
|
22070
22070
|
} catch {
|
|
22071
22071
|
}
|
|
22072
22072
|
}
|
|
@@ -22237,75 +22237,6 @@ var init_which = __esm({
|
|
|
22237
22237
|
}
|
|
22238
22238
|
});
|
|
22239
22239
|
|
|
22240
|
-
// ../engine/dist/core/sync-scope.js
|
|
22241
|
-
var sync_scope_exports = {};
|
|
22242
|
-
__export(sync_scope_exports, {
|
|
22243
|
-
summariseSyncScope: () => summariseSyncScope
|
|
22244
|
-
});
|
|
22245
|
-
function summariseSyncScope(sinceMs = 0) {
|
|
22246
|
-
const sync = loadSettings().sync;
|
|
22247
|
-
const excludeProjects = sync?.excludeProjects ?? [];
|
|
22248
|
-
const excludeTools = new Set(sync?.excludeTools ?? []);
|
|
22249
|
-
const allowlistMode = (sync?.syncMode ?? "all") === "only";
|
|
22250
|
-
const syncOnly2 = new Set(sync?.syncOnlyProjects ?? []);
|
|
22251
|
-
const perProject = /* @__PURE__ */ new Map();
|
|
22252
|
-
const perTool = /* @__PURE__ */ new Map();
|
|
22253
|
-
for (const backend of listAvailableBackends()) {
|
|
22254
|
-
let refs = [];
|
|
22255
|
-
try {
|
|
22256
|
-
refs = backend.listSessions({ sinceMs });
|
|
22257
|
-
} catch {
|
|
22258
|
-
continue;
|
|
22259
|
-
}
|
|
22260
|
-
for (const ref of refs) {
|
|
22261
|
-
const projectPath = ref.projectPath || "";
|
|
22262
|
-
const toolId = ref.toolId || backend.id;
|
|
22263
|
-
let heldBackBy = null;
|
|
22264
|
-
if (excludeTools.has(toolId))
|
|
22265
|
-
heldBackBy = "excluded-tool";
|
|
22266
|
-
else if (excludeProjects.some((x) => projectPathIncludes(projectPath, x)))
|
|
22267
|
-
heldBackBy = "excluded-project";
|
|
22268
|
-
else if (!isProjectSyncable(idOf(projectPath), projectPath, { syncMode: sync?.syncMode, syncOnly: syncOnly2 })) {
|
|
22269
|
-
heldBackBy = "not-in-allowlist";
|
|
22270
|
-
}
|
|
22271
|
-
const id = idOf(projectPath);
|
|
22272
|
-
const key2 = `${id}\0${projectPath}`;
|
|
22273
|
-
const row = perProject.get(key2) ?? { id, projectPath, sessions: 0, heldBackBy };
|
|
22274
|
-
row.sessions++;
|
|
22275
|
-
row.heldBackBy = row.heldBackBy ?? heldBackBy;
|
|
22276
|
-
perProject.set(key2, row);
|
|
22277
|
-
if (!heldBackBy)
|
|
22278
|
-
perTool.set(toolId, (perTool.get(toolId) ?? 0) + 1);
|
|
22279
|
-
}
|
|
22280
|
-
}
|
|
22281
|
-
const projects = [...perProject.values()].sort((a, b) => b.sessions - a.sessions);
|
|
22282
|
-
const noPathSessions = projects.filter((p) => !p.projectPath && !p.heldBackBy).reduce((n, p) => n + p.sessions, 0);
|
|
22283
|
-
return {
|
|
22284
|
-
included: projects.filter((p) => !p.heldBackBy).reduce((n, p) => n + p.sessions, 0),
|
|
22285
|
-
heldBack: projects.filter((p) => p.heldBackBy).reduce((n, p) => n + p.sessions, 0),
|
|
22286
|
-
byTool: [...perTool.entries()].map(([tool, sessions]) => ({ tool, sessions })).sort((a, b) => b.sessions - a.sessions),
|
|
22287
|
-
projects,
|
|
22288
|
-
allowlistMode,
|
|
22289
|
-
noPathSessions
|
|
22290
|
-
};
|
|
22291
|
-
}
|
|
22292
|
-
function idOf(projectPath) {
|
|
22293
|
-
if (!projectPath)
|
|
22294
|
-
return "";
|
|
22295
|
-
const r = resolveProjectId(projectPath);
|
|
22296
|
-
return r.source === "ignored" ? "" : r.id;
|
|
22297
|
-
}
|
|
22298
|
-
var init_sync_scope = __esm({
|
|
22299
|
-
"../engine/dist/core/sync-scope.js"() {
|
|
22300
|
-
"use strict";
|
|
22301
|
-
init_tool_backend();
|
|
22302
|
-
init_backends();
|
|
22303
|
-
init_project_resolver();
|
|
22304
|
-
init_settings();
|
|
22305
|
-
init_project_path_match();
|
|
22306
|
-
}
|
|
22307
|
-
});
|
|
22308
|
-
|
|
22309
22240
|
// ../engine/dist/core/mcp-clients.js
|
|
22310
22241
|
var mcp_clients_exports = {};
|
|
22311
22242
|
__export(mcp_clients_exports, {
|
|
@@ -24217,6 +24148,8 @@ var init_escalate = __esm({
|
|
|
24217
24148
|
// src/server-probe.ts
|
|
24218
24149
|
var server_probe_exports = {};
|
|
24219
24150
|
__export(server_probe_exports, {
|
|
24151
|
+
classifyUnreachable: () => classifyUnreachable,
|
|
24152
|
+
describeCause: () => describeCause,
|
|
24220
24153
|
probeAdvice: () => probeAdvice,
|
|
24221
24154
|
probeOk: () => probeOk,
|
|
24222
24155
|
probeServer: () => probeServer
|
|
@@ -24232,7 +24165,11 @@ async function probeServer(base2, opts = {}) {
|
|
|
24232
24165
|
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
24233
24166
|
});
|
|
24234
24167
|
} catch (err) {
|
|
24235
|
-
return {
|
|
24168
|
+
return {
|
|
24169
|
+
kind: "unreachable",
|
|
24170
|
+
error: describeCause(err),
|
|
24171
|
+
reason: classifyUnreachable(err)
|
|
24172
|
+
};
|
|
24236
24173
|
}
|
|
24237
24174
|
if (res.status === 401 || res.status === 403) return { kind: "unauthorized", status: res.status };
|
|
24238
24175
|
if (res.status === 404 || res.status === 410) return { kind: "moved", status: res.status };
|
|
@@ -24242,7 +24179,7 @@ async function probeServer(base2, opts = {}) {
|
|
|
24242
24179
|
try {
|
|
24243
24180
|
body = await res.text();
|
|
24244
24181
|
} catch (err) {
|
|
24245
|
-
return { kind: "unreachable", error: err
|
|
24182
|
+
return { kind: "unreachable", error: describeCause(err), reason: classifyUnreachable(err) };
|
|
24246
24183
|
}
|
|
24247
24184
|
let parsed;
|
|
24248
24185
|
try {
|
|
@@ -24273,8 +24210,45 @@ function probeAdvice(r, base2) {
|
|
|
24273
24210
|
case "not_api":
|
|
24274
24211
|
return `${base2} answered ${r.status} with something that is not the chat-recall API (${JSON.stringify(r.snippet)}) \u2014 check the URL, a proxy or a captive portal`;
|
|
24275
24212
|
case "unreachable":
|
|
24276
|
-
|
|
24213
|
+
switch (r.reason) {
|
|
24214
|
+
case "dns":
|
|
24215
|
+
return `cannot resolve the host in ${base2} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
|
|
24216
|
+
case "refused":
|
|
24217
|
+
return `${base2} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
|
|
24218
|
+
case "tls":
|
|
24219
|
+
return `the TLS certificate at ${base2} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
|
|
24220
|
+
case "timeout":
|
|
24221
|
+
return `${base2} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
|
|
24222
|
+
case "reset":
|
|
24223
|
+
return `the connection to ${base2} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
|
|
24224
|
+
default:
|
|
24225
|
+
return `no HTTP response from ${base2} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
|
|
24226
|
+
}
|
|
24227
|
+
}
|
|
24228
|
+
}
|
|
24229
|
+
function classifyUnreachable(err) {
|
|
24230
|
+
if (err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError")) return "timeout";
|
|
24231
|
+
for (let e = err, depth = 0; e && depth < 5; depth++) {
|
|
24232
|
+
const code2 = String(e.code ?? "");
|
|
24233
|
+
const msg = String(e.message ?? "");
|
|
24234
|
+
if (code2 === "ENOTFOUND" || code2 === "EAI_AGAIN") return "dns";
|
|
24235
|
+
if (code2 === "ECONNREFUSED") return "refused";
|
|
24236
|
+
if (code2 === "ECONNRESET" || code2 === "EPIPE") return "reset";
|
|
24237
|
+
if (code2 === "ETIMEDOUT" || code2 === "UND_ERR_CONNECT_TIMEOUT" || code2 === "UND_ERR_HEADERS_TIMEOUT") return "timeout";
|
|
24238
|
+
if (code2.startsWith("CERT_") || code2.startsWith("ERR_TLS") || code2 === "DEPTH_ZERO_SELF_SIGNED_CERT" || code2 === "SELF_SIGNED_CERT_IN_CHAIN" || code2 === "UNABLE_TO_VERIFY_LEAF_SIGNATURE" || /certificate/i.test(msg)) return "tls";
|
|
24239
|
+
e = e.cause;
|
|
24277
24240
|
}
|
|
24241
|
+
return "unknown";
|
|
24242
|
+
}
|
|
24243
|
+
function describeCause(err) {
|
|
24244
|
+
const parts = [];
|
|
24245
|
+
for (let e = err, depth = 0; e && depth < 5; depth++) {
|
|
24246
|
+
const code2 = e.code;
|
|
24247
|
+
if (typeof code2 === "string" && code2 && !parts.includes(code2)) parts.push(code2);
|
|
24248
|
+
e = e.cause;
|
|
24249
|
+
}
|
|
24250
|
+
const base2 = err instanceof Error ? err.message : String(err);
|
|
24251
|
+
return parts.length ? `${base2}: ${parts.join(" \u2192 ")}` : base2;
|
|
24278
24252
|
}
|
|
24279
24253
|
var init_server_probe = __esm({
|
|
24280
24254
|
"src/server-probe.ts"() {
|
|
@@ -25862,7 +25836,7 @@ var init_intent_drain = __esm({
|
|
|
25862
25836
|
ownVersion2 = JSON.parse(readFileSync46(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25863
25837
|
} catch {
|
|
25864
25838
|
try {
|
|
25865
|
-
if (true) ownVersion2 = "0.5.
|
|
25839
|
+
if (true) ownVersion2 = "0.5.22";
|
|
25866
25840
|
} catch {
|
|
25867
25841
|
}
|
|
25868
25842
|
}
|
|
@@ -27261,6 +27235,50 @@ var init_device_auth = __esm({
|
|
|
27261
27235
|
}
|
|
27262
27236
|
});
|
|
27263
27237
|
|
|
27238
|
+
// src/install-report.ts
|
|
27239
|
+
var install_report_exports = {};
|
|
27240
|
+
__export(install_report_exports, {
|
|
27241
|
+
reportInstallFailure: () => reportInstallFailure
|
|
27242
|
+
});
|
|
27243
|
+
async function reportInstallFailure(serverUrl, failure, opts = {}) {
|
|
27244
|
+
if (!serverUrl) return false;
|
|
27245
|
+
if (!userConsents() && !mayReport(serverUrl)) return false;
|
|
27246
|
+
const payload = {
|
|
27247
|
+
step: failure.step,
|
|
27248
|
+
reason: trim(failure.reason, 40),
|
|
27249
|
+
message: trim(failure.message, 200),
|
|
27250
|
+
cliVersion: trim(process.env.CHAT_RECALL_CLI_VERSION, 20),
|
|
27251
|
+
node: trim(process.versions.node, 20),
|
|
27252
|
+
os: `${process.platform}-${process.arch}`
|
|
27253
|
+
};
|
|
27254
|
+
try {
|
|
27255
|
+
assertNoSensitiveKeys(payload);
|
|
27256
|
+
} catch {
|
|
27257
|
+
return false;
|
|
27258
|
+
}
|
|
27259
|
+
const f = opts.fetchImpl || fetch;
|
|
27260
|
+
try {
|
|
27261
|
+
const res = await f(`${serverUrl.replace(/\/+$/, "")}/install/report`, {
|
|
27262
|
+
method: "POST",
|
|
27263
|
+
headers: { "content-type": "application/json" },
|
|
27264
|
+
body: JSON.stringify(payload),
|
|
27265
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 3e3)
|
|
27266
|
+
});
|
|
27267
|
+
return res.ok || res.status === 204;
|
|
27268
|
+
} catch {
|
|
27269
|
+
return false;
|
|
27270
|
+
}
|
|
27271
|
+
}
|
|
27272
|
+
function trim(v, n) {
|
|
27273
|
+
return typeof v === "string" && v.trim() ? v.trim().slice(0, n) : null;
|
|
27274
|
+
}
|
|
27275
|
+
var init_install_report = __esm({
|
|
27276
|
+
"src/install-report.ts"() {
|
|
27277
|
+
"use strict";
|
|
27278
|
+
init_telemetry_consent();
|
|
27279
|
+
}
|
|
27280
|
+
});
|
|
27281
|
+
|
|
27264
27282
|
// ../engine/dist/core/resume-command.js
|
|
27265
27283
|
function toolOfSessionId(sessionId) {
|
|
27266
27284
|
if (sessionId.startsWith("codex_"))
|
|
@@ -27377,54 +27395,20 @@ function firstTarget() {
|
|
|
27377
27395
|
if (!cred) return null;
|
|
27378
27396
|
return { base: cred.serverUrl.replace(/\/+$/, ""), token: cred.token };
|
|
27379
27397
|
}
|
|
27380
|
-
|
|
27381
|
-
const
|
|
27382
|
-
let
|
|
27383
|
-
|
|
27384
|
-
|
|
27385
|
-
|
|
27386
|
-
console.log(chalk.dim(" (could not summarise local scope \u2014 proceeding)"));
|
|
27387
|
-
return true;
|
|
27388
|
-
}
|
|
27389
|
-
console.log(chalk.bold("6. What would leave this machine"));
|
|
27390
|
-
if (scope.included === 0 && scope.heldBack === 0) {
|
|
27391
|
-
console.log(chalk.dim(" No local sessions found yet \u2014 nothing to ship."));
|
|
27392
|
-
return true;
|
|
27393
|
-
}
|
|
27394
|
-
const tools = scope.byTool.map((t) => `${t.tool} ${t.sessions}`).join(", ");
|
|
27395
|
-
console.log(` ${chalk.bold(String(scope.included))} session(s) would upload${tools ? chalk.dim(` (${tools})`) : ""}`);
|
|
27396
|
-
if (scope.heldBack > 0) {
|
|
27397
|
-
console.log(` ${chalk.green(String(scope.heldBack))} held back by your existing rules`);
|
|
27398
|
-
}
|
|
27399
|
-
if (scope.allowlistMode) {
|
|
27400
|
-
console.log(chalk.yellow(" Allowlist mode is on \u2014 only the projects you listed would ship."));
|
|
27401
|
-
}
|
|
27402
|
-
if (scope.noPathSessions > 0) {
|
|
27403
|
-
console.log(` ${chalk.yellow(String(scope.noPathSessions))} of those carry no project path \u2014 only \`exclude tool\` can hold those back`);
|
|
27404
|
-
}
|
|
27405
|
-
const shown = scope.projects.filter((p) => !p.heldBackBy).slice(0, 8);
|
|
27406
|
-
for (const p of shown) {
|
|
27407
|
-
console.log(` ${chalk.cyan(p.projectPath || p.id)} ${chalk.dim(`\xB7 ${p.sessions}`)}`);
|
|
27408
|
-
}
|
|
27409
|
-
const more = scope.projects.filter((p) => !p.heldBackBy).length - shown.length;
|
|
27410
|
-
if (more > 0) console.log(chalk.dim(` \u2026and ${more} more project(s)`));
|
|
27411
|
-
console.log(chalk.dim(" Secrets are masked on this machine before anything uploads."));
|
|
27412
|
-
console.log(chalk.dim(" Hold one back: chat-recall exclude project <path>"));
|
|
27413
|
-
console.log(chalk.dim(" Or invert it: chat-recall sync-only add <project>"));
|
|
27414
|
-
if (skipPause || !process.stdin.isTTY) {
|
|
27415
|
-
console.log();
|
|
27416
|
-
return true;
|
|
27417
|
-
}
|
|
27418
|
-
const { createInterface: createInterface3 } = await import("node:readline/promises");
|
|
27419
|
-
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
27420
|
-
const answer = (await rl.question(" Upload these now? [Y/n] ")).trim().toLowerCase();
|
|
27421
|
-
rl.close();
|
|
27422
|
-
if (answer === "n" || answer === "no") {
|
|
27423
|
-
console.log(chalk.dim(" Skipped. Set your rules, then run `chat-recall sync`."));
|
|
27424
|
-
return false;
|
|
27398
|
+
function describeProbeError(err) {
|
|
27399
|
+
const codes = [];
|
|
27400
|
+
for (let e = err, depth = 0; e && depth < 5; depth++) {
|
|
27401
|
+
const code2 = e.code;
|
|
27402
|
+
if (typeof code2 === "string" && code2 && !codes.includes(code2)) codes.push(code2);
|
|
27403
|
+
e = e.cause;
|
|
27425
27404
|
}
|
|
27426
|
-
|
|
27427
|
-
return
|
|
27405
|
+
const base2 = err instanceof Error ? err.message : String(err);
|
|
27406
|
+
return codes.length ? `${base2}: ${codes.join(" \u2192 ")}` : base2;
|
|
27407
|
+
}
|
|
27408
|
+
function failLogin(opts, message) {
|
|
27409
|
+
if (opts.fromInit) throw new Error(message);
|
|
27410
|
+
console.error(chalk.red("login failed:"), message);
|
|
27411
|
+
process.exit(1);
|
|
27428
27412
|
}
|
|
27429
27413
|
function requireTarget() {
|
|
27430
27414
|
const t = firstTarget();
|
|
@@ -27480,6 +27464,13 @@ async function serverDelete(path, body) {
|
|
|
27480
27464
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27481
27465
|
return res.json();
|
|
27482
27466
|
}
|
|
27467
|
+
var pkgEngines = (() => {
|
|
27468
|
+
try {
|
|
27469
|
+
return JSON.parse(readFileSync49(new URL("../package.json", import.meta.url), "utf-8")).engines?.node ?? "";
|
|
27470
|
+
} catch {
|
|
27471
|
+
return "";
|
|
27472
|
+
}
|
|
27473
|
+
})();
|
|
27483
27474
|
var pkgVersion = JSON.parse(
|
|
27484
27475
|
readFileSync49(new URL("../package.json", import.meta.url), "utf-8")
|
|
27485
27476
|
).version;
|
|
@@ -27556,11 +27547,21 @@ var DEFAULT_ALLOW = [
|
|
|
27556
27547
|
"recall_toolkit_sync"
|
|
27557
27548
|
];
|
|
27558
27549
|
var SELF_HOST_DOCS = "https://github.com/munhq/chat-recall/blob/main/docs/SELF_HOSTING.md";
|
|
27550
|
+
function enforceNodeVersion() {
|
|
27551
|
+
const required = Number(/(\d+)/.exec(String(pkgEngines))?.[1] ?? 0);
|
|
27552
|
+
const found = Number(process.versions.node.split(".")[0]);
|
|
27553
|
+
if (!required || !found || found >= required) return;
|
|
27554
|
+
console.error(`chat-recall needs Node ${required} or newer. This is Node ${process.versions.node}.`);
|
|
27555
|
+
console.error(`Install it with your version manager (\`nvm install ${required}\`, \`fnm install ${required}\`, \`brew upgrade node\`), then run this again.`);
|
|
27556
|
+
process.exit(1);
|
|
27557
|
+
}
|
|
27558
|
+
process.env.CHAT_RECALL_CLI_VERSION = pkgVersion;
|
|
27559
|
+
enforceNodeVersion();
|
|
27559
27560
|
var program = new Command();
|
|
27560
27561
|
program.name("chat-recall").description("Semantic search for Claude Code sessions - recall and resume past conversations").version(pkgVersion);
|
|
27561
27562
|
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) => {
|
|
27562
27563
|
try {
|
|
27563
|
-
console.log(chalk.bold("chat-recall init"));
|
|
27564
|
+
console.log(chalk.bold("chat-recall init") + chalk.dim(` v${pkgVersion}`));
|
|
27564
27565
|
console.log();
|
|
27565
27566
|
console.log(chalk.bold("1. Detecting AI tools..."));
|
|
27566
27567
|
const clis = [
|
|
@@ -27586,8 +27587,13 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27586
27587
|
console.log(chalk.bold("2. Connecting to your server..."));
|
|
27587
27588
|
let target = firstTarget();
|
|
27588
27589
|
if (options.server) {
|
|
27589
|
-
|
|
27590
|
-
|
|
27590
|
+
try {
|
|
27591
|
+
await runLogin(options.server, { token: options.token, fromInit: true, promptJson: options.promptJson });
|
|
27592
|
+
target = firstTarget();
|
|
27593
|
+
} catch (e) {
|
|
27594
|
+
console.log(` ${chalk.yellow("Not connected.")} ${describeProbeError(e)}`);
|
|
27595
|
+
console.log(` ${chalk.dim(`Run ${chalk.bold(`chat-recall login ${options.server}`)} when ready, or self-host: ${SELF_HOST_DOCS}`)}`);
|
|
27596
|
+
}
|
|
27591
27597
|
} else if (!target) {
|
|
27592
27598
|
console.log(` Connecting to ${chalk.bold(DEFAULT_SERVER)} \u2014 sign in to approve this machine.`);
|
|
27593
27599
|
console.log(` ${chalk.dim(`Prefer your own server? ${chalk.bold("--server <url>")}. Self-hosting is free: ${SELF_HOST_DOCS}`)}`);
|
|
@@ -27595,7 +27601,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27595
27601
|
await runLogin(DEFAULT_SERVER, { token: options.token, fromInit: true, promptJson: options.promptJson });
|
|
27596
27602
|
target = firstTarget();
|
|
27597
27603
|
} catch (e) {
|
|
27598
|
-
console.log(` ${chalk.yellow("Not connected.")} ${e
|
|
27604
|
+
console.log(` ${chalk.yellow("Not connected.")} ${describeProbeError(e)}`);
|
|
27599
27605
|
console.log(` ${chalk.dim(`Run ${chalk.bold("chat-recall login <server-url>")} when ready, or self-host: ${SELF_HOST_DOCS}`)}`);
|
|
27600
27606
|
}
|
|
27601
27607
|
}
|
|
@@ -27604,7 +27610,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27604
27610
|
}
|
|
27605
27611
|
console.log();
|
|
27606
27612
|
if (!options.skipMcp) {
|
|
27607
|
-
console.log(chalk.bold("
|
|
27613
|
+
console.log(chalk.bold("3. Configuring MCP server..."));
|
|
27608
27614
|
const projectRoot = join60(import.meta.dirname, "..");
|
|
27609
27615
|
let mcpBinOnPath = false;
|
|
27610
27616
|
mcpBinOnPath = isOnPath("chat-recall-mcp");
|
|
@@ -27629,13 +27635,13 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27629
27635
|
}
|
|
27630
27636
|
console.log(chalk.dim(` Launch: ${launch.command}${launch.args ? " " + launch.args.join(" ") : ""}`));
|
|
27631
27637
|
} else {
|
|
27632
|
-
console.log(chalk.bold("
|
|
27638
|
+
console.log(chalk.bold("3. Skipping MCP configuration (--skip-mcp)"));
|
|
27633
27639
|
}
|
|
27634
27640
|
console.log();
|
|
27635
27641
|
const skipCodeindex = options.skipCodeindex === true;
|
|
27636
27642
|
const forceInstall = options.withCodeindex === true || process.env.CHAT_RECALL_WITH_CODEINDEX === "1";
|
|
27637
27643
|
if (skipCodeindex) {
|
|
27638
|
-
console.log(chalk.bold("
|
|
27644
|
+
console.log(chalk.bold("4. Skipping codeindex companion (--skip-codeindex)"));
|
|
27639
27645
|
} else {
|
|
27640
27646
|
const {
|
|
27641
27647
|
checkCodeindexStatus: checkCodeindexStatus2,
|
|
@@ -27645,7 +27651,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27645
27651
|
} = await Promise.resolve().then(() => (init_companions(), companions_exports));
|
|
27646
27652
|
const detected = checkCodeindexStatus2();
|
|
27647
27653
|
if (detected.installed && !forceInstall) {
|
|
27648
|
-
console.log(chalk.bold("
|
|
27654
|
+
console.log(chalk.bold("4. Detected codeindex companion"));
|
|
27649
27655
|
console.log(` ${chalk.green("codeindex")}: ${detected.path}`);
|
|
27650
27656
|
if (!options.skipMcp) {
|
|
27651
27657
|
const mcpJsonPath = join60(homedir22(), ".mcp.json");
|
|
@@ -27654,7 +27660,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27654
27660
|
else console.log(` codeindex MCP server: ${chalk.green("already registered")}`);
|
|
27655
27661
|
}
|
|
27656
27662
|
} else if (forceInstall) {
|
|
27657
|
-
console.log(chalk.bold("
|
|
27663
|
+
console.log(chalk.bold("4. Installing codeindex companion (--with-codeindex)..."));
|
|
27658
27664
|
try {
|
|
27659
27665
|
const result = await installCodeindex2({ force: true });
|
|
27660
27666
|
if (result.installed) {
|
|
@@ -27677,7 +27683,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27677
27683
|
}
|
|
27678
27684
|
}
|
|
27679
27685
|
} else {
|
|
27680
|
-
console.log(chalk.bold("
|
|
27686
|
+
console.log(chalk.bold("4. codeindex companion: not installed"));
|
|
27681
27687
|
console.log(chalk.dim(" codeindex is a separate MCP server for code-level lookup \u2014"));
|
|
27682
27688
|
console.log(chalk.dim(" find_symbol, plan_change, get_change_impact, etc."));
|
|
27683
27689
|
console.log(chalk.dim(" To install: `chat-recall init --with-codeindex`"));
|
|
@@ -27739,27 +27745,22 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27739
27745
|
console.log();
|
|
27740
27746
|
}
|
|
27741
27747
|
if (!options.skipSync && firstTarget()) {
|
|
27742
|
-
|
|
27743
|
-
|
|
27744
|
-
|
|
27745
|
-
|
|
27746
|
-
console.log(chalk.dim("
|
|
27747
|
-
|
|
27748
|
-
|
|
27749
|
-
|
|
27750
|
-
console.log(` ${chalk.green(`Synced ${r.uploaded} session(s), ${r.items} item(s)`)} ${chalk.dim(`\u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`)}`);
|
|
27751
|
-
} catch (err) {
|
|
27752
|
-
console.log(` ${chalk.yellow("Sync failed")} \u2014 ${err instanceof Error ? err.message : err}`);
|
|
27753
|
-
console.log(` ${chalk.dim("Re-run `chat-recall sync` once your server is reachable.")}`);
|
|
27754
|
-
}
|
|
27748
|
+
console.log(chalk.bold("5. Indexing and uploading your sessions"));
|
|
27749
|
+
try {
|
|
27750
|
+
const { syncSessions: syncSessions2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
27751
|
+
const r = await syncSessions2();
|
|
27752
|
+
console.log(` ${chalk.green(`Synced ${r.uploaded} session(s), ${r.items} item(s)`)} ${chalk.dim(`\u2014 ${r.links} links, ${r.derived} derived rows, ${r.kgTriples} KG triples, ${r.skipped} skipped, ${r.redactions} secrets redacted, ${r.findings} secret findings${r.scanned ? ` (scanned ${r.scanned} in ${r.scanMs}ms)` : ""}`)}`);
|
|
27753
|
+
} catch (err) {
|
|
27754
|
+
console.log(` ${chalk.yellow("Sync failed")} \u2014 ${err instanceof Error ? err.message : err}`);
|
|
27755
|
+
console.log(` ${chalk.dim("Re-run `chat-recall sync` once your server is reachable.")}`);
|
|
27755
27756
|
}
|
|
27756
27757
|
} else if (!options.skipSync) {
|
|
27757
|
-
console.log(chalk.bold("
|
|
27758
|
+
console.log(chalk.bold("5. Skipping first sync (not logged in)"));
|
|
27758
27759
|
} else {
|
|
27759
|
-
console.log(chalk.bold("
|
|
27760
|
+
console.log(chalk.bold("5. Skipping first sync (--skip-sync)"));
|
|
27760
27761
|
}
|
|
27761
27762
|
console.log();
|
|
27762
|
-
console.log(chalk.bold("
|
|
27763
|
+
console.log(chalk.bold("6. Background sync"));
|
|
27763
27764
|
console.log(chalk.dim(" Runs via the MCP server while Claude Code is open (no extra service to install)."));
|
|
27764
27765
|
console.log(chalk.dim(" Always-on / headless? Opt in with `chat-recall watch --install-service`."));
|
|
27765
27766
|
void options.skipService;
|
|
@@ -29607,19 +29608,16 @@ async function runLogin(serverUrl, opts) {
|
|
|
29607
29608
|
if (opts.token) {
|
|
29608
29609
|
const token = opts.token.trim();
|
|
29609
29610
|
if (/[^\x21-\x7e]/.test(token)) {
|
|
29610
|
-
console.error(chalk.red('login failed: the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026").'));
|
|
29611
29611
|
console.error(chalk.dim("Use the Copy button next to the token in the dashboard and paste the full line."));
|
|
29612
|
-
|
|
29612
|
+
return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
|
|
29613
29613
|
}
|
|
29614
29614
|
const check = await verifyToken(token);
|
|
29615
29615
|
if (!check.ok) {
|
|
29616
29616
|
if (check.status === 401 || check.status === 403) {
|
|
29617
|
-
console.error(chalk.red(`login failed: ${base2} rejected the token (HTTP ${check.status}).`));
|
|
29618
29617
|
console.error(chalk.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
|
|
29619
|
-
|
|
29620
|
-
console.error(chalk.red(`login failed: could not verify the token against ${base2}:`), check.error || `HTTP ${check.status}`);
|
|
29618
|
+
return failLogin(opts, `${base2} rejected the token (HTTP ${check.status})`);
|
|
29621
29619
|
}
|
|
29622
|
-
|
|
29620
|
+
return failLogin(opts, `could not verify the token against ${base2}: ${check.error || `HTTP ${check.status}`}`);
|
|
29623
29621
|
}
|
|
29624
29622
|
saveCredentials2({ serverUrl, token });
|
|
29625
29623
|
console.log(chalk.green("\u2713 Logged in.") + chalk.dim(` server: ${serverUrl} (token verified)`));
|
|
@@ -29647,12 +29645,36 @@ async function runLogin(serverUrl, opts) {
|
|
|
29647
29645
|
const { deviceLogin: deviceLogin2, betterAuthDeviceLogin: betterAuthDeviceLogin2 } = await Promise.resolve().then(() => (init_device_auth(), device_auth_exports));
|
|
29648
29646
|
let issuer = opts.issuer;
|
|
29649
29647
|
let authProvider;
|
|
29648
|
+
let capsError = null;
|
|
29650
29649
|
if (!issuer) {
|
|
29651
|
-
|
|
29652
|
-
|
|
29653
|
-
|
|
29654
|
-
if (
|
|
29655
|
-
|
|
29650
|
+
const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
29651
|
+
for (let attempt = 1; attempt <= 3 && !authProvider; attempt++) {
|
|
29652
|
+
const probe = await probeServer2(base2, { timeoutMs: 15e3 });
|
|
29653
|
+
if (probeOk2(probe)) {
|
|
29654
|
+
try {
|
|
29655
|
+
const caps = await fetch(`${base2}/api/capabilities`, { signal: AbortSignal.timeout(15e3) }).then((r) => r.json());
|
|
29656
|
+
authProvider = caps?.authProvider;
|
|
29657
|
+
if (caps?.oidcIssuer) issuer = caps.oidcIssuer;
|
|
29658
|
+
capsError = null;
|
|
29659
|
+
} catch (err) {
|
|
29660
|
+
capsError = describeProbeError(err);
|
|
29661
|
+
}
|
|
29662
|
+
} else {
|
|
29663
|
+
capsError = probeAdvice2(probe, base2);
|
|
29664
|
+
}
|
|
29665
|
+
if (!authProvider && attempt < 3) await new Promise((r) => setTimeout(r, attempt * 1e3));
|
|
29666
|
+
}
|
|
29667
|
+
}
|
|
29668
|
+
if (!authProvider && !issuer) {
|
|
29669
|
+
authProvider = "better-auth";
|
|
29670
|
+
if (capsError) {
|
|
29671
|
+
console.log(` ${chalk.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
|
|
29672
|
+
void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(base2, {
|
|
29673
|
+
step: "cli_login_probe",
|
|
29674
|
+
reason: capsError?.slice(0, 40) ?? null,
|
|
29675
|
+
message: capsError
|
|
29676
|
+
})).catch(() => {
|
|
29677
|
+
});
|
|
29656
29678
|
}
|
|
29657
29679
|
}
|
|
29658
29680
|
const onPrompt = (p) => {
|
|
@@ -29681,9 +29703,8 @@ async function runLogin(serverUrl, opts) {
|
|
|
29681
29703
|
slug = (await created.json()).slug;
|
|
29682
29704
|
console.log(chalk.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
|
|
29683
29705
|
} else {
|
|
29684
|
-
console.error(chalk.red("You belong to multiple teams \u2014 pass --team <slug>:"));
|
|
29685
29706
|
teams.forEach((t) => console.error(` ${t.team_slug} ${chalk.dim(t.name)}`));
|
|
29686
|
-
|
|
29707
|
+
throw new Error("you belong to multiple teams \u2014 pass --team <slug> (listed above)");
|
|
29687
29708
|
}
|
|
29688
29709
|
}
|
|
29689
29710
|
const deviceId = opts.deviceId || (await import("node:os")).hostname();
|
|
@@ -29700,6 +29721,7 @@ async function runLogin(serverUrl, opts) {
|
|
|
29700
29721
|
console.log(chalk.dim("Run `chat-recall sync` to push redacted conversations."));
|
|
29701
29722
|
}
|
|
29702
29723
|
} catch (err) {
|
|
29724
|
+
if (opts.fromInit) throw err instanceof Error ? err : new Error(String(err));
|
|
29703
29725
|
console.error(chalk.red("login failed:"), err instanceof Error ? err.message : err);
|
|
29704
29726
|
process.exit(1);
|
|
29705
29727
|
}
|