chat-recall 0.5.22 → 0.5.23
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 +289 -167
- package/dist/cli.js.map +1 -1
- package/dist/conformant-server.d.ts +17 -0
- package/dist/conformant-server.d.ts.map +1 -0
- package/dist/conformant-server.js +116 -0
- package/dist/conformant-server.js.map +1 -0
- package/dist/device-auth.d.ts +0 -4
- package/dist/device-auth.d.ts.map +1 -1
- package/dist/device-auth.js +43 -2
- package/dist/device-auth.js.map +1 -1
- package/dist/hostile-server.d.ts +47 -0
- package/dist/hostile-server.d.ts.map +1 -0
- package/dist/hostile-server.js +95 -0
- package/dist/hostile-server.js.map +1 -0
- package/dist/mcp.js +160 -8
- package/dist/server-probe.d.ts +16 -2
- package/dist/server-probe.d.ts.map +1 -1
- package/dist/server-probe.js +59 -4
- package/dist/server-probe.js.map +1 -1
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +47 -2
- package/dist/sync-client.js.map +1 -1
- package/dist/watch.js +250 -103
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -13470,8 +13470,11 @@ function isInside(child, parent) {
|
|
|
13470
13470
|
return c.startsWith(p);
|
|
13471
13471
|
}
|
|
13472
13472
|
function globMatch(pattern, path) {
|
|
13473
|
-
const re = new RegExp("^" + globToRegex(pattern) + "$");
|
|
13474
|
-
return re.test(path);
|
|
13473
|
+
const re = new RegExp("^" + globToRegex(toPosix(pattern)) + "$");
|
|
13474
|
+
return re.test(toPosix(path));
|
|
13475
|
+
}
|
|
13476
|
+
function toPosix(p) {
|
|
13477
|
+
return p.replace(/\\/g, "/");
|
|
13475
13478
|
}
|
|
13476
13479
|
function globToRegex(glob) {
|
|
13477
13480
|
let out = "";
|
|
@@ -19727,7 +19730,7 @@ var init_http = __esm({
|
|
|
19727
19730
|
CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19728
19731
|
} catch {
|
|
19729
19732
|
try {
|
|
19730
|
-
if (true) CLI_VERSION = "0.5.
|
|
19733
|
+
if (true) CLI_VERSION = "0.5.23";
|
|
19731
19734
|
} catch {
|
|
19732
19735
|
}
|
|
19733
19736
|
}
|
|
@@ -20239,7 +20242,7 @@ var init_telemetry = __esm({
|
|
|
20239
20242
|
init_sync_client();
|
|
20240
20243
|
cliVersion2 = () => {
|
|
20241
20244
|
try {
|
|
20242
|
-
return true ? "0.5.
|
|
20245
|
+
return true ? "0.5.23" : "dev";
|
|
20243
20246
|
} catch {
|
|
20244
20247
|
return "dev";
|
|
20245
20248
|
}
|
|
@@ -20351,6 +20354,143 @@ var init_collector_health = __esm({
|
|
|
20351
20354
|
}
|
|
20352
20355
|
});
|
|
20353
20356
|
|
|
20357
|
+
// src/server-probe.ts
|
|
20358
|
+
var server_probe_exports = {};
|
|
20359
|
+
__export(server_probe_exports, {
|
|
20360
|
+
classifyUnreachable: () => classifyUnreachable,
|
|
20361
|
+
describeCause: () => describeCause,
|
|
20362
|
+
describeUnreachable: () => describeUnreachable,
|
|
20363
|
+
probeAdvice: () => probeAdvice,
|
|
20364
|
+
probeOk: () => probeOk,
|
|
20365
|
+
probeServer: () => probeServer
|
|
20366
|
+
});
|
|
20367
|
+
function probeOk(r) {
|
|
20368
|
+
return r.kind === "ok" && r.apiVersion >= 2;
|
|
20369
|
+
}
|
|
20370
|
+
async function probeServer(base2, opts = {}) {
|
|
20371
|
+
const f = opts.fetchImpl || fetch;
|
|
20372
|
+
let res;
|
|
20373
|
+
try {
|
|
20374
|
+
res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
|
|
20375
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
20376
|
+
});
|
|
20377
|
+
} catch (err) {
|
|
20378
|
+
return {
|
|
20379
|
+
kind: "unreachable",
|
|
20380
|
+
error: describeCause(err),
|
|
20381
|
+
reason: classifyUnreachable(err)
|
|
20382
|
+
};
|
|
20383
|
+
}
|
|
20384
|
+
if (res.status === 401 || res.status === 403) return { kind: "unauthorized", status: res.status };
|
|
20385
|
+
if (res.status === 404 || res.status === 410) return { kind: "moved", status: res.status };
|
|
20386
|
+
if (res.status >= 500) return { kind: "server_error", status: res.status };
|
|
20387
|
+
if (!res.ok) return { kind: "moved", status: res.status };
|
|
20388
|
+
let body;
|
|
20389
|
+
try {
|
|
20390
|
+
body = await res.text();
|
|
20391
|
+
} catch (err) {
|
|
20392
|
+
return { kind: "unreachable", error: describeCause(err), reason: classifyUnreachable(err) };
|
|
20393
|
+
}
|
|
20394
|
+
let parsed;
|
|
20395
|
+
try {
|
|
20396
|
+
parsed = JSON.parse(body);
|
|
20397
|
+
} catch {
|
|
20398
|
+
return { kind: "not_api", status: res.status, snippet: body.trim().slice(0, 60) };
|
|
20399
|
+
}
|
|
20400
|
+
if (typeof parsed?.apiVersion !== "number") {
|
|
20401
|
+
return { kind: "not_api", status: res.status, snippet: body.trim().slice(0, 60) };
|
|
20402
|
+
}
|
|
20403
|
+
return {
|
|
20404
|
+
kind: "ok",
|
|
20405
|
+
apiVersion: parsed.apiVersion,
|
|
20406
|
+
edition: parsed.edition,
|
|
20407
|
+
cliVersion: parsed.cli?.version,
|
|
20408
|
+
raw: parsed
|
|
20409
|
+
};
|
|
20410
|
+
}
|
|
20411
|
+
function probeAdvice(r, base2) {
|
|
20412
|
+
switch (r.kind) {
|
|
20413
|
+
case "ok":
|
|
20414
|
+
return r.apiVersion >= 2 ? `apiVersion ${r.apiVersion}${r.edition ? `, edition ${r.edition}` : ""}` : `apiVersion ${r.apiVersion} is too old for this CLI \u2014 upgrade the server`;
|
|
20415
|
+
case "moved":
|
|
20416
|
+
return `HTTP ${r.status} \u2014 nothing is served at ${base2}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
|
|
20417
|
+
case "unauthorized":
|
|
20418
|
+
return `HTTP ${r.status} \u2014 ${base2} rejected the credential. Re-login: \`chat-recall login ` + base2 + "`";
|
|
20419
|
+
case "server_error":
|
|
20420
|
+
return `HTTP ${r.status} \u2014 ${base2} is up but failing. Nothing to fix locally; check the server.`;
|
|
20421
|
+
case "not_api":
|
|
20422
|
+
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`;
|
|
20423
|
+
case "unreachable":
|
|
20424
|
+
switch (r.reason) {
|
|
20425
|
+
case "dns":
|
|
20426
|
+
return `cannot resolve the host in ${base2} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
|
|
20427
|
+
case "refused":
|
|
20428
|
+
return `${base2} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
|
|
20429
|
+
case "tls":
|
|
20430
|
+
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.`;
|
|
20431
|
+
case "timeout":
|
|
20432
|
+
return `${base2} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
|
|
20433
|
+
case "reset":
|
|
20434
|
+
return `the connection to ${base2} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
|
|
20435
|
+
case "bad_port":
|
|
20436
|
+
return `${base2} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
|
|
20437
|
+
default:
|
|
20438
|
+
return `no HTTP response from ${base2} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
|
|
20439
|
+
}
|
|
20440
|
+
}
|
|
20441
|
+
}
|
|
20442
|
+
function classifyUnreachable(err) {
|
|
20443
|
+
if (err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError")) return "timeout";
|
|
20444
|
+
for (const e of walkErrorChain(err)) {
|
|
20445
|
+
const code2 = String(e.code ?? "");
|
|
20446
|
+
const msg = String(e.message ?? "");
|
|
20447
|
+
if (code2 === "ENOTFOUND" || code2 === "EAI_AGAIN") return "dns";
|
|
20448
|
+
if (code2 === "ECONNREFUSED") return "refused";
|
|
20449
|
+
if (code2 === "ECONNRESET" || code2 === "EPIPE") return "reset";
|
|
20450
|
+
if (code2 === "ETIMEDOUT" || code2 === "UND_ERR_CONNECT_TIMEOUT" || code2 === "UND_ERR_HEADERS_TIMEOUT") return "timeout";
|
|
20451
|
+
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";
|
|
20452
|
+
if (/^bad port$/i.test(msg)) return "bad_port";
|
|
20453
|
+
}
|
|
20454
|
+
return "unknown";
|
|
20455
|
+
}
|
|
20456
|
+
function* walkErrorChain(err, depth = 0) {
|
|
20457
|
+
if (!err || typeof err !== "object" || depth > 5) return;
|
|
20458
|
+
yield err;
|
|
20459
|
+
const members = err.errors;
|
|
20460
|
+
if (Array.isArray(members)) {
|
|
20461
|
+
for (const m of members) yield* walkErrorChain(m, depth + 1);
|
|
20462
|
+
}
|
|
20463
|
+
yield* walkErrorChain(err.cause, depth + 1);
|
|
20464
|
+
}
|
|
20465
|
+
function describeCause(err) {
|
|
20466
|
+
const parts = [];
|
|
20467
|
+
for (const e of walkErrorChain(err)) {
|
|
20468
|
+
const code2 = e.code;
|
|
20469
|
+
if (typeof code2 === "string" && code2 && !parts.includes(code2)) parts.push(code2);
|
|
20470
|
+
}
|
|
20471
|
+
const base2 = err instanceof Error ? err.message : String(err);
|
|
20472
|
+
return parts.length ? `${base2}: ${parts.join(" \u2192 ")}` : base2;
|
|
20473
|
+
}
|
|
20474
|
+
function describeUnreachable(err) {
|
|
20475
|
+
const reason = classifyUnreachable(err);
|
|
20476
|
+
const detail = describeCause(err);
|
|
20477
|
+
const phrase = {
|
|
20478
|
+
dns: "the host name does not resolve",
|
|
20479
|
+
refused: "the connection was refused \u2014 nothing is listening there",
|
|
20480
|
+
tls: "the TLS certificate was rejected",
|
|
20481
|
+
timeout: "no answer before the timeout",
|
|
20482
|
+
reset: "the connection was cut mid-request",
|
|
20483
|
+
bad_port: "that port is one Node and every browser refuse to open",
|
|
20484
|
+
unknown: "no HTTP response"
|
|
20485
|
+
};
|
|
20486
|
+
return `${phrase[reason]} (${detail})`;
|
|
20487
|
+
}
|
|
20488
|
+
var init_server_probe = __esm({
|
|
20489
|
+
"src/server-probe.ts"() {
|
|
20490
|
+
"use strict";
|
|
20491
|
+
}
|
|
20492
|
+
});
|
|
20493
|
+
|
|
20354
20494
|
// src/client-events.ts
|
|
20355
20495
|
var client_events_exports = {};
|
|
20356
20496
|
__export(client_events_exports, {
|
|
@@ -20758,6 +20898,7 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20758
20898
|
persistSyncConfig(base2, config2);
|
|
20759
20899
|
return config2;
|
|
20760
20900
|
} catch (err) {
|
|
20901
|
+
if (isSyncRulesRefusal(err)) throw err;
|
|
20761
20902
|
return lastKnownSyncConfig(base2, err instanceof Error ? err.message : "request failed");
|
|
20762
20903
|
}
|
|
20763
20904
|
}
|
|
@@ -20767,9 +20908,14 @@ function lastKnownSyncConfig(base2, reason) {
|
|
|
20767
20908
|
console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
|
|
20768
20909
|
return remembered.config;
|
|
20769
20910
|
}
|
|
20770
|
-
|
|
20911
|
+
const refusal = new Error(
|
|
20771
20912
|
`Cannot read the server-side sync rules from ${base2} (${reason}), and this machine has never successfully read them. Refusing to sync: uploading without knowing your exclusions could ship a project you told the dashboard to hold back. Fix the server or retry.`
|
|
20772
20913
|
);
|
|
20914
|
+
refusal[SYNC_RULES_REFUSAL] = true;
|
|
20915
|
+
throw refusal;
|
|
20916
|
+
}
|
|
20917
|
+
function isSyncRulesRefusal(err) {
|
|
20918
|
+
return !!err && typeof err === "object" && err[SYNC_RULES_REFUSAL] === true;
|
|
20773
20919
|
}
|
|
20774
20920
|
function deviceLabel() {
|
|
20775
20921
|
try {
|
|
@@ -21030,7 +21176,12 @@ async function verifyServerApi(serverUrl, minApi) {
|
|
|
21030
21176
|
const base2 = serverUrl.replace(/\/$/, "");
|
|
21031
21177
|
const seen = capsOk.get(base2);
|
|
21032
21178
|
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
21033
|
-
const
|
|
21179
|
+
const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
21180
|
+
const probe = await probeServer2(base2, {
|
|
21181
|
+
fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
|
|
21182
|
+
});
|
|
21183
|
+
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base2));
|
|
21184
|
+
const caps = probe.raw;
|
|
21034
21185
|
if ((caps.apiVersion ?? 0) < minApi) {
|
|
21035
21186
|
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
21036
21187
|
}
|
|
@@ -22020,7 +22171,7 @@ async function syncIncremental(opts = {}) {
|
|
|
22020
22171
|
lock.release();
|
|
22021
22172
|
}
|
|
22022
22173
|
}
|
|
22023
|
-
var ownVersion, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
22174
|
+
var ownVersion, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
22024
22175
|
var init_sync_client = __esm({
|
|
22025
22176
|
"src/sync-client.ts"() {
|
|
22026
22177
|
"use strict";
|
|
@@ -22066,7 +22217,7 @@ var init_sync_client = __esm({
|
|
|
22066
22217
|
ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22067
22218
|
} catch {
|
|
22068
22219
|
try {
|
|
22069
|
-
if (true) ownVersion = "0.5.
|
|
22220
|
+
if (true) ownVersion = "0.5.23";
|
|
22070
22221
|
} catch {
|
|
22071
22222
|
}
|
|
22072
22223
|
}
|
|
@@ -22078,6 +22229,7 @@ var init_sync_client = __esm({
|
|
|
22078
22229
|
_syncConfigCache = /* @__PURE__ */ new Map();
|
|
22079
22230
|
EMPTY_SYNC_CONFIG = { excludeTools: [], excludeProjects: [], excludeSources: [], approveSources: [] };
|
|
22080
22231
|
_fetchTenantSyncConfigForTests = fetchTenantSyncConfig;
|
|
22232
|
+
SYNC_RULES_REFUSAL = /* @__PURE__ */ Symbol.for("chat-recall.syncRulesRefusal");
|
|
22081
22233
|
hashPath = (p) => p ? "p_" + createHash13("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
22082
22234
|
MAX_DERIVED_ROW_BYTES = 2 * 1024 * 1024;
|
|
22083
22235
|
isLocalHost = isPrivateHost;
|
|
@@ -23502,7 +23654,7 @@ __export(toolkit_pull_exports, {
|
|
|
23502
23654
|
portableCommand: () => portableCommand
|
|
23503
23655
|
});
|
|
23504
23656
|
import { existsSync as existsSync48, mkdirSync as mkdirSync14, statSync as statSync42, writeFileSync as writeFileSync15 } from "node:fs";
|
|
23505
|
-
import {
|
|
23657
|
+
import { dirname as dirname22, join as join52, basename as basename25, isAbsolute as isAbsolute3 } from "node:path";
|
|
23506
23658
|
function isExecutableFile(p) {
|
|
23507
23659
|
try {
|
|
23508
23660
|
return statSync42(p).isFile();
|
|
@@ -23511,13 +23663,7 @@ function isExecutableFile(p) {
|
|
|
23511
23663
|
}
|
|
23512
23664
|
}
|
|
23513
23665
|
function onPath(name) {
|
|
23514
|
-
|
|
23515
|
-
for (const d of dirs) {
|
|
23516
|
-
const candidate = join52(d, name);
|
|
23517
|
-
if (isExecutableFile(candidate))
|
|
23518
|
-
return candidate;
|
|
23519
|
-
}
|
|
23520
|
-
return null;
|
|
23666
|
+
return resolveOnPath(name);
|
|
23521
23667
|
}
|
|
23522
23668
|
function portableCommand(cmd) {
|
|
23523
23669
|
if (!isAbsolute3(cmd)) {
|
|
@@ -23779,6 +23925,7 @@ var NOT_REBUILDABLE;
|
|
|
23779
23925
|
var init_toolkit_pull = __esm({
|
|
23780
23926
|
"../engine/dist/core/toolkit-pull.js"() {
|
|
23781
23927
|
"use strict";
|
|
23928
|
+
init_which();
|
|
23782
23929
|
init_toolkit_sync();
|
|
23783
23930
|
init_artifact_codec();
|
|
23784
23931
|
NOT_REBUILDABLE = {
|
|
@@ -24145,117 +24292,6 @@ var init_escalate = __esm({
|
|
|
24145
24292
|
}
|
|
24146
24293
|
});
|
|
24147
24294
|
|
|
24148
|
-
// src/server-probe.ts
|
|
24149
|
-
var server_probe_exports = {};
|
|
24150
|
-
__export(server_probe_exports, {
|
|
24151
|
-
classifyUnreachable: () => classifyUnreachable,
|
|
24152
|
-
describeCause: () => describeCause,
|
|
24153
|
-
probeAdvice: () => probeAdvice,
|
|
24154
|
-
probeOk: () => probeOk,
|
|
24155
|
-
probeServer: () => probeServer
|
|
24156
|
-
});
|
|
24157
|
-
function probeOk(r) {
|
|
24158
|
-
return r.kind === "ok" && r.apiVersion >= 2;
|
|
24159
|
-
}
|
|
24160
|
-
async function probeServer(base2, opts = {}) {
|
|
24161
|
-
const f = opts.fetchImpl || fetch;
|
|
24162
|
-
let res;
|
|
24163
|
-
try {
|
|
24164
|
-
res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
|
|
24165
|
-
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
24166
|
-
});
|
|
24167
|
-
} catch (err) {
|
|
24168
|
-
return {
|
|
24169
|
-
kind: "unreachable",
|
|
24170
|
-
error: describeCause(err),
|
|
24171
|
-
reason: classifyUnreachable(err)
|
|
24172
|
-
};
|
|
24173
|
-
}
|
|
24174
|
-
if (res.status === 401 || res.status === 403) return { kind: "unauthorized", status: res.status };
|
|
24175
|
-
if (res.status === 404 || res.status === 410) return { kind: "moved", status: res.status };
|
|
24176
|
-
if (res.status >= 500) return { kind: "server_error", status: res.status };
|
|
24177
|
-
if (!res.ok) return { kind: "moved", status: res.status };
|
|
24178
|
-
let body;
|
|
24179
|
-
try {
|
|
24180
|
-
body = await res.text();
|
|
24181
|
-
} catch (err) {
|
|
24182
|
-
return { kind: "unreachable", error: describeCause(err), reason: classifyUnreachable(err) };
|
|
24183
|
-
}
|
|
24184
|
-
let parsed;
|
|
24185
|
-
try {
|
|
24186
|
-
parsed = JSON.parse(body);
|
|
24187
|
-
} catch {
|
|
24188
|
-
return { kind: "not_api", status: res.status, snippet: body.trim().slice(0, 60) };
|
|
24189
|
-
}
|
|
24190
|
-
if (typeof parsed?.apiVersion !== "number") {
|
|
24191
|
-
return { kind: "not_api", status: res.status, snippet: body.trim().slice(0, 60) };
|
|
24192
|
-
}
|
|
24193
|
-
return {
|
|
24194
|
-
kind: "ok",
|
|
24195
|
-
apiVersion: parsed.apiVersion,
|
|
24196
|
-
edition: parsed.edition,
|
|
24197
|
-
cliVersion: parsed.cli?.version
|
|
24198
|
-
};
|
|
24199
|
-
}
|
|
24200
|
-
function probeAdvice(r, base2) {
|
|
24201
|
-
switch (r.kind) {
|
|
24202
|
-
case "ok":
|
|
24203
|
-
return r.apiVersion >= 2 ? `apiVersion ${r.apiVersion}${r.edition ? `, edition ${r.edition}` : ""}` : `apiVersion ${r.apiVersion} is too old for this CLI \u2014 upgrade the server`;
|
|
24204
|
-
case "moved":
|
|
24205
|
-
return `HTTP ${r.status} \u2014 nothing is served at ${base2}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
|
|
24206
|
-
case "unauthorized":
|
|
24207
|
-
return `HTTP ${r.status} \u2014 ${base2} rejected the credential. Re-login: \`chat-recall login ` + base2 + "`";
|
|
24208
|
-
case "server_error":
|
|
24209
|
-
return `HTTP ${r.status} \u2014 ${base2} is up but failing. Nothing to fix locally; check the server.`;
|
|
24210
|
-
case "not_api":
|
|
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`;
|
|
24212
|
-
case "unreachable":
|
|
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;
|
|
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;
|
|
24252
|
-
}
|
|
24253
|
-
var init_server_probe = __esm({
|
|
24254
|
-
"src/server-probe.ts"() {
|
|
24255
|
-
"use strict";
|
|
24256
|
-
}
|
|
24257
|
-
});
|
|
24258
|
-
|
|
24259
24295
|
// src/verify-deep.ts
|
|
24260
24296
|
var verify_deep_exports = {};
|
|
24261
24297
|
__export(verify_deep_exports, {
|
|
@@ -25836,7 +25872,7 @@ var init_intent_drain = __esm({
|
|
|
25836
25872
|
ownVersion2 = JSON.parse(readFileSync46(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25837
25873
|
} catch {
|
|
25838
25874
|
try {
|
|
25839
|
-
if (true) ownVersion2 = "0.5.
|
|
25875
|
+
if (true) ownVersion2 = "0.5.23";
|
|
25840
25876
|
} catch {
|
|
25841
25877
|
}
|
|
25842
25878
|
}
|
|
@@ -27111,6 +27147,24 @@ __export(device_auth_exports, {
|
|
|
27111
27147
|
deviceLogin: () => deviceLogin
|
|
27112
27148
|
});
|
|
27113
27149
|
import { createHash as createHash19, randomBytes } from "node:crypto";
|
|
27150
|
+
async function readDeviceCode(res, where) {
|
|
27151
|
+
const text = await res.text().catch(() => "");
|
|
27152
|
+
let parsed;
|
|
27153
|
+
try {
|
|
27154
|
+
parsed = JSON.parse(text);
|
|
27155
|
+
} catch {
|
|
27156
|
+
throw new Error(
|
|
27157
|
+
`${where} answered ${res.status} with something that is not a device-code response (${JSON.stringify(text.trim().slice(0, 60))}) \u2014 this host is not serving the chat-recall API`
|
|
27158
|
+
);
|
|
27159
|
+
}
|
|
27160
|
+
const d = parsed;
|
|
27161
|
+
if (typeof d?.device_code !== "string" || typeof d?.user_code !== "string" || typeof d?.verification_uri !== "string" || typeof d?.expires_in !== "number") {
|
|
27162
|
+
throw new Error(
|
|
27163
|
+
`${where} answered ${res.status} with JSON that is not a device-code response (${JSON.stringify(text.trim().slice(0, 60))}) \u2014 this host is not serving the chat-recall API`
|
|
27164
|
+
);
|
|
27165
|
+
}
|
|
27166
|
+
return d;
|
|
27167
|
+
}
|
|
27114
27168
|
async function deviceLogin(opts, onPrompt) {
|
|
27115
27169
|
const issuer = (opts.issuer || DEFAULT_ISSUER).replace(/\/+$/, "");
|
|
27116
27170
|
if (!issuer) {
|
|
@@ -27130,7 +27184,7 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
27130
27184
|
if (!startRes.ok) {
|
|
27131
27185
|
throw new Error(`device-auth init failed: HTTP ${startRes.status} ${await startRes.text().catch(() => "")}`);
|
|
27132
27186
|
}
|
|
27133
|
-
const start = await startRes
|
|
27187
|
+
const start = await readDeviceCode(startRes, issuer);
|
|
27134
27188
|
onPrompt({
|
|
27135
27189
|
url: start.verification_uri_complete || start.verification_uri,
|
|
27136
27190
|
userCode: start.user_code,
|
|
@@ -27184,7 +27238,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27184
27238
|
if (!startRes.ok) {
|
|
27185
27239
|
throw new Error(`device-auth init failed: HTTP ${startRes.status} ${await startRes.text().catch(() => "")}`);
|
|
27186
27240
|
}
|
|
27187
|
-
const start = await startRes
|
|
27241
|
+
const start = await readDeviceCode(startRes, base2);
|
|
27188
27242
|
onPrompt({
|
|
27189
27243
|
url: start.verification_uri_complete || start.verification_uri,
|
|
27190
27244
|
userCode: start.user_code,
|
|
@@ -27355,6 +27409,7 @@ function tierAll(results) {
|
|
|
27355
27409
|
// src/cli.ts
|
|
27356
27410
|
init_sync_client();
|
|
27357
27411
|
init_update_notice();
|
|
27412
|
+
init_server_probe();
|
|
27358
27413
|
init_which();
|
|
27359
27414
|
init_collector_health();
|
|
27360
27415
|
init_telemetry_consent();
|
|
@@ -27396,14 +27451,9 @@ function firstTarget() {
|
|
|
27396
27451
|
return { base: cred.serverUrl.replace(/\/+$/, ""), token: cred.token };
|
|
27397
27452
|
}
|
|
27398
27453
|
function describeProbeError(err) {
|
|
27399
|
-
const
|
|
27400
|
-
|
|
27401
|
-
|
|
27402
|
-
if (typeof code2 === "string" && code2 && !codes.includes(code2)) codes.push(code2);
|
|
27403
|
-
e = e.cause;
|
|
27404
|
-
}
|
|
27405
|
-
const base2 = err instanceof Error ? err.message : String(err);
|
|
27406
|
-
return codes.length ? `${base2}: ${codes.join(" \u2192 ")}` : base2;
|
|
27454
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27455
|
+
if (!/fetch failed|ECONN|ENOTFOUND|EAI_AGAIN|ETIMEDOUT|CERT_|aborted|timeout/i.test(msg)) return msg;
|
|
27456
|
+
return describeUnreachable(err);
|
|
27407
27457
|
}
|
|
27408
27458
|
function failLogin(opts, message) {
|
|
27409
27459
|
if (opts.fromInit) throw new Error(message);
|
|
@@ -27418,11 +27468,21 @@ function requireTarget() {
|
|
|
27418
27468
|
}
|
|
27419
27469
|
return t;
|
|
27420
27470
|
}
|
|
27471
|
+
async function readJsonBody(res, base2, what) {
|
|
27472
|
+
const text = await res.text().catch(() => "");
|
|
27473
|
+
try {
|
|
27474
|
+
return JSON.parse(text);
|
|
27475
|
+
} catch {
|
|
27476
|
+
throw new Error(
|
|
27477
|
+
`${base2} answered ${res.status} with something that is not JSON (${JSON.stringify(text.trim().slice(0, 60))}) for ${what} \u2014 a proxy, a captive portal or a host that no longer serves the chat-recall API`
|
|
27478
|
+
);
|
|
27479
|
+
}
|
|
27480
|
+
}
|
|
27421
27481
|
async function serverGet(path) {
|
|
27422
27482
|
const t = requireTarget();
|
|
27423
27483
|
const res = await fetch(t.base + path, { headers: t.token ? { authorization: `Bearer ${t.token}` } : {} });
|
|
27424
27484
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27425
|
-
return res.
|
|
27485
|
+
return readJsonBody(res, t.base, `GET ${path}`);
|
|
27426
27486
|
}
|
|
27427
27487
|
async function serverGetSoft(path) {
|
|
27428
27488
|
const t = requireTarget();
|
|
@@ -27432,7 +27492,7 @@ async function serverGetSoft(path) {
|
|
|
27432
27492
|
return { status: res.status, data: null, message: body.message };
|
|
27433
27493
|
}
|
|
27434
27494
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27435
|
-
return { status: res.status, data: await res.
|
|
27495
|
+
return { status: res.status, data: await readJsonBody(res, t.base, `GET ${path}`) };
|
|
27436
27496
|
}
|
|
27437
27497
|
async function serverPost(path, body) {
|
|
27438
27498
|
const t = requireTarget();
|
|
@@ -27442,7 +27502,7 @@ async function serverPost(path, body) {
|
|
|
27442
27502
|
body: JSON.stringify(body)
|
|
27443
27503
|
});
|
|
27444
27504
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27445
|
-
return res.
|
|
27505
|
+
return readJsonBody(res, t.base, `POST ${path}`);
|
|
27446
27506
|
}
|
|
27447
27507
|
async function serverPatch(path, body) {
|
|
27448
27508
|
const t = requireTarget();
|
|
@@ -27452,7 +27512,7 @@ async function serverPatch(path, body) {
|
|
|
27452
27512
|
body: JSON.stringify(body)
|
|
27453
27513
|
});
|
|
27454
27514
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27455
|
-
return res.
|
|
27515
|
+
return readJsonBody(res, t.base, `PATCH ${path}`);
|
|
27456
27516
|
}
|
|
27457
27517
|
async function serverDelete(path, body) {
|
|
27458
27518
|
const t = requireTarget();
|
|
@@ -27462,7 +27522,7 @@ async function serverDelete(path, body) {
|
|
|
27462
27522
|
body: JSON.stringify(body)
|
|
27463
27523
|
});
|
|
27464
27524
|
if (!res.ok) throw new Error(`server ${path}: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
27465
|
-
return res.
|
|
27525
|
+
return readJsonBody(res, t.base, `DELETE ${path}`);
|
|
27466
27526
|
}
|
|
27467
27527
|
var pkgEngines = (() => {
|
|
27468
27528
|
try {
|
|
@@ -27474,7 +27534,7 @@ var pkgEngines = (() => {
|
|
|
27474
27534
|
var pkgVersion = JSON.parse(
|
|
27475
27535
|
readFileSync49(new URL("../package.json", import.meta.url), "utf-8")
|
|
27476
27536
|
).version;
|
|
27477
|
-
var DEFAULT_SERVER = "https://chatrecall.dev";
|
|
27537
|
+
var DEFAULT_SERVER = (process.env.CHAT_RECALL_DEFAULT_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
|
|
27478
27538
|
var DEFAULT_ALLOW = [
|
|
27479
27539
|
"recall_search",
|
|
27480
27540
|
"recall_show",
|
|
@@ -27586,6 +27646,7 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27586
27646
|
console.log();
|
|
27587
27647
|
console.log(chalk.bold("2. Connecting to your server..."));
|
|
27588
27648
|
let target = firstTarget();
|
|
27649
|
+
let deadTarget = false;
|
|
27589
27650
|
if (options.server) {
|
|
27590
27651
|
try {
|
|
27591
27652
|
await runLogin(options.server, { token: options.token, fromInit: true, promptJson: options.promptJson });
|
|
@@ -27605,7 +27666,34 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27605
27666
|
console.log(` ${chalk.dim(`Run ${chalk.bold("chat-recall login <server-url>")} when ready, or self-host: ${SELF_HOST_DOCS}`)}`);
|
|
27606
27667
|
}
|
|
27607
27668
|
}
|
|
27608
|
-
if (target) {
|
|
27669
|
+
if (target && !options.server) {
|
|
27670
|
+
const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
27671
|
+
const probe = await probeServer2(target.base, { timeoutMs: 1e4 });
|
|
27672
|
+
if (probeOk2(probe)) {
|
|
27673
|
+
console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
|
|
27674
|
+
} else if (probe.kind === "moved" || probe.kind === "not_api") {
|
|
27675
|
+
const retired = target.base;
|
|
27676
|
+
console.log(` ${chalk.yellow("The saved server no longer serves chat-recall")} \u2192 ${retired}`);
|
|
27677
|
+
console.log(` ${probeAdvice2(probe, retired)}`);
|
|
27678
|
+
console.log(` Switching to ${chalk.bold(DEFAULT_SERVER)} \u2014 sign in to approve this machine.`);
|
|
27679
|
+
try {
|
|
27680
|
+
await runLogin(DEFAULT_SERVER, { token: options.token, fromInit: true, promptJson: options.promptJson });
|
|
27681
|
+
const { removeCredentials: removeCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
27682
|
+
if (removeCredentials2(retired)) {
|
|
27683
|
+
console.log(` ${chalk.dim(`Removed the retired target ${retired} (log in there again any time).`)}`);
|
|
27684
|
+
}
|
|
27685
|
+
target = firstTarget();
|
|
27686
|
+
if (target) console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
|
|
27687
|
+
} catch (e) {
|
|
27688
|
+
console.log(` ${chalk.yellow("Not connected.")} ${describeProbeError(e)}`);
|
|
27689
|
+
console.log(` ${chalk.dim(`Run ${chalk.bold(`chat-recall login ${DEFAULT_SERVER}`)} when ready, then ${chalk.bold(`chat-recall logout ${retired}`)}.`)}`);
|
|
27690
|
+
deadTarget = true;
|
|
27691
|
+
}
|
|
27692
|
+
} else {
|
|
27693
|
+
console.log(` ${chalk.yellow("Saved server did not answer")} \u2192 ${target.base}`);
|
|
27694
|
+
console.log(` ${probeAdvice2(probe, target.base)}`);
|
|
27695
|
+
}
|
|
27696
|
+
} else if (target) {
|
|
27609
27697
|
console.log(` ${chalk.green("Connected")} \u2192 ${target.base}`);
|
|
27610
27698
|
}
|
|
27611
27699
|
console.log();
|
|
@@ -27714,22 +27802,40 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27714
27802
|
const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
|
|
27715
27803
|
const { hostname: hostname3 } = await import("node:os");
|
|
27716
27804
|
const rows = [];
|
|
27805
|
+
let answered = 0;
|
|
27806
|
+
const askFailed = [];
|
|
27717
27807
|
for (const t of loadAllCredentials2()) {
|
|
27718
27808
|
try {
|
|
27719
27809
|
const res = await fetch(`${t.serverUrl}/api/toolkit/browse/mcp?limit=1000`, {
|
|
27720
27810
|
headers: t.token ? { authorization: `Bearer ${t.token}` } : {},
|
|
27721
27811
|
signal: AbortSignal.timeout(2e4)
|
|
27722
27812
|
});
|
|
27723
|
-
if (!res.ok)
|
|
27724
|
-
|
|
27813
|
+
if (!res.ok) {
|
|
27814
|
+
askFailed.push(`${t.serverUrl} (HTTP ${res.status})`);
|
|
27815
|
+
continue;
|
|
27816
|
+
}
|
|
27817
|
+
const text = await res.text();
|
|
27818
|
+
let body;
|
|
27819
|
+
try {
|
|
27820
|
+
body = JSON.parse(text);
|
|
27821
|
+
} catch {
|
|
27822
|
+
askFailed.push(`${t.serverUrl} (not JSON: ${JSON.stringify(text.trim().slice(0, 40))})`);
|
|
27823
|
+
continue;
|
|
27824
|
+
}
|
|
27825
|
+
answered++;
|
|
27725
27826
|
for (const it of body.items || []) rows.push(it);
|
|
27726
|
-
} catch {
|
|
27827
|
+
} catch (e) {
|
|
27828
|
+
askFailed.push(`${t.serverUrl} (${describeProbeError(e)})`);
|
|
27727
27829
|
}
|
|
27728
27830
|
}
|
|
27729
27831
|
const report = executePull2(rows, { thisDeviceId: hostname3(), types: ["mcp"] });
|
|
27730
27832
|
const written = report.outcomes.filter((o) => o.status === "written");
|
|
27731
27833
|
const present = report.outcomes.filter((o) => o.status === "present").length;
|
|
27732
|
-
if (
|
|
27834
|
+
if (answered === 0) {
|
|
27835
|
+
console.log(` ${chalk.yellow("Could not ask your server what MCP servers are on your account")}`);
|
|
27836
|
+
for (const f of askFailed) console.log(` ${chalk.dim(f)}`);
|
|
27837
|
+
console.log(` ${chalk.dim("Re-run `chat-recall toolkit pull` once the server answers.")}`);
|
|
27838
|
+
} else if (written.length === 0 && present === 0) {
|
|
27733
27839
|
console.log(chalk.dim(" Nothing on your account to install yet."));
|
|
27734
27840
|
} else {
|
|
27735
27841
|
console.log(` ${chalk.green(`Installed ${written.length}`)} ${chalk.dim(`(${present} already present)`)}`);
|
|
@@ -27744,7 +27850,10 @@ program.command("init").description("Set up chat-recall: connect to your server,
|
|
|
27744
27850
|
}
|
|
27745
27851
|
console.log();
|
|
27746
27852
|
}
|
|
27747
|
-
if (
|
|
27853
|
+
if (deadTarget) {
|
|
27854
|
+
console.log(chalk.bold("5. Skipping first sync \u2014 the saved server is not serving chat-recall"));
|
|
27855
|
+
console.log(` ${chalk.dim(`Re-point with the two commands above, then run ${chalk.bold("chat-recall sync")}.`)}`);
|
|
27856
|
+
} else if (!options.skipSync && firstTarget()) {
|
|
27748
27857
|
console.log(chalk.bold("5. Indexing and uploading your sessions"));
|
|
27749
27858
|
try {
|
|
27750
27859
|
const { syncSessions: syncSessions2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
@@ -29602,7 +29711,7 @@ async function runLogin(serverUrl, opts) {
|
|
|
29602
29711
|
});
|
|
29603
29712
|
return { ok: res.ok, status: res.status };
|
|
29604
29713
|
} catch (err) {
|
|
29605
|
-
return { ok: false, error:
|
|
29714
|
+
return { ok: false, error: describeUnreachable(err) };
|
|
29606
29715
|
}
|
|
29607
29716
|
};
|
|
29608
29717
|
if (opts.token) {
|
|
@@ -29611,12 +29720,21 @@ async function runLogin(serverUrl, opts) {
|
|
|
29611
29720
|
console.error(chalk.dim("Use the Copy button next to the token in the dashboard and paste the full line."));
|
|
29612
29721
|
return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
|
|
29613
29722
|
}
|
|
29723
|
+
const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
29724
|
+
const who = await identifyServer(base2, { timeoutMs: 1e4 });
|
|
29725
|
+
if (!identified(who)) return failLogin(opts, identifyAdvice(who, base2));
|
|
29614
29726
|
const check = await verifyToken(token);
|
|
29615
29727
|
if (!check.ok) {
|
|
29616
29728
|
if (check.status === 401 || check.status === 403) {
|
|
29617
29729
|
console.error(chalk.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
|
|
29618
29730
|
return failLogin(opts, `${base2} rejected the token (HTTP ${check.status})`);
|
|
29619
29731
|
}
|
|
29732
|
+
if (check.status !== void 0 && check.status >= 500) {
|
|
29733
|
+
return failLogin(opts, `${base2} answered HTTP ${check.status} \u2014 the server is up but failing. The token was never checked. Nothing to fix locally.`);
|
|
29734
|
+
}
|
|
29735
|
+
if (check.status === 404 || check.status === 410) {
|
|
29736
|
+
return failLogin(opts, `${base2} does not serve the chat-recall API (HTTP ${check.status}). If the server moved, log in to its new URL.`);
|
|
29737
|
+
}
|
|
29620
29738
|
return failLogin(opts, `could not verify the token against ${base2}: ${check.error || `HTTP ${check.status}`}`);
|
|
29621
29739
|
}
|
|
29622
29740
|
saveCredentials2({ serverUrl, token });
|
|
@@ -29629,11 +29747,15 @@ async function runLogin(serverUrl, opts) {
|
|
|
29629
29747
|
return;
|
|
29630
29748
|
}
|
|
29631
29749
|
try {
|
|
29632
|
-
const
|
|
29633
|
-
|
|
29634
|
-
|
|
29635
|
-
|
|
29636
|
-
|
|
29750
|
+
const { probeServer: probeServer2, probeOk: probeOk2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
29751
|
+
const identified = await probeServer2(base2, { timeoutMs: 8e3 });
|
|
29752
|
+
if (probeOk2(identified)) {
|
|
29753
|
+
const probe = await fetch(`${base2}/api/status`, { signal: AbortSignal.timeout(8e3) });
|
|
29754
|
+
if (probe.status === 200) {
|
|
29755
|
+
saveCredentials2({ serverUrl, token: "" });
|
|
29756
|
+
console.log(chalk.green("\u2713 Logged in.") + chalk.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
|
|
29757
|
+
return;
|
|
29758
|
+
}
|
|
29637
29759
|
}
|
|
29638
29760
|
} catch {
|
|
29639
29761
|
}
|
|
@@ -29651,14 +29773,12 @@ async function runLogin(serverUrl, opts) {
|
|
|
29651
29773
|
for (let attempt = 1; attempt <= 3 && !authProvider; attempt++) {
|
|
29652
29774
|
const probe = await probeServer2(base2, { timeoutMs: 15e3 });
|
|
29653
29775
|
if (probeOk2(probe)) {
|
|
29654
|
-
|
|
29655
|
-
|
|
29656
|
-
|
|
29657
|
-
|
|
29658
|
-
|
|
29659
|
-
|
|
29660
|
-
capsError = describeProbeError(err);
|
|
29661
|
-
}
|
|
29776
|
+
const caps = probe.raw;
|
|
29777
|
+
authProvider = caps?.authProvider;
|
|
29778
|
+
if (caps?.oidcIssuer) issuer = caps.oidcIssuer;
|
|
29779
|
+
capsError = null;
|
|
29780
|
+
} else if (probe.kind === "moved" || probe.kind === "not_api") {
|
|
29781
|
+
return failLogin(opts, probeAdvice2(probe, base2));
|
|
29662
29782
|
} else {
|
|
29663
29783
|
capsError = probeAdvice2(probe, base2);
|
|
29664
29784
|
}
|
|
@@ -29691,7 +29811,9 @@ async function runLogin(serverUrl, opts) {
|
|
|
29691
29811
|
};
|
|
29692
29812
|
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base2, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
|
|
29693
29813
|
const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
|
|
29694
|
-
const
|
|
29814
|
+
const meRes = await fetch(`${base2}/api/me`, { headers: authHdr });
|
|
29815
|
+
if (!meRes.ok) throw new Error(`${base2}/api/me: HTTP ${meRes.status} ${await meRes.text().catch(() => "")}`);
|
|
29816
|
+
const me = await readJsonBody(meRes, base2, "GET /api/me");
|
|
29695
29817
|
const teams = me.teams || [];
|
|
29696
29818
|
let slug = opts.team;
|
|
29697
29819
|
if (!slug) {
|
|
@@ -29700,7 +29822,7 @@ async function runLogin(serverUrl, opts) {
|
|
|
29700
29822
|
const name = me.user?.email?.split("@")[0]?.replace(/[^a-z0-9]/gi, "") || "workspace";
|
|
29701
29823
|
const created = await fetch(`${base2}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
|
|
29702
29824
|
if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
|
|
29703
|
-
slug = (await created
|
|
29825
|
+
slug = (await readJsonBody(created, base2, "POST /api/teams")).slug;
|
|
29704
29826
|
console.log(chalk.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
|
|
29705
29827
|
} else {
|
|
29706
29828
|
teams.forEach((t) => console.error(` ${t.team_slug} ${chalk.dim(t.name)}`));
|
|
@@ -29714,7 +29836,7 @@ async function runLogin(serverUrl, opts) {
|
|
|
29714
29836
|
body: JSON.stringify({ device_id: deviceId })
|
|
29715
29837
|
});
|
|
29716
29838
|
if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
|
|
29717
|
-
const { token } = await mint
|
|
29839
|
+
const { token } = await readJsonBody(mint, base2, "POST /api/teams/:slug/tokens");
|
|
29718
29840
|
saveCredentials2({ serverUrl, token });
|
|
29719
29841
|
console.log(chalk.green(`\u2713 Logged in to ${chalk.bold(slug)}`) + chalk.dim(` (device: ${deviceId}) server: ${serverUrl}`));
|
|
29720
29842
|
if (!opts.fromInit) {
|