chat-recall 0.7.14 → 0.7.15
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 +348 -283
- package/dist/hostile-server.d.ts.map +1 -1
- package/dist/hostile-server.js +10 -1
- package/dist/hostile-server.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +255 -190
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +112 -17
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +297 -230
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -4259,7 +4259,7 @@ var require_pino = __commonJS({
|
|
|
4259
4259
|
messageKey,
|
|
4260
4260
|
errorKey,
|
|
4261
4261
|
nestedKey,
|
|
4262
|
-
base,
|
|
4262
|
+
base: base2,
|
|
4263
4263
|
name,
|
|
4264
4264
|
level: level2,
|
|
4265
4265
|
customLevels,
|
|
@@ -4298,11 +4298,11 @@ var require_pino = __commonJS({
|
|
|
4298
4298
|
[formattersSym]: allFormatters
|
|
4299
4299
|
});
|
|
4300
4300
|
let chindings = "";
|
|
4301
|
-
if (
|
|
4301
|
+
if (base2 !== null) {
|
|
4302
4302
|
if (name === void 0) {
|
|
4303
|
-
chindings = coreChindings(
|
|
4303
|
+
chindings = coreChindings(base2);
|
|
4304
4304
|
} else {
|
|
4305
|
-
chindings = coreChindings(Object.assign({},
|
|
4305
|
+
chindings = coreChindings(Object.assign({}, base2, { name }));
|
|
4306
4306
|
}
|
|
4307
4307
|
}
|
|
4308
4308
|
const time2 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime;
|
|
@@ -5271,57 +5271,57 @@ function freshDefaults() {
|
|
|
5271
5271
|
team: defaultTeam()
|
|
5272
5272
|
};
|
|
5273
5273
|
}
|
|
5274
|
-
function mergeSources(
|
|
5274
|
+
function mergeSources(base2, partial) {
|
|
5275
5275
|
if (!partial)
|
|
5276
|
-
return
|
|
5276
|
+
return base2;
|
|
5277
5277
|
const legacyGemini = partial.enabled?.gemini;
|
|
5278
5278
|
const inherited = legacyGemini && typeof legacyGemini === "object" ? (({ sessions: _s, plans: _p, ...rest }) => rest)(legacyGemini) : {};
|
|
5279
5279
|
const enabled = {
|
|
5280
|
-
claude: { ...
|
|
5281
|
-
opencode: { ...
|
|
5282
|
-
codex: { ...
|
|
5283
|
-
agy: { ...
|
|
5284
|
-
cursor: { ...
|
|
5285
|
-
shared: { ...
|
|
5286
|
-
common: { ...
|
|
5280
|
+
claude: { ...base2.enabled.claude, ...partial.enabled?.claude ?? {} },
|
|
5281
|
+
opencode: { ...base2.enabled.opencode, ...partial.enabled?.opencode ?? {} },
|
|
5282
|
+
codex: { ...base2.enabled.codex, ...partial.enabled?.codex ?? {} },
|
|
5283
|
+
agy: { ...base2.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
|
|
5284
|
+
cursor: { ...base2.enabled.cursor, ...partial.enabled?.cursor ?? {} },
|
|
5285
|
+
shared: { ...base2.enabled.shared, ...partial.enabled?.shared ?? {} },
|
|
5286
|
+
common: { ...base2.enabled.common, ...partial.enabled?.common ?? {} }
|
|
5287
5287
|
};
|
|
5288
5288
|
return {
|
|
5289
|
-
claudeHome: partial.claudeHome ??
|
|
5290
|
-
geminiHome: partial.geminiHome ??
|
|
5291
|
-
codexHome: partial.codexHome ??
|
|
5292
|
-
opencodeDbPath: partial.opencodeDbPath ??
|
|
5293
|
-
agyHome: partial.agyHome ??
|
|
5294
|
-
cursorHome: partial.cursorHome ??
|
|
5295
|
-
cursorIdeHome: partial.cursorIdeHome ??
|
|
5296
|
-
extraClaudeHomes: partial.extraClaudeHomes ??
|
|
5297
|
-
approvedHomes: partial.approvedHomes ??
|
|
5298
|
-
declinedHomes: partial.declinedHomes ??
|
|
5299
|
-
homesGrandfathered: partial.homesGrandfathered ??
|
|
5289
|
+
claudeHome: partial.claudeHome ?? base2.claudeHome,
|
|
5290
|
+
geminiHome: partial.geminiHome ?? base2.geminiHome,
|
|
5291
|
+
codexHome: partial.codexHome ?? base2.codexHome,
|
|
5292
|
+
opencodeDbPath: partial.opencodeDbPath ?? base2.opencodeDbPath,
|
|
5293
|
+
agyHome: partial.agyHome ?? base2.agyHome,
|
|
5294
|
+
cursorHome: partial.cursorHome ?? base2.cursorHome,
|
|
5295
|
+
cursorIdeHome: partial.cursorIdeHome ?? base2.cursorIdeHome,
|
|
5296
|
+
extraClaudeHomes: partial.extraClaudeHomes ?? base2.extraClaudeHomes,
|
|
5297
|
+
approvedHomes: partial.approvedHomes ?? base2.approvedHomes,
|
|
5298
|
+
declinedHomes: partial.declinedHomes ?? base2.declinedHomes,
|
|
5299
|
+
homesGrandfathered: partial.homesGrandfathered ?? base2.homesGrandfathered,
|
|
5300
5300
|
enabled
|
|
5301
5301
|
};
|
|
5302
5302
|
}
|
|
5303
|
-
function mergePrivacy(
|
|
5303
|
+
function mergePrivacy(base2, partial) {
|
|
5304
5304
|
if (!partial)
|
|
5305
|
-
return
|
|
5306
|
-
return { ...
|
|
5305
|
+
return base2;
|
|
5306
|
+
return { ...base2, ...partial };
|
|
5307
5307
|
}
|
|
5308
|
-
function mergeSync(
|
|
5308
|
+
function mergeSync(base2, partial) {
|
|
5309
5309
|
if (!partial)
|
|
5310
|
-
return
|
|
5310
|
+
return base2;
|
|
5311
5311
|
return {
|
|
5312
|
-
...
|
|
5312
|
+
...base2,
|
|
5313
5313
|
...partial,
|
|
5314
|
-
upload: { ...
|
|
5314
|
+
upload: { ...base2.upload, ...partial.upload ?? {} }
|
|
5315
5315
|
};
|
|
5316
5316
|
}
|
|
5317
|
-
function mergeTeam(
|
|
5317
|
+
function mergeTeam(base2, partial) {
|
|
5318
5318
|
if (!partial)
|
|
5319
|
-
return
|
|
5319
|
+
return base2;
|
|
5320
5320
|
return {
|
|
5321
|
-
...
|
|
5321
|
+
...base2,
|
|
5322
5322
|
...partial,
|
|
5323
|
-
publishAllowed: { ...
|
|
5324
|
-
vault: { ...
|
|
5323
|
+
publishAllowed: { ...base2.publishAllowed, ...partial.publishAllowed ?? {} },
|
|
5324
|
+
vault: { ...base2.vault, ...partial.vault ?? {} }
|
|
5325
5325
|
};
|
|
5326
5326
|
}
|
|
5327
5327
|
function settingsFilePath() {
|
|
@@ -5439,15 +5439,15 @@ function loadSettings() {
|
|
|
5439
5439
|
}
|
|
5440
5440
|
try {
|
|
5441
5441
|
const parsed = JSON.parse(readFileSync3(path2, "utf-8"));
|
|
5442
|
-
const
|
|
5442
|
+
const base2 = freshDefaults();
|
|
5443
5443
|
const result = {
|
|
5444
5444
|
v: SCHEMA_VERSION,
|
|
5445
|
-
embedding: { ...
|
|
5446
|
-
summary: { ...
|
|
5447
|
-
sources: mergeSources(
|
|
5448
|
-
privacy: mergePrivacy(
|
|
5449
|
-
sync: mergeSync(
|
|
5450
|
-
team: mergeTeam(
|
|
5445
|
+
embedding: { ...base2.embedding, ...parsed.embedding ?? {} },
|
|
5446
|
+
summary: { ...base2.summary, ...parsed.summary ?? {} },
|
|
5447
|
+
sources: mergeSources(base2.sources, parsed.sources),
|
|
5448
|
+
privacy: mergePrivacy(base2.privacy, parsed.privacy),
|
|
5449
|
+
sync: mergeSync(base2.sync, parsed.sync),
|
|
5450
|
+
team: mergeTeam(base2.team, parsed.team)
|
|
5451
5451
|
};
|
|
5452
5452
|
if (mtimeMs >= 0)
|
|
5453
5453
|
_settingsCache = { mtimeMs, size, value: structuredClone(result) };
|
|
@@ -5643,10 +5643,10 @@ function legacyAutoSyncedHomes() {
|
|
|
5643
5643
|
{ base: join6(home, ".local", "share", "opencode"), marker: "opencode.db" },
|
|
5644
5644
|
{ base: join6(home, ".cursor"), marker: "chats" }
|
|
5645
5645
|
];
|
|
5646
|
-
for (const { base, marker } of bases) {
|
|
5647
|
-
add(
|
|
5648
|
-
const parent = dirname5(
|
|
5649
|
-
const leaf =
|
|
5646
|
+
for (const { base: base2, marker } of bases) {
|
|
5647
|
+
add(base2, marker);
|
|
5648
|
+
const parent = dirname5(base2);
|
|
5649
|
+
const leaf = base2.slice(parent.length + 1);
|
|
5650
5650
|
try {
|
|
5651
5651
|
for (const e of readdirSync4(parent, { withFileTypes: true })) {
|
|
5652
5652
|
if (!e.isDirectory())
|
|
@@ -5827,17 +5827,17 @@ function cursorHomeDir() {
|
|
|
5827
5827
|
function cursorIdeHomeDir() {
|
|
5828
5828
|
return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join7(homedir3(), "Library", "Application Support", "Cursor") : join7(homedir3(), ".config", "Cursor"));
|
|
5829
5829
|
}
|
|
5830
|
-
function siblingHomes(
|
|
5830
|
+
function siblingHomes(base2, overridden, suffix) {
|
|
5831
5831
|
const roots = [];
|
|
5832
5832
|
const add = (home) => {
|
|
5833
5833
|
const root = suffix ? join7(home, suffix) : home;
|
|
5834
5834
|
if (existsSync5(root) && !roots.includes(root))
|
|
5835
5835
|
roots.push(root);
|
|
5836
5836
|
};
|
|
5837
|
-
add(
|
|
5837
|
+
add(base2);
|
|
5838
5838
|
if (!overridden) {
|
|
5839
|
-
const parent = dirname6(
|
|
5840
|
-
const leaf = basename3(
|
|
5839
|
+
const parent = dirname6(base2);
|
|
5840
|
+
const leaf = basename3(base2);
|
|
5841
5841
|
try {
|
|
5842
5842
|
for (const entry of readdirSync5(parent, { withFileTypes: true })) {
|
|
5843
5843
|
if (!entry.isDirectory())
|
|
@@ -11019,9 +11019,9 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
11019
11019
|
content.metadata.durationMs += obj.durationMs;
|
|
11020
11020
|
}
|
|
11021
11021
|
if (msgType === "file-history-snapshot") {
|
|
11022
|
-
const
|
|
11023
|
-
if (
|
|
11024
|
-
const backups =
|
|
11022
|
+
const snapshot2 = obj.snapshot;
|
|
11023
|
+
if (snapshot2 && typeof snapshot2 === "object") {
|
|
11024
|
+
const backups = snapshot2.trackedFileBackups;
|
|
11025
11025
|
if (backups && typeof backups === "object") {
|
|
11026
11026
|
for (const filePath2 of Object.keys(backups)) {
|
|
11027
11027
|
filesModified.add(filePath2);
|
|
@@ -13290,8 +13290,8 @@ function serverRulePackVersion() {
|
|
|
13290
13290
|
return serverPack ? serverPack.version || "unversioned" : null;
|
|
13291
13291
|
}
|
|
13292
13292
|
function activeRules() {
|
|
13293
|
-
const
|
|
13294
|
-
return serverPack && serverPack.rules.length > 0 ? [...
|
|
13293
|
+
const base2 = settingsView().rules;
|
|
13294
|
+
return serverPack && serverPack.rules.length > 0 ? [...base2, ...serverPack.rules] : base2;
|
|
13295
13295
|
}
|
|
13296
13296
|
function isRedactionEnabled() {
|
|
13297
13297
|
const env = isEnvRedactionRequested();
|
|
@@ -14154,17 +14154,17 @@ async function collectCode(opts) {
|
|
|
14154
14154
|
return r;
|
|
14155
14155
|
};
|
|
14156
14156
|
log6(`indexing ${ws} + analyses \u2026`);
|
|
14157
|
-
const
|
|
14157
|
+
const base2 = await runMcp(bin, ws, [
|
|
14158
14158
|
call(1, "index_workspace", { path: ws }),
|
|
14159
14159
|
call(2, "status"),
|
|
14160
14160
|
call(3, "get_tree"),
|
|
14161
14161
|
...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
|
|
14162
14162
|
]);
|
|
14163
|
-
const st = parseJson(
|
|
14164
|
-
const tree = parseJson(
|
|
14163
|
+
const st = parseJson(base2, 2, {});
|
|
14164
|
+
const tree = parseJson(base2, 3, []);
|
|
14165
14165
|
const A = {};
|
|
14166
14166
|
ANALYSES.forEach((a, i) => {
|
|
14167
|
-
A[a] = parseJson(
|
|
14167
|
+
A[a] = parseJson(base2, 10 + i, {});
|
|
14168
14168
|
});
|
|
14169
14169
|
const { health, security: sec, duplication: dup, clones, literal_scan: lit, coupling: coup, cycles: cyc, dead_code: dead, unwrap_audit: unwrap, test_coverage: coverage, architecture: arch, crossref, type_drift: typeDrift, db_schema: dbSchema, migration_parity: migParity, manifest_compliance: manifest } = A;
|
|
14170
14170
|
if (tree.length === 0) {
|
|
@@ -19452,38 +19452,100 @@ var init_extractor_version = __esm({
|
|
|
19452
19452
|
});
|
|
19453
19453
|
|
|
19454
19454
|
// src/sync-ledger.ts
|
|
19455
|
-
import { readFileSync as readFileSync34, writeFileSync as writeFileSync7, renameSync as renameSync5, mkdirSync as mkdirSync10 } from "node:fs";
|
|
19455
|
+
import { readFileSync as readFileSync34, writeFileSync as writeFileSync7, renameSync as renameSync5, mkdirSync as mkdirSync10, statSync as statSync40 } from "node:fs";
|
|
19456
19456
|
import { join as join46, dirname as dirname17 } from "node:path";
|
|
19457
19457
|
function toRow(entry) {
|
|
19458
19458
|
if (entry === void 0) return void 0;
|
|
19459
19459
|
return typeof entry === "number" ? { m: entry, v: 0 } : entry;
|
|
19460
19460
|
}
|
|
19461
|
-
function
|
|
19462
|
-
|
|
19461
|
+
function stampOf(path2) {
|
|
19462
|
+
try {
|
|
19463
|
+
const st = statSync40(path2);
|
|
19464
|
+
return `${st.mtimeMs}:${st.size}`;
|
|
19465
|
+
} catch {
|
|
19466
|
+
return null;
|
|
19467
|
+
}
|
|
19468
|
+
}
|
|
19469
|
+
function readDisk(path2) {
|
|
19463
19470
|
try {
|
|
19464
|
-
const parsed = JSON.parse(readFileSync34(
|
|
19465
|
-
|
|
19471
|
+
const parsed = JSON.parse(readFileSync34(path2, "utf-8"));
|
|
19472
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
19466
19473
|
} catch {
|
|
19467
|
-
|
|
19474
|
+
return {};
|
|
19475
|
+
}
|
|
19476
|
+
}
|
|
19477
|
+
function snapshot(data) {
|
|
19478
|
+
const out = /* @__PURE__ */ new Map();
|
|
19479
|
+
for (const [server, rows] of Object.entries(data)) {
|
|
19480
|
+
for (const [id, entry] of Object.entries(rows)) out.set(rowKey(server, id), JSON.stringify(entry));
|
|
19481
|
+
}
|
|
19482
|
+
return out;
|
|
19483
|
+
}
|
|
19484
|
+
function mergeOnto(disk) {
|
|
19485
|
+
const out = {};
|
|
19486
|
+
const put = (server, id, entry) => {
|
|
19487
|
+
(out[server] ??= {})[id] = entry;
|
|
19488
|
+
};
|
|
19489
|
+
const mine = cache3 ?? {};
|
|
19490
|
+
for (const [server, rows] of Object.entries(disk)) {
|
|
19491
|
+
for (const [id, entry] of Object.entries(rows)) {
|
|
19492
|
+
const k = rowKey(server, id);
|
|
19493
|
+
const own = mine[server]?.[id];
|
|
19494
|
+
const was = base.get(k);
|
|
19495
|
+
if (own === void 0) {
|
|
19496
|
+
if (was === void 0) put(server, id, entry);
|
|
19497
|
+
} else {
|
|
19498
|
+
put(server, id, JSON.stringify(own) === was ? entry : own);
|
|
19499
|
+
}
|
|
19500
|
+
}
|
|
19501
|
+
}
|
|
19502
|
+
for (const [server, rows] of Object.entries(mine)) {
|
|
19503
|
+
for (const [id, entry] of Object.entries(rows)) {
|
|
19504
|
+
if (disk[server]?.[id] !== void 0) continue;
|
|
19505
|
+
if (JSON.stringify(entry) !== base.get(rowKey(server, id))) put(server, id, entry);
|
|
19506
|
+
}
|
|
19468
19507
|
}
|
|
19508
|
+
return out;
|
|
19509
|
+
}
|
|
19510
|
+
function load() {
|
|
19511
|
+
const path2 = ledgerPath();
|
|
19512
|
+
const stamp = stampOf(path2);
|
|
19513
|
+
if (cache3 && stamp === diskStamp) return cache3;
|
|
19514
|
+
const disk = readDisk(path2);
|
|
19515
|
+
const merged = cache3 ? mergeOnto(disk) : disk;
|
|
19516
|
+
if (cache3) {
|
|
19517
|
+
for (const server of Object.keys(cache3)) if (!(server in merged)) delete cache3[server];
|
|
19518
|
+
for (const [server, rows] of Object.entries(merged)) {
|
|
19519
|
+
const target = cache3[server] ?? (cache3[server] = {});
|
|
19520
|
+
for (const id of Object.keys(target)) if (!(id in rows)) delete target[id];
|
|
19521
|
+
Object.assign(target, rows);
|
|
19522
|
+
}
|
|
19523
|
+
} else {
|
|
19524
|
+
cache3 = merged;
|
|
19525
|
+
}
|
|
19526
|
+
base = snapshot(disk);
|
|
19527
|
+
diskStamp = stamp;
|
|
19469
19528
|
return cache3;
|
|
19470
19529
|
}
|
|
19471
|
-
function persistNow(
|
|
19530
|
+
function persistNow() {
|
|
19472
19531
|
const path2 = ledgerPath();
|
|
19473
19532
|
mkdirSync10(dirname17(path2), { recursive: true });
|
|
19474
|
-
|
|
19475
|
-
|
|
19533
|
+
load();
|
|
19534
|
+
const tmp = `${path2}.tmp-${process.pid}`;
|
|
19535
|
+
writeFileSync7(tmp, JSON.stringify(cache3 ?? {}));
|
|
19476
19536
|
renameSync5(tmp, path2);
|
|
19537
|
+
base = snapshot(cache3 ?? {});
|
|
19538
|
+
diskStamp = stampOf(path2);
|
|
19477
19539
|
pendingWrite = false;
|
|
19478
19540
|
}
|
|
19479
|
-
function persist(
|
|
19541
|
+
function persist(_data) {
|
|
19480
19542
|
pendingWrite = true;
|
|
19481
19543
|
if (flushTimer) return;
|
|
19482
19544
|
flushTimer = setTimeout(() => {
|
|
19483
19545
|
flushTimer = null;
|
|
19484
19546
|
if (pendingWrite) {
|
|
19485
19547
|
try {
|
|
19486
|
-
persistNow(
|
|
19548
|
+
persistNow();
|
|
19487
19549
|
} catch {
|
|
19488
19550
|
}
|
|
19489
19551
|
}
|
|
@@ -19517,7 +19579,7 @@ function pruneLedgerTargets(configuredServers) {
|
|
|
19517
19579
|
}
|
|
19518
19580
|
const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
|
|
19519
19581
|
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.`);
|
|
19520
|
-
persistNow(
|
|
19582
|
+
persistNow();
|
|
19521
19583
|
return names.length;
|
|
19522
19584
|
}
|
|
19523
19585
|
function flushLedger() {
|
|
@@ -19526,7 +19588,7 @@ function flushLedger() {
|
|
|
19526
19588
|
flushTimer = null;
|
|
19527
19589
|
}
|
|
19528
19590
|
if (!pendingWrite || !cache3) return;
|
|
19529
|
-
persistNow(
|
|
19591
|
+
persistNow();
|
|
19530
19592
|
}
|
|
19531
19593
|
function loadItemVersionsAll() {
|
|
19532
19594
|
if (itemVersionsCache) return itemVersionsCache;
|
|
@@ -19602,13 +19664,13 @@ function markSynced(server, rows) {
|
|
|
19602
19664
|
const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
|
|
19603
19665
|
const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
|
|
19604
19666
|
const ev = extractorVersionForId(r.id);
|
|
19605
|
-
const
|
|
19667
|
+
const base2 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
|
|
19606
19668
|
if (o > 0 || s > 0) {
|
|
19607
|
-
|
|
19608
|
-
|
|
19669
|
+
base2.o = o;
|
|
19670
|
+
base2.s = s;
|
|
19609
19671
|
}
|
|
19610
|
-
if (r.hash !== void 0)
|
|
19611
|
-
forServer[r.id] =
|
|
19672
|
+
if (r.hash !== void 0) base2.h = r.hash;
|
|
19673
|
+
forServer[r.id] = base2;
|
|
19612
19674
|
}
|
|
19613
19675
|
persist(data);
|
|
19614
19676
|
}
|
|
@@ -19683,7 +19745,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
19683
19745
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
19684
19746
|
return "full";
|
|
19685
19747
|
}
|
|
19686
|
-
var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
19748
|
+
var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
19687
19749
|
var init_sync_ledger = __esm({
|
|
19688
19750
|
"src/sync-ledger.ts"() {
|
|
19689
19751
|
"use strict";
|
|
@@ -19691,6 +19753,9 @@ var init_sync_ledger = __esm({
|
|
|
19691
19753
|
init_extractor_version();
|
|
19692
19754
|
ledgerPath = () => join46(getDataDir(), "sync-ledger.json");
|
|
19693
19755
|
cache3 = null;
|
|
19756
|
+
base = /* @__PURE__ */ new Map();
|
|
19757
|
+
diskStamp = null;
|
|
19758
|
+
rowKey = (server, id) => `${server}\0${id}`;
|
|
19694
19759
|
LEDGER_FLUSH_MS = 2e3;
|
|
19695
19760
|
pendingWrite = false;
|
|
19696
19761
|
flushTimer = null;
|
|
@@ -19729,7 +19794,7 @@ var init_sync_fields = __esm({
|
|
|
19729
19794
|
});
|
|
19730
19795
|
|
|
19731
19796
|
// ../engine/dist/core/index-lock.js
|
|
19732
|
-
import { existsSync as existsSync43, mkdirSync as mkdirSync11, openSync as openSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync35, rmSync as rmSync4, statSync as
|
|
19797
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync11, openSync as openSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync35, rmSync as rmSync4, statSync as statSync41, closeSync as closeSync9 } from "fs";
|
|
19733
19798
|
import { dirname as dirname18, join as join47 } from "path";
|
|
19734
19799
|
function acquireIndexLock(opts) {
|
|
19735
19800
|
const lockPath = lockFilePath(opts.file);
|
|
@@ -19779,7 +19844,7 @@ function lockFilePath(file = ".compact.lock") {
|
|
|
19779
19844
|
}
|
|
19780
19845
|
function stealStaleLock(lockPath, staleAfterMs) {
|
|
19781
19846
|
try {
|
|
19782
|
-
const s =
|
|
19847
|
+
const s = statSync41(lockPath);
|
|
19783
19848
|
const age = Date.now() - s.mtimeMs;
|
|
19784
19849
|
let payload;
|
|
19785
19850
|
try {
|
|
@@ -19845,7 +19910,7 @@ var init_http = __esm({
|
|
|
19845
19910
|
CLI_VERSION = JSON.parse(readFileSync36(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19846
19911
|
} catch {
|
|
19847
19912
|
try {
|
|
19848
|
-
if (true) CLI_VERSION = "0.7.
|
|
19913
|
+
if (true) CLI_VERSION = "0.7.15";
|
|
19849
19914
|
} catch {
|
|
19850
19915
|
}
|
|
19851
19916
|
}
|
|
@@ -20343,7 +20408,7 @@ var init_telemetry = __esm({
|
|
|
20343
20408
|
init_sync_client();
|
|
20344
20409
|
cliVersion2 = () => {
|
|
20345
20410
|
try {
|
|
20346
|
-
return true ? "0.7.
|
|
20411
|
+
return true ? "0.7.15" : "dev";
|
|
20347
20412
|
} catch {
|
|
20348
20413
|
return "dev";
|
|
20349
20414
|
}
|
|
@@ -20366,11 +20431,11 @@ __export(server_probe_exports, {
|
|
|
20366
20431
|
function probeOk(r) {
|
|
20367
20432
|
return r.kind === "ok" && r.apiVersion >= 2;
|
|
20368
20433
|
}
|
|
20369
|
-
async function probeServer(
|
|
20434
|
+
async function probeServer(base2, opts = {}) {
|
|
20370
20435
|
const f = opts.fetchImpl || fetch;
|
|
20371
20436
|
let res;
|
|
20372
20437
|
try {
|
|
20373
|
-
res = await f(`${
|
|
20438
|
+
res = await f(`${base2.replace(/\/+$/, "")}/api/capabilities`, {
|
|
20374
20439
|
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
20375
20440
|
});
|
|
20376
20441
|
} catch (err) {
|
|
@@ -20407,34 +20472,34 @@ async function probeServer(base, opts = {}) {
|
|
|
20407
20472
|
raw: parsed
|
|
20408
20473
|
};
|
|
20409
20474
|
}
|
|
20410
|
-
function probeAdvice(r,
|
|
20475
|
+
function probeAdvice(r, base2) {
|
|
20411
20476
|
switch (r.kind) {
|
|
20412
20477
|
case "ok":
|
|
20413
20478
|
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`;
|
|
20414
20479
|
case "moved":
|
|
20415
|
-
return `HTTP ${r.status} \u2014 nothing is served at ${
|
|
20480
|
+
return `HTTP ${r.status} \u2014 nothing is served at ${base2}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
|
|
20416
20481
|
case "unauthorized":
|
|
20417
|
-
return `HTTP ${r.status} \u2014 ${
|
|
20482
|
+
return `HTTP ${r.status} \u2014 ${base2} rejected the credential. Re-login: \`chat-recall login ` + base2 + "`";
|
|
20418
20483
|
case "server_error":
|
|
20419
|
-
return `HTTP ${r.status} \u2014 ${
|
|
20484
|
+
return `HTTP ${r.status} \u2014 ${base2} is up but failing. Nothing to fix locally; check the server.`;
|
|
20420
20485
|
case "not_api":
|
|
20421
|
-
return `${
|
|
20486
|
+
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`;
|
|
20422
20487
|
case "unreachable":
|
|
20423
20488
|
switch (r.reason) {
|
|
20424
20489
|
case "dns":
|
|
20425
|
-
return `cannot resolve the host in ${
|
|
20490
|
+
return `cannot resolve the host in ${base2} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
|
|
20426
20491
|
case "refused":
|
|
20427
|
-
return `${
|
|
20492
|
+
return `${base2} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
|
|
20428
20493
|
case "tls":
|
|
20429
|
-
return `the TLS certificate at ${
|
|
20494
|
+
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.`;
|
|
20430
20495
|
case "timeout":
|
|
20431
|
-
return `${
|
|
20496
|
+
return `${base2} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
|
|
20432
20497
|
case "reset":
|
|
20433
|
-
return `the connection to ${
|
|
20498
|
+
return `the connection to ${base2} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
|
|
20434
20499
|
case "bad_port":
|
|
20435
|
-
return `${
|
|
20500
|
+
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`;
|
|
20436
20501
|
default:
|
|
20437
|
-
return `no HTTP response from ${
|
|
20502
|
+
return `no HTTP response from ${base2} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
|
|
20438
20503
|
}
|
|
20439
20504
|
}
|
|
20440
20505
|
}
|
|
@@ -20467,8 +20532,8 @@ function describeCause(err) {
|
|
|
20467
20532
|
const code = e.code;
|
|
20468
20533
|
if (typeof code === "string" && code && !parts.includes(code)) parts.push(code);
|
|
20469
20534
|
}
|
|
20470
|
-
const
|
|
20471
|
-
return parts.length ? `${
|
|
20535
|
+
const base2 = err instanceof Error ? err.message : String(err);
|
|
20536
|
+
return parts.length ? `${base2}: ${parts.join(" \u2192 ")}` : base2;
|
|
20472
20537
|
}
|
|
20473
20538
|
function describeUnreachable(err) {
|
|
20474
20539
|
const reason = classifyUnreachable(err);
|
|
@@ -20516,7 +20581,7 @@ __export(auto_update_exports, {
|
|
|
20516
20581
|
import { execSync as execSync4, execFileSync as execFileSync3 } from "node:child_process";
|
|
20517
20582
|
import { readFileSync as readFileSync37, existsSync as existsSync45 } from "node:fs";
|
|
20518
20583
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20519
|
-
import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as
|
|
20584
|
+
import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as statSync42, mkdirSync as mkdirSync12 } from "node:fs";
|
|
20520
20585
|
import { join as join48, dirname as dirname19, sep as sep3, posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
20521
20586
|
import { tmpdir as tmpdir3, homedir as homedir17 } from "node:os";
|
|
20522
20587
|
import { createHash as createHash10 } from "node:crypto";
|
|
@@ -20548,12 +20613,12 @@ function installedVersion() {
|
|
|
20548
20613
|
return null;
|
|
20549
20614
|
}
|
|
20550
20615
|
}
|
|
20551
|
-
function planAutoUpdate(
|
|
20616
|
+
function planAutoUpdate(base2, caps, ownVersion2, flag) {
|
|
20552
20617
|
const rel = caps.cli;
|
|
20553
20618
|
if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
|
|
20554
20619
|
if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
|
|
20555
20620
|
if (compareVersions(rel.version, ownVersion2) <= 0) return { update: false, reason: `already current (own ${ownVersion2} >= server ${rel.version})` };
|
|
20556
|
-
return { update: true, reason: `server ${rel.version} > own ${ownVersion2}`, url: tarballUrl(
|
|
20621
|
+
return { update: true, reason: `server ${rel.version} > own ${ownVersion2}`, url: tarballUrl(base2, rel.version), fallbackUrl: tarballUrl(base2), sha256: rel.sha256, from: ownVersion2, to: rel.version };
|
|
20557
20622
|
}
|
|
20558
20623
|
function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
|
|
20559
20624
|
const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
|
|
@@ -20569,7 +20634,7 @@ function sweepStaleStaging(root = tmpdir3(), now = Date.now()) {
|
|
|
20569
20634
|
if (!MKDTEMP_SUFFIX.test(name)) continue;
|
|
20570
20635
|
const dir = join48(root, name);
|
|
20571
20636
|
try {
|
|
20572
|
-
const st =
|
|
20637
|
+
const st = statSync42(dir);
|
|
20573
20638
|
if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
|
|
20574
20639
|
const inside = readdirSync31(dir);
|
|
20575
20640
|
if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
|
|
@@ -20733,20 +20798,20 @@ function clearUpdateFailures() {
|
|
|
20733
20798
|
function stopAutoUpdates() {
|
|
20734
20799
|
stopRequested = true;
|
|
20735
20800
|
}
|
|
20736
|
-
async function runAutoUpdate(
|
|
20801
|
+
async function runAutoUpdate(base2, authHeaders, ownVersion2, deps) {
|
|
20737
20802
|
let caps;
|
|
20738
20803
|
try {
|
|
20739
|
-
const res = await fetchWithTimeout(`${
|
|
20804
|
+
const res = await fetchWithTimeout(`${base2.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
|
|
20740
20805
|
if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
|
|
20741
20806
|
caps = await res.json();
|
|
20742
20807
|
} catch (e) {
|
|
20743
20808
|
return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
|
|
20744
20809
|
}
|
|
20745
20810
|
const effectiveOwn = newerOf(ownVersion2, installedVersion());
|
|
20746
|
-
const plan = planAutoUpdate(
|
|
20811
|
+
const plan = planAutoUpdate(base2, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20747
20812
|
if (!plan.update) {
|
|
20748
|
-
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(
|
|
20749
|
-
reportedStandingSkip.add(
|
|
20813
|
+
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base2)) {
|
|
20814
|
+
reportedStandingSkip.add(base2);
|
|
20750
20815
|
try {
|
|
20751
20816
|
const { reportClientEvent: reportClientEvent3 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
|
|
20752
20817
|
reportClientEvent3("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
|
|
@@ -20802,7 +20867,7 @@ var init_auto_update = __esm({
|
|
|
20802
20867
|
"use strict";
|
|
20803
20868
|
init_http();
|
|
20804
20869
|
init_index_lock();
|
|
20805
|
-
tarballUrl = (
|
|
20870
|
+
tarballUrl = (base2, version2) => `${base2.replace(/\/+$/, "")}/install/${version2 ? `chat-recall-${version2}.tgz` : "chat-recall.tgz"}`;
|
|
20806
20871
|
GIVE_UP_AFTER = 3;
|
|
20807
20872
|
reportedStandingSkip = /* @__PURE__ */ new Set();
|
|
20808
20873
|
STOPPING_REASON = "not installed: this process is shutting down";
|
|
@@ -20847,7 +20912,7 @@ __export(sync_client_exports, {
|
|
|
20847
20912
|
syncSessions: () => syncSessions
|
|
20848
20913
|
});
|
|
20849
20914
|
import { join as join49, dirname as dirname20, basename as basename22 } from "node:path";
|
|
20850
|
-
import { readFileSync as readFileSync38, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync6, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as
|
|
20915
|
+
import { readFileSync as readFileSync38, writeFileSync as writeFileSync10, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync6, unlinkSync as unlinkSync3, readdirSync as readdirSync32, statSync as statSync43 } from "node:fs";
|
|
20851
20916
|
import { tmpdir as tmpdir4, hostname as hostname2 } from "node:os";
|
|
20852
20917
|
import { createHash as createHash11 } from "node:crypto";
|
|
20853
20918
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -20910,15 +20975,15 @@ function loadAllCredentials() {
|
|
|
20910
20975
|
return [];
|
|
20911
20976
|
}
|
|
20912
20977
|
async function fetchTenantSecurityConfig(cred) {
|
|
20913
|
-
const
|
|
20914
|
-
const cached = _securityConfigCache.get(
|
|
20978
|
+
const base2 = cred.serverUrl.replace(/\/+$/, "");
|
|
20979
|
+
const cached = _securityConfigCache.get(base2);
|
|
20915
20980
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20916
20981
|
const headers = { "content-type": "application/json" };
|
|
20917
20982
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
20918
20983
|
try {
|
|
20919
20984
|
const [rulesRes, settingsRes] = await Promise.all([
|
|
20920
|
-
fetchWithTimeout(`${
|
|
20921
|
-
fetchWithTimeout(`${
|
|
20985
|
+
fetchWithTimeout(`${base2}/api/secrets/rules`, { headers }),
|
|
20986
|
+
fetchWithTimeout(`${base2}/api/teams/security-config`, { headers }).catch(() => null)
|
|
20922
20987
|
]);
|
|
20923
20988
|
let tenantRules = [];
|
|
20924
20989
|
let rulePackVersion = null;
|
|
@@ -20943,18 +21008,18 @@ async function fetchTenantSecurityConfig(cred) {
|
|
|
20943
21008
|
const body2 = await settingsRes.json().catch(() => ({}));
|
|
20944
21009
|
if (typeof body2.verifySecrets === "boolean") verifySecrets = body2.verifySecrets;
|
|
20945
21010
|
if (typeof body2.telemetry === "boolean") {
|
|
20946
|
-
setTelemetryEligible(
|
|
21011
|
+
setTelemetryEligible(base2, body2.telemetry);
|
|
20947
21012
|
try {
|
|
20948
21013
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
20949
21014
|
updateCollectorHealth({
|
|
20950
|
-
telemetryEligible: { ...prior, [
|
|
21015
|
+
telemetryEligible: { ...prior, [base2]: { allowed: body2.telemetry, at: Date.now() } }
|
|
20951
21016
|
});
|
|
20952
21017
|
} catch {
|
|
20953
21018
|
}
|
|
20954
21019
|
}
|
|
20955
21020
|
}
|
|
20956
21021
|
const config2 = { tenantRules, verifySecrets, rulePackVersion };
|
|
20957
|
-
_securityConfigCache.set(
|
|
21022
|
+
_securityConfigCache.set(base2, { fetchedAt: Date.now(), config: config2 });
|
|
20958
21023
|
return config2;
|
|
20959
21024
|
} catch {
|
|
20960
21025
|
return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
|
|
@@ -20973,18 +21038,18 @@ function readPersistedSyncConfigs() {
|
|
|
20973
21038
|
return {};
|
|
20974
21039
|
}
|
|
20975
21040
|
}
|
|
20976
|
-
function persistSyncConfig(
|
|
21041
|
+
function persistSyncConfig(base2, config2) {
|
|
20977
21042
|
try {
|
|
20978
21043
|
const all = readPersistedSyncConfigs();
|
|
20979
|
-
all[
|
|
21044
|
+
all[base2] = { fetchedAt: Date.now(), config: config2 };
|
|
20980
21045
|
mkdirSync13(dirname20(syncConfigCachePath()), { recursive: true });
|
|
20981
21046
|
writeFileSync10(syncConfigCachePath(), JSON.stringify(all, null, 2));
|
|
20982
21047
|
} catch {
|
|
20983
21048
|
}
|
|
20984
21049
|
}
|
|
20985
21050
|
async function fetchTenantSyncConfig(cred) {
|
|
20986
|
-
const
|
|
20987
|
-
const cached = _syncConfigCache.get(
|
|
21051
|
+
const base2 = cred.serverUrl.replace(/\/+$/, "");
|
|
21052
|
+
const cached = _syncConfigCache.get(base2);
|
|
20988
21053
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20989
21054
|
const headers = { "content-type": "application/json" };
|
|
20990
21055
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
@@ -20992,7 +21057,7 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20992
21057
|
try {
|
|
20993
21058
|
const sources2 = discoverSessionSources();
|
|
20994
21059
|
if (sources2.length > 0) {
|
|
20995
|
-
await fetchWithTimeout(`${
|
|
21060
|
+
await fetchWithTimeout(`${base2}/api/sync-config/sources`, {
|
|
20996
21061
|
method: "POST",
|
|
20997
21062
|
headers,
|
|
20998
21063
|
body: JSON.stringify({ device: deviceLabel(), sources: sources2 })
|
|
@@ -21000,12 +21065,12 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
21000
21065
|
}
|
|
21001
21066
|
} catch {
|
|
21002
21067
|
}
|
|
21003
|
-
const res = await fetchWithTimeout(`${
|
|
21068
|
+
const res = await fetchWithTimeout(`${base2}/api/sync-config`, { headers });
|
|
21004
21069
|
if (res.status === 404) {
|
|
21005
|
-
_syncConfigCache.set(
|
|
21070
|
+
_syncConfigCache.set(base2, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
|
|
21006
21071
|
return EMPTY_SYNC_CONFIG;
|
|
21007
21072
|
}
|
|
21008
|
-
if (!res.ok) return lastKnownSyncConfig(
|
|
21073
|
+
if (!res.ok) return lastKnownSyncConfig(base2, `HTTP ${res.status}`);
|
|
21009
21074
|
const body2 = await res.json().catch(() => ({}));
|
|
21010
21075
|
const config2 = {
|
|
21011
21076
|
excludeTools: Array.isArray(body2.excludeTools) ? body2.excludeTools.filter((t) => typeof t === "string") : [],
|
|
@@ -21042,22 +21107,22 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
21042
21107
|
if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
|
|
21043
21108
|
} catch {
|
|
21044
21109
|
}
|
|
21045
|
-
_syncConfigCache.set(
|
|
21046
|
-
persistSyncConfig(
|
|
21110
|
+
_syncConfigCache.set(base2, { fetchedAt: Date.now(), config: config2 });
|
|
21111
|
+
persistSyncConfig(base2, config2);
|
|
21047
21112
|
return config2;
|
|
21048
21113
|
} catch (err) {
|
|
21049
21114
|
if (isSyncRulesRefusal(err)) throw err;
|
|
21050
|
-
return lastKnownSyncConfig(
|
|
21115
|
+
return lastKnownSyncConfig(base2, err instanceof Error ? err.message : "request failed");
|
|
21051
21116
|
}
|
|
21052
21117
|
}
|
|
21053
|
-
function lastKnownSyncConfig(
|
|
21054
|
-
const remembered = _syncConfigCache.get(
|
|
21118
|
+
function lastKnownSyncConfig(base2, reason) {
|
|
21119
|
+
const remembered = _syncConfigCache.get(base2) ?? readPersistedSyncConfigs()[base2];
|
|
21055
21120
|
if (remembered) {
|
|
21056
21121
|
console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
|
|
21057
21122
|
return remembered.config;
|
|
21058
21123
|
}
|
|
21059
21124
|
const refusal = new Error(
|
|
21060
|
-
`Cannot read the server-side sync rules from ${
|
|
21125
|
+
`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.`
|
|
21061
21126
|
);
|
|
21062
21127
|
refusal[SYNC_RULES_REFUSAL] = true;
|
|
21063
21128
|
throw refusal;
|
|
@@ -21178,25 +21243,25 @@ async function syncSessions(opts = {}) {
|
|
|
21178
21243
|
${errors.join("\n ")}`);
|
|
21179
21244
|
return { ...agg, perTarget };
|
|
21180
21245
|
}
|
|
21181
|
-
async function postFieldBatch(
|
|
21246
|
+
async function postFieldBatch(base2, token, rows) {
|
|
21182
21247
|
const headers = { "content-type": "application/json" };
|
|
21183
21248
|
if (token) headers.authorization = `Bearer ${token}`;
|
|
21184
21249
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
21185
21250
|
for (let attempt = 0; ; attempt++) {
|
|
21186
|
-
const res = await fetchWithTimeout(`${
|
|
21251
|
+
const res = await fetchWithTimeout(`${base2}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
|
|
21187
21252
|
if (res.ok) return;
|
|
21188
21253
|
const retryable = res.status === 429 || res.status >= 500;
|
|
21189
|
-
if (!retryable || attempt >= 5) throw new Error(`${
|
|
21254
|
+
if (!retryable || attempt >= 5) throw new Error(`${base2}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
21190
21255
|
const ra = Number(res.headers.get("retry-after")) || 0;
|
|
21191
21256
|
await sleep(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
|
|
21192
21257
|
}
|
|
21193
21258
|
}
|
|
21194
21259
|
async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
21195
|
-
const
|
|
21196
|
-
const ledger = getSyncedRows(
|
|
21260
|
+
const base2 = cred.serverUrl.replace(/\/+$/, "");
|
|
21261
|
+
const ledger = getSyncedRows(base2);
|
|
21197
21262
|
let pushed = 0, absent = 0, scanned = 0;
|
|
21198
21263
|
for (const field of SYNC_FIELDS) {
|
|
21199
|
-
const needFull = !!opts.force || fieldNeedsFullPass(
|
|
21264
|
+
const needFull = !!opts.force || fieldNeedsFullPass(base2, field);
|
|
21200
21265
|
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
21201
21266
|
const send = [];
|
|
21202
21267
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
@@ -21212,15 +21277,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
21212
21277
|
}
|
|
21213
21278
|
for (let i = 0; i < send.length; i += 200) {
|
|
21214
21279
|
const chunk = send.slice(i, i + 200);
|
|
21215
|
-
await postFieldBatch(
|
|
21216
|
-
markFieldCoverage(
|
|
21280
|
+
await postFieldBatch(base2, cred.token, chunk);
|
|
21281
|
+
markFieldCoverage(base2, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
|
|
21217
21282
|
pushed += chunk.length;
|
|
21218
21283
|
}
|
|
21219
21284
|
if (absentIds.length) {
|
|
21220
|
-
markFieldCoverage(
|
|
21285
|
+
markFieldCoverage(base2, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
|
|
21221
21286
|
absent += absentIds.length;
|
|
21222
21287
|
}
|
|
21223
|
-
if (needFull) markFieldFullPassDone(
|
|
21288
|
+
if (needFull) markFieldFullPassDone(base2, field);
|
|
21224
21289
|
}
|
|
21225
21290
|
return { pushed, absent, scanned };
|
|
21226
21291
|
}
|
|
@@ -21258,7 +21323,7 @@ function reapStaleScanDirs(dir = tmpdir4(), maxAgeMs = 6 * 36e5, now = Date.now(
|
|
|
21258
21323
|
if (!name.startsWith("cr-batchscan-")) continue;
|
|
21259
21324
|
const p = join49(dir, name);
|
|
21260
21325
|
try {
|
|
21261
|
-
if (now -
|
|
21326
|
+
if (now - statSync43(p).mtimeMs < maxAgeMs) continue;
|
|
21262
21327
|
rmSync6(p, { recursive: true, force: true });
|
|
21263
21328
|
reaped++;
|
|
21264
21329
|
} catch {
|
|
@@ -21337,25 +21402,25 @@ function serverIngestConcurrency(serverUrl) {
|
|
|
21337
21402
|
return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
|
|
21338
21403
|
}
|
|
21339
21404
|
async function verifyServerApi(serverUrl, minApi) {
|
|
21340
|
-
const
|
|
21341
|
-
const seen = capsOk.get(
|
|
21405
|
+
const base2 = serverUrl.replace(/\/$/, "");
|
|
21406
|
+
const seen = capsOk.get(base2);
|
|
21342
21407
|
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
21343
21408
|
const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
21344
|
-
const probe = await probeServer2(
|
|
21409
|
+
const probe = await probeServer2(base2, {
|
|
21345
21410
|
fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
|
|
21346
21411
|
});
|
|
21347
|
-
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe,
|
|
21412
|
+
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base2));
|
|
21348
21413
|
const caps = probe.raw;
|
|
21349
21414
|
if ((caps.apiVersion ?? 0) < minApi) {
|
|
21350
21415
|
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
21351
21416
|
}
|
|
21352
21417
|
const adv = caps.limits?.ingestConcurrencyPerTenant;
|
|
21353
21418
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
21354
|
-
advertisedIngestConc.set(
|
|
21419
|
+
advertisedIngestConc.set(base2, Math.floor(adv));
|
|
21355
21420
|
}
|
|
21356
|
-
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(
|
|
21357
|
-
else advertisedGzipBody.delete(
|
|
21358
|
-
capsOk.set(
|
|
21421
|
+
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base2);
|
|
21422
|
+
else advertisedGzipBody.delete(base2);
|
|
21423
|
+
capsOk.set(base2, Date.now());
|
|
21359
21424
|
return true;
|
|
21360
21425
|
}
|
|
21361
21426
|
async function syncToTarget(cred, opts = {}) {
|
|
@@ -21420,7 +21485,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21420
21485
|
const ac = new AbortController();
|
|
21421
21486
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21422
21487
|
try {
|
|
21423
|
-
const res = await fetch(`${
|
|
21488
|
+
const res = await fetch(`${base2}/api/sync`, {
|
|
21424
21489
|
method: "POST",
|
|
21425
21490
|
// No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
|
|
21426
21491
|
// accepts it as the single 'default' tenant.
|
|
@@ -21436,26 +21501,26 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21436
21501
|
acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
|
|
21437
21502
|
const body3 = await res.json().catch(() => ({}));
|
|
21438
21503
|
if (typeof body3.telemetry === "boolean") {
|
|
21439
|
-
setTelemetryEligible(
|
|
21504
|
+
setTelemetryEligible(base2, body3.telemetry);
|
|
21440
21505
|
try {
|
|
21441
21506
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
21442
21507
|
updateCollectorHealth({
|
|
21443
|
-
telemetryEligible: { ...prior, [
|
|
21508
|
+
telemetryEligible: { ...prior, [base2]: { allowed: body3.telemetry, at: Date.now() } }
|
|
21444
21509
|
});
|
|
21445
21510
|
} catch {
|
|
21446
21511
|
}
|
|
21447
21512
|
}
|
|
21448
21513
|
const adv = body3.limits?.ingestConcurrencyPerTenant;
|
|
21449
21514
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
21450
|
-
setServerIngestConcurrency(
|
|
21515
|
+
setServerIngestConcurrency(base2, Math.floor(adv));
|
|
21451
21516
|
}
|
|
21452
21517
|
if (body3.cli && body3.cli.version) {
|
|
21453
21518
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
21454
21519
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
21455
|
-
const plan = planAutoUpdate2(
|
|
21520
|
+
const plan = planAutoUpdate2(base2, { cli: body3.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
21456
21521
|
sweepStaleStaging2();
|
|
21457
21522
|
if (plan.update) {
|
|
21458
|
-
void runAutoUpdate2(
|
|
21523
|
+
void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
|
|
21459
21524
|
});
|
|
21460
21525
|
}
|
|
21461
21526
|
}
|
|
@@ -21464,7 +21529,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21464
21529
|
const retryable = res.status === 429 || res.status >= 500;
|
|
21465
21530
|
const text = await res.text().catch(() => "");
|
|
21466
21531
|
if (res.status === 401 || res.status === 403) {
|
|
21467
|
-
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${
|
|
21532
|
+
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base2}`);
|
|
21468
21533
|
}
|
|
21469
21534
|
if (res.status === 402) {
|
|
21470
21535
|
let detail = text;
|
|
@@ -21485,7 +21550,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21485
21550
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
21486
21551
|
const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
|
|
21487
21552
|
const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
|
|
21488
|
-
console.error(`[sync] HTTP ${res.status} from ${
|
|
21553
|
+
console.error(`[sync] HTTP ${res.status} from ${base2}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
|
|
21489
21554
|
await sleep(waitMs);
|
|
21490
21555
|
continue;
|
|
21491
21556
|
} catch (err) {
|
|
@@ -21553,11 +21618,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21553
21618
|
}
|
|
21554
21619
|
};
|
|
21555
21620
|
};
|
|
21556
|
-
const
|
|
21557
|
-
const ledger = opts.useLedger ? getSyncedRows(
|
|
21621
|
+
const base2 = cred.serverUrl.replace(/\/$/, "");
|
|
21622
|
+
const ledger = opts.useLedger ? getSyncedRows(base2) : null;
|
|
21558
21623
|
const convBatch = makeBatcher("conversations", 25, false, (rows) => {
|
|
21559
21624
|
try {
|
|
21560
|
-
markSynced(
|
|
21625
|
+
markSynced(base2, rows.map((r) => {
|
|
21561
21626
|
const off = typeof r.from_offset === "number" ? r.from_offset : 0;
|
|
21562
21627
|
const hash = shippedHash.get(r.session_id);
|
|
21563
21628
|
return off > 0 ? { id: r.session_id, mtime: r.mtime, offset: off, size: off, hash, acked: true } : { id: r.session_id, mtime: r.mtime, hash };
|
|
@@ -21572,7 +21637,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21572
21637
|
const ac = new AbortController();
|
|
21573
21638
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21574
21639
|
try {
|
|
21575
|
-
const res = await fetch(`${
|
|
21640
|
+
const res = await fetch(`${base2}/api/sync`, {
|
|
21576
21641
|
method: "POST",
|
|
21577
21642
|
headers,
|
|
21578
21643
|
body: JSON.stringify({ conversations: convs }),
|
|
@@ -21583,10 +21648,10 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21583
21648
|
if (body2.cli && body2.cli.version) {
|
|
21584
21649
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
21585
21650
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
21586
|
-
const plan = planAutoUpdate2(
|
|
21651
|
+
const plan = planAutoUpdate2(base2, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
21587
21652
|
sweepStaleStaging2();
|
|
21588
21653
|
if (plan.update) {
|
|
21589
|
-
void runAutoUpdate2(
|
|
21654
|
+
void runAutoUpdate2(base2, authHeaders, ownVersion).catch(() => {
|
|
21590
21655
|
});
|
|
21591
21656
|
}
|
|
21592
21657
|
}
|
|
@@ -21594,7 +21659,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21594
21659
|
const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
|
|
21595
21660
|
if (acked.length > 0) {
|
|
21596
21661
|
try {
|
|
21597
|
-
markSynced(
|
|
21662
|
+
markSynced(base2, acked.map((c) => ({
|
|
21598
21663
|
id: c.session_id,
|
|
21599
21664
|
mtime: c.mtime,
|
|
21600
21665
|
offset: c.from_offset,
|
|
@@ -21618,7 +21683,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21618
21683
|
const ac = new AbortController();
|
|
21619
21684
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21620
21685
|
try {
|
|
21621
|
-
const res = await fetch(`${
|
|
21686
|
+
const res = await fetch(`${base2}/api/sync`, {
|
|
21622
21687
|
method: "POST",
|
|
21623
21688
|
headers,
|
|
21624
21689
|
body: JSON.stringify({ conversations: [conv] }),
|
|
@@ -21631,11 +21696,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21631
21696
|
const mtime = conv.mtime;
|
|
21632
21697
|
try {
|
|
21633
21698
|
if (!guarded) {
|
|
21634
|
-
markSynced(
|
|
21699
|
+
markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
|
|
21635
21700
|
} else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
|
|
21636
|
-
markSynced(
|
|
21701
|
+
markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
|
|
21637
21702
|
} else {
|
|
21638
|
-
markSynced(
|
|
21703
|
+
markSynced(base2, [{ id, mtime }]);
|
|
21639
21704
|
}
|
|
21640
21705
|
} catch {
|
|
21641
21706
|
}
|
|
@@ -21701,7 +21766,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21701
21766
|
const m = process.memoryUsage();
|
|
21702
21767
|
console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
|
|
21703
21768
|
} : null;
|
|
21704
|
-
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${
|
|
21769
|
+
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base2}`);
|
|
21705
21770
|
if (upload.sessionMeta) {
|
|
21706
21771
|
try {
|
|
21707
21772
|
await reconcileFieldsForTarget(
|
|
@@ -21716,7 +21781,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21716
21781
|
{ convRefs: slice }
|
|
21717
21782
|
);
|
|
21718
21783
|
} catch (e) {
|
|
21719
|
-
console.error(`[sync] field reconcile (${
|
|
21784
|
+
console.error(`[sync] field reconcile (${base2}): ${e instanceof Error ? e.message : e}`);
|
|
21720
21785
|
}
|
|
21721
21786
|
}
|
|
21722
21787
|
trace?.("field reconcile done");
|
|
@@ -21758,7 +21823,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21758
21823
|
}
|
|
21759
21824
|
trace?.("conversation walk start");
|
|
21760
21825
|
const walkStartedAt = Date.now();
|
|
21761
|
-
const firstWalk = (ledger ?? getSyncedRows(
|
|
21826
|
+
const firstWalk = (ledger ?? getSyncedRows(base2)).size === 0;
|
|
21762
21827
|
reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
|
|
21763
21828
|
walkProgressForUpload = { done: 0, total: slice.length, complete: false };
|
|
21764
21829
|
let traceN = 0;
|
|
@@ -21798,7 +21863,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21798
21863
|
continue;
|
|
21799
21864
|
} else {
|
|
21800
21865
|
try {
|
|
21801
|
-
markSynced(
|
|
21866
|
+
markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21802
21867
|
} catch {
|
|
21803
21868
|
}
|
|
21804
21869
|
skipped++;
|
|
@@ -21821,7 +21886,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21821
21886
|
const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
|
|
21822
21887
|
const priorCursor = ackRow?.s ?? 0;
|
|
21823
21888
|
const safeToAck = off > 0 && off <= priorCursor;
|
|
21824
|
-
markSynced(
|
|
21889
|
+
markSynced(base2, [safeToAck ? { id: ref.prefixedId, mtime: ref.mtime, offset: off, size: off, hash: built.srcHash, acked: true } : { id: ref.prefixedId, mtime: ref.mtime, hash: built.srcHash }]);
|
|
21825
21890
|
} catch {
|
|
21826
21891
|
}
|
|
21827
21892
|
}
|
|
@@ -21831,7 +21896,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21831
21896
|
if (!built) {
|
|
21832
21897
|
if (ledger) {
|
|
21833
21898
|
try {
|
|
21834
|
-
markSynced(
|
|
21899
|
+
markSynced(base2, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21835
21900
|
} catch {
|
|
21836
21901
|
}
|
|
21837
21902
|
}
|
|
@@ -21888,7 +21953,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21888
21953
|
walked++;
|
|
21889
21954
|
if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
|
|
21890
21955
|
}
|
|
21891
|
-
const itemVersions = loadItemVersions(
|
|
21956
|
+
const itemVersions = loadItemVersions(base2);
|
|
21892
21957
|
const seenTools = /* @__PURE__ */ new Set();
|
|
21893
21958
|
const seenItemKeys = /* @__PURE__ */ new Map();
|
|
21894
21959
|
const registry = buildSourceRegistry();
|
|
@@ -21982,7 +22047,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21982
22047
|
await appendFlush();
|
|
21983
22048
|
for (const id of appendResults.fullResyncNeeded) {
|
|
21984
22049
|
try {
|
|
21985
|
-
markFullResync(
|
|
22050
|
+
markFullResync(base2, id);
|
|
21986
22051
|
} catch {
|
|
21987
22052
|
}
|
|
21988
22053
|
}
|
|
@@ -21995,7 +22060,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21995
22060
|
await findingsBatch.drain();
|
|
21996
22061
|
await drainInflight();
|
|
21997
22062
|
{
|
|
21998
|
-
const sentHashes = loadInventoryHashes(
|
|
22063
|
+
const sentHashes = loadInventoryHashes(base2);
|
|
21999
22064
|
const entries = [];
|
|
22000
22065
|
const hashes = {};
|
|
22001
22066
|
for (const [sourceType, ids] of inventory) {
|
|
@@ -22009,7 +22074,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
22009
22074
|
if (entries.length > 0) {
|
|
22010
22075
|
try {
|
|
22011
22076
|
await post({ inventory: entries });
|
|
22012
|
-
saveInventoryHashes(
|
|
22077
|
+
saveInventoryHashes(base2, hashes);
|
|
22013
22078
|
} catch (err) {
|
|
22014
22079
|
console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
|
|
22015
22080
|
}
|
|
@@ -22020,7 +22085,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
22020
22085
|
const rec = {};
|
|
22021
22086
|
for (const t of seenTools) rec[t] = extractorVersionForTool(t);
|
|
22022
22087
|
for (const [k, v] of seenItemKeys) rec[k] = v;
|
|
22023
|
-
saveItemVersions(
|
|
22088
|
+
saveItemVersions(base2, rec);
|
|
22024
22089
|
} catch {
|
|
22025
22090
|
}
|
|
22026
22091
|
}
|
|
@@ -22033,9 +22098,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
22033
22098
|
}
|
|
22034
22099
|
if (tombstones.length > 0) {
|
|
22035
22100
|
await post({ tombstones });
|
|
22036
|
-
const data = getLedgerData(
|
|
22101
|
+
const data = getLedgerData(base2);
|
|
22037
22102
|
for (const t of tombstones) delete data[t.session_id];
|
|
22038
|
-
persistLedgerData(
|
|
22103
|
+
persistLedgerData(base2, data);
|
|
22039
22104
|
}
|
|
22040
22105
|
}
|
|
22041
22106
|
if (opts.prune) await post({ prune_empty_sessions: true });
|
|
@@ -22506,7 +22571,7 @@ var init_sync_client = __esm({
|
|
|
22506
22571
|
ownVersion = JSON.parse(readFileSync38(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22507
22572
|
} catch {
|
|
22508
22573
|
try {
|
|
22509
|
-
if (true) ownVersion = "0.7.
|
|
22574
|
+
if (true) ownVersion = "0.7.15";
|
|
22510
22575
|
} catch {
|
|
22511
22576
|
}
|
|
22512
22577
|
}
|
|
@@ -22665,9 +22730,9 @@ async function refreshUpdateCheck(force = false) {
|
|
|
22665
22730
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
22666
22731
|
for (const cred of loadAllCredentials2()) {
|
|
22667
22732
|
if (!cred.serverUrl) continue;
|
|
22668
|
-
const
|
|
22733
|
+
const base2 = cred.serverUrl.replace(/\/+$/, "");
|
|
22669
22734
|
try {
|
|
22670
|
-
const res = await fetchWithTimeout(`${
|
|
22735
|
+
const res = await fetchWithTimeout(`${base2}/api/capabilities`, {
|
|
22671
22736
|
headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
|
|
22672
22737
|
}, 5e3);
|
|
22673
22738
|
if (!res.ok) continue;
|
|
@@ -23056,7 +23121,7 @@ __export(install_skills_exports, {
|
|
|
23056
23121
|
skillsSourceDir: () => skillsSourceDir,
|
|
23057
23122
|
uninstallSkills: () => uninstallSkills
|
|
23058
23123
|
});
|
|
23059
|
-
import { readdirSync as readdirSync33, existsSync as existsSync47, mkdirSync as mkdirSync15, rmSync as rmSync8, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync42, statSync as
|
|
23124
|
+
import { readdirSync as readdirSync33, existsSync as existsSync47, mkdirSync as mkdirSync15, rmSync as rmSync8, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync42, statSync as statSync44, realpathSync as realpathSync4 } from "fs";
|
|
23060
23125
|
import { createHash as createHash12 } from "crypto";
|
|
23061
23126
|
import { join as join52, basename as basename23 } from "path";
|
|
23062
23127
|
function skillsSourceDir() {
|
|
@@ -23297,18 +23362,18 @@ function usableDir(dir) {
|
|
|
23297
23362
|
if (!isDir(dir)) {
|
|
23298
23363
|
const missing = [];
|
|
23299
23364
|
let cur = dir;
|
|
23300
|
-
let
|
|
23365
|
+
let base2 = false;
|
|
23301
23366
|
while (missing.length < MAX_MISSING_LEVELS) {
|
|
23302
23367
|
const parent = dirname(cur);
|
|
23303
23368
|
if (parent === cur) break;
|
|
23304
23369
|
missing.push(cur);
|
|
23305
23370
|
if (isDir(parent)) {
|
|
23306
|
-
|
|
23371
|
+
base2 = true;
|
|
23307
23372
|
break;
|
|
23308
23373
|
}
|
|
23309
23374
|
cur = parent;
|
|
23310
23375
|
}
|
|
23311
|
-
if (!
|
|
23376
|
+
if (!base2) return false;
|
|
23312
23377
|
for (let i = missing.length - 1; i >= 0; i--) {
|
|
23313
23378
|
try {
|
|
23314
23379
|
mkdirSync(missing[i]);
|
|
@@ -29497,7 +29562,7 @@ function installCrashGuards() {
|
|
|
29497
29562
|
reportClientEvent2("mcp_crash", { message: err.stack || err.message });
|
|
29498
29563
|
});
|
|
29499
29564
|
}
|
|
29500
|
-
var RELAY_VERSION = true ? "0.7.
|
|
29565
|
+
var RELAY_VERSION = true ? "0.7.15" : "0.0.0";
|
|
29501
29566
|
function daemonIdleSecs() {
|
|
29502
29567
|
const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
|
|
29503
29568
|
if (raw === void 0) return 900;
|