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/cli.js
CHANGED
|
@@ -4259,7 +4259,7 @@ var require_pino = __commonJS({
|
|
|
4259
4259
|
messageKey,
|
|
4260
4260
|
errorKey,
|
|
4261
4261
|
nestedKey,
|
|
4262
|
-
base:
|
|
4262
|
+
base: base4,
|
|
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 (base4 !== null) {
|
|
4302
4302
|
if (name === void 0) {
|
|
4303
|
-
chindings = coreChindings(
|
|
4303
|
+
chindings = coreChindings(base4);
|
|
4304
4304
|
} else {
|
|
4305
|
-
chindings = coreChindings(Object.assign({},
|
|
4305
|
+
chindings = coreChindings(Object.assign({}, base4, { name }));
|
|
4306
4306
|
}
|
|
4307
4307
|
}
|
|
4308
4308
|
const time2 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime;
|
|
@@ -4834,57 +4834,57 @@ function freshDefaults() {
|
|
|
4834
4834
|
team: defaultTeam()
|
|
4835
4835
|
};
|
|
4836
4836
|
}
|
|
4837
|
-
function mergeSources(
|
|
4837
|
+
function mergeSources(base4, partial) {
|
|
4838
4838
|
if (!partial)
|
|
4839
|
-
return
|
|
4839
|
+
return base4;
|
|
4840
4840
|
const legacyGemini = partial.enabled?.gemini;
|
|
4841
4841
|
const inherited = legacyGemini && typeof legacyGemini === "object" ? (({ sessions: _s, plans: _p, ...rest }) => rest)(legacyGemini) : {};
|
|
4842
4842
|
const enabled = {
|
|
4843
|
-
claude: { ...
|
|
4844
|
-
opencode: { ...
|
|
4845
|
-
codex: { ...
|
|
4846
|
-
agy: { ...
|
|
4847
|
-
cursor: { ...
|
|
4848
|
-
shared: { ...
|
|
4849
|
-
common: { ...
|
|
4843
|
+
claude: { ...base4.enabled.claude, ...partial.enabled?.claude ?? {} },
|
|
4844
|
+
opencode: { ...base4.enabled.opencode, ...partial.enabled?.opencode ?? {} },
|
|
4845
|
+
codex: { ...base4.enabled.codex, ...partial.enabled?.codex ?? {} },
|
|
4846
|
+
agy: { ...base4.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
|
|
4847
|
+
cursor: { ...base4.enabled.cursor, ...partial.enabled?.cursor ?? {} },
|
|
4848
|
+
shared: { ...base4.enabled.shared, ...partial.enabled?.shared ?? {} },
|
|
4849
|
+
common: { ...base4.enabled.common, ...partial.enabled?.common ?? {} }
|
|
4850
4850
|
};
|
|
4851
4851
|
return {
|
|
4852
|
-
claudeHome: partial.claudeHome ??
|
|
4853
|
-
geminiHome: partial.geminiHome ??
|
|
4854
|
-
codexHome: partial.codexHome ??
|
|
4855
|
-
opencodeDbPath: partial.opencodeDbPath ??
|
|
4856
|
-
agyHome: partial.agyHome ??
|
|
4857
|
-
cursorHome: partial.cursorHome ??
|
|
4858
|
-
cursorIdeHome: partial.cursorIdeHome ??
|
|
4859
|
-
extraClaudeHomes: partial.extraClaudeHomes ??
|
|
4860
|
-
approvedHomes: partial.approvedHomes ??
|
|
4861
|
-
declinedHomes: partial.declinedHomes ??
|
|
4862
|
-
homesGrandfathered: partial.homesGrandfathered ??
|
|
4852
|
+
claudeHome: partial.claudeHome ?? base4.claudeHome,
|
|
4853
|
+
geminiHome: partial.geminiHome ?? base4.geminiHome,
|
|
4854
|
+
codexHome: partial.codexHome ?? base4.codexHome,
|
|
4855
|
+
opencodeDbPath: partial.opencodeDbPath ?? base4.opencodeDbPath,
|
|
4856
|
+
agyHome: partial.agyHome ?? base4.agyHome,
|
|
4857
|
+
cursorHome: partial.cursorHome ?? base4.cursorHome,
|
|
4858
|
+
cursorIdeHome: partial.cursorIdeHome ?? base4.cursorIdeHome,
|
|
4859
|
+
extraClaudeHomes: partial.extraClaudeHomes ?? base4.extraClaudeHomes,
|
|
4860
|
+
approvedHomes: partial.approvedHomes ?? base4.approvedHomes,
|
|
4861
|
+
declinedHomes: partial.declinedHomes ?? base4.declinedHomes,
|
|
4862
|
+
homesGrandfathered: partial.homesGrandfathered ?? base4.homesGrandfathered,
|
|
4863
4863
|
enabled
|
|
4864
4864
|
};
|
|
4865
4865
|
}
|
|
4866
|
-
function mergePrivacy(
|
|
4866
|
+
function mergePrivacy(base4, partial) {
|
|
4867
4867
|
if (!partial)
|
|
4868
|
-
return
|
|
4869
|
-
return { ...
|
|
4868
|
+
return base4;
|
|
4869
|
+
return { ...base4, ...partial };
|
|
4870
4870
|
}
|
|
4871
|
-
function mergeSync(
|
|
4871
|
+
function mergeSync(base4, partial) {
|
|
4872
4872
|
if (!partial)
|
|
4873
|
-
return
|
|
4873
|
+
return base4;
|
|
4874
4874
|
return {
|
|
4875
|
-
...
|
|
4875
|
+
...base4,
|
|
4876
4876
|
...partial,
|
|
4877
|
-
upload: { ...
|
|
4877
|
+
upload: { ...base4.upload, ...partial.upload ?? {} }
|
|
4878
4878
|
};
|
|
4879
4879
|
}
|
|
4880
|
-
function mergeTeam(
|
|
4880
|
+
function mergeTeam(base4, partial) {
|
|
4881
4881
|
if (!partial)
|
|
4882
|
-
return
|
|
4882
|
+
return base4;
|
|
4883
4883
|
return {
|
|
4884
|
-
...
|
|
4884
|
+
...base4,
|
|
4885
4885
|
...partial,
|
|
4886
|
-
publishAllowed: { ...
|
|
4887
|
-
vault: { ...
|
|
4886
|
+
publishAllowed: { ...base4.publishAllowed, ...partial.publishAllowed ?? {} },
|
|
4887
|
+
vault: { ...base4.vault, ...partial.vault ?? {} }
|
|
4888
4888
|
};
|
|
4889
4889
|
}
|
|
4890
4890
|
function settingsFilePath() {
|
|
@@ -5002,15 +5002,15 @@ function loadSettings() {
|
|
|
5002
5002
|
}
|
|
5003
5003
|
try {
|
|
5004
5004
|
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
5005
|
-
const
|
|
5005
|
+
const base4 = freshDefaults();
|
|
5006
5006
|
const result = {
|
|
5007
5007
|
v: SCHEMA_VERSION,
|
|
5008
|
-
embedding: { ...
|
|
5009
|
-
summary: { ...
|
|
5010
|
-
sources: mergeSources(
|
|
5011
|
-
privacy: mergePrivacy(
|
|
5012
|
-
sync: mergeSync(
|
|
5013
|
-
team: mergeTeam(
|
|
5008
|
+
embedding: { ...base4.embedding, ...parsed.embedding ?? {} },
|
|
5009
|
+
summary: { ...base4.summary, ...parsed.summary ?? {} },
|
|
5010
|
+
sources: mergeSources(base4.sources, parsed.sources),
|
|
5011
|
+
privacy: mergePrivacy(base4.privacy, parsed.privacy),
|
|
5012
|
+
sync: mergeSync(base4.sync, parsed.sync),
|
|
5013
|
+
team: mergeTeam(base4.team, parsed.team)
|
|
5014
5014
|
};
|
|
5015
5015
|
if (mtimeMs >= 0)
|
|
5016
5016
|
_settingsCache = { mtimeMs, size, value: structuredClone(result) };
|
|
@@ -5216,10 +5216,10 @@ function legacyAutoSyncedHomes() {
|
|
|
5216
5216
|
{ base: join3(home, ".local", "share", "opencode"), marker: "opencode.db" },
|
|
5217
5217
|
{ base: join3(home, ".cursor"), marker: "chats" }
|
|
5218
5218
|
];
|
|
5219
|
-
for (const { base:
|
|
5220
|
-
add(
|
|
5221
|
-
const parent = dirname3(
|
|
5222
|
-
const leaf =
|
|
5219
|
+
for (const { base: base4, marker } of bases) {
|
|
5220
|
+
add(base4, marker);
|
|
5221
|
+
const parent = dirname3(base4);
|
|
5222
|
+
const leaf = base4.slice(parent.length + 1);
|
|
5223
5223
|
try {
|
|
5224
5224
|
for (const e of readdirSync2(parent, { withFileTypes: true })) {
|
|
5225
5225
|
if (!e.isDirectory())
|
|
@@ -5417,17 +5417,17 @@ function cursorHomeDir() {
|
|
|
5417
5417
|
function cursorIdeHomeDir() {
|
|
5418
5418
|
return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join4(homedir3(), "Library", "Application Support", "Cursor") : join4(homedir3(), ".config", "Cursor"));
|
|
5419
5419
|
}
|
|
5420
|
-
function siblingHomes(
|
|
5420
|
+
function siblingHomes(base4, overridden, suffix) {
|
|
5421
5421
|
const roots = [];
|
|
5422
5422
|
const add = (home) => {
|
|
5423
5423
|
const root = suffix ? join4(home, suffix) : home;
|
|
5424
5424
|
if (existsSync4(root) && !roots.includes(root))
|
|
5425
5425
|
roots.push(root);
|
|
5426
5426
|
};
|
|
5427
|
-
add(
|
|
5427
|
+
add(base4);
|
|
5428
5428
|
if (!overridden) {
|
|
5429
|
-
const parent = dirname4(
|
|
5430
|
-
const leaf = basename(
|
|
5429
|
+
const parent = dirname4(base4);
|
|
5430
|
+
const leaf = basename(base4);
|
|
5431
5431
|
try {
|
|
5432
5432
|
for (const entry of readdirSync3(parent, { withFileTypes: true })) {
|
|
5433
5433
|
if (!entry.isDirectory())
|
|
@@ -5937,9 +5937,9 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
5937
5937
|
content.metadata.durationMs += obj.durationMs;
|
|
5938
5938
|
}
|
|
5939
5939
|
if (msgType === "file-history-snapshot") {
|
|
5940
|
-
const
|
|
5941
|
-
if (
|
|
5942
|
-
const backups =
|
|
5940
|
+
const snapshot2 = obj.snapshot;
|
|
5941
|
+
if (snapshot2 && typeof snapshot2 === "object") {
|
|
5942
|
+
const backups = snapshot2.trackedFileBackups;
|
|
5943
5943
|
if (backups && typeof backups === "object") {
|
|
5944
5944
|
for (const filePath2 of Object.keys(backups)) {
|
|
5945
5945
|
filesModified.add(filePath2);
|
|
@@ -12776,8 +12776,8 @@ function _clearServerRulePack() {
|
|
|
12776
12776
|
serverPack = null;
|
|
12777
12777
|
}
|
|
12778
12778
|
function activeRules() {
|
|
12779
|
-
const
|
|
12780
|
-
return serverPack && serverPack.rules.length > 0 ? [...
|
|
12779
|
+
const base4 = settingsView().rules;
|
|
12780
|
+
return serverPack && serverPack.rules.length > 0 ? [...base4, ...serverPack.rules] : base4;
|
|
12781
12781
|
}
|
|
12782
12782
|
function isRedactionEnabled() {
|
|
12783
12783
|
const env = isEnvRedactionRequested();
|
|
@@ -18535,7 +18535,7 @@ var init_extractor_version = __esm({
|
|
|
18535
18535
|
});
|
|
18536
18536
|
|
|
18537
18537
|
// src/sync-ledger.ts
|
|
18538
|
-
import { readFileSync as readFileSync29, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync6 } from "node:fs";
|
|
18538
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync5, renameSync as renameSync4, mkdirSync as mkdirSync6, statSync as statSync35 } from "node:fs";
|
|
18539
18539
|
import { join as join38, dirname as dirname15 } from "node:path";
|
|
18540
18540
|
function toRow(entry) {
|
|
18541
18541
|
if (entry === void 0) return void 0;
|
|
@@ -18544,32 +18544,94 @@ function toRow(entry) {
|
|
|
18544
18544
|
function ledgerFilePath() {
|
|
18545
18545
|
return ledgerPath();
|
|
18546
18546
|
}
|
|
18547
|
-
function
|
|
18548
|
-
if (cache3) return cache3;
|
|
18547
|
+
function stampOf(path) {
|
|
18549
18548
|
try {
|
|
18550
|
-
const
|
|
18551
|
-
|
|
18549
|
+
const st = statSync35(path);
|
|
18550
|
+
return `${st.mtimeMs}:${st.size}`;
|
|
18552
18551
|
} catch {
|
|
18553
|
-
|
|
18552
|
+
return null;
|
|
18554
18553
|
}
|
|
18554
|
+
}
|
|
18555
|
+
function readDisk(path) {
|
|
18556
|
+
try {
|
|
18557
|
+
const parsed = JSON.parse(readFileSync29(path, "utf-8"));
|
|
18558
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
18559
|
+
} catch {
|
|
18560
|
+
return {};
|
|
18561
|
+
}
|
|
18562
|
+
}
|
|
18563
|
+
function snapshot(data) {
|
|
18564
|
+
const out = /* @__PURE__ */ new Map();
|
|
18565
|
+
for (const [server, rows] of Object.entries(data)) {
|
|
18566
|
+
for (const [id, entry] of Object.entries(rows)) out.set(rowKey(server, id), JSON.stringify(entry));
|
|
18567
|
+
}
|
|
18568
|
+
return out;
|
|
18569
|
+
}
|
|
18570
|
+
function mergeOnto(disk) {
|
|
18571
|
+
const out = {};
|
|
18572
|
+
const put = (server, id, entry) => {
|
|
18573
|
+
(out[server] ??= {})[id] = entry;
|
|
18574
|
+
};
|
|
18575
|
+
const mine = cache3 ?? {};
|
|
18576
|
+
for (const [server, rows] of Object.entries(disk)) {
|
|
18577
|
+
for (const [id, entry] of Object.entries(rows)) {
|
|
18578
|
+
const k = rowKey(server, id);
|
|
18579
|
+
const own = mine[server]?.[id];
|
|
18580
|
+
const was = base.get(k);
|
|
18581
|
+
if (own === void 0) {
|
|
18582
|
+
if (was === void 0) put(server, id, entry);
|
|
18583
|
+
} else {
|
|
18584
|
+
put(server, id, JSON.stringify(own) === was ? entry : own);
|
|
18585
|
+
}
|
|
18586
|
+
}
|
|
18587
|
+
}
|
|
18588
|
+
for (const [server, rows] of Object.entries(mine)) {
|
|
18589
|
+
for (const [id, entry] of Object.entries(rows)) {
|
|
18590
|
+
if (disk[server]?.[id] !== void 0) continue;
|
|
18591
|
+
if (JSON.stringify(entry) !== base.get(rowKey(server, id))) put(server, id, entry);
|
|
18592
|
+
}
|
|
18593
|
+
}
|
|
18594
|
+
return out;
|
|
18595
|
+
}
|
|
18596
|
+
function load() {
|
|
18597
|
+
const path = ledgerPath();
|
|
18598
|
+
const stamp = stampOf(path);
|
|
18599
|
+
if (cache3 && stamp === diskStamp) return cache3;
|
|
18600
|
+
const disk = readDisk(path);
|
|
18601
|
+
const merged = cache3 ? mergeOnto(disk) : disk;
|
|
18602
|
+
if (cache3) {
|
|
18603
|
+
for (const server of Object.keys(cache3)) if (!(server in merged)) delete cache3[server];
|
|
18604
|
+
for (const [server, rows] of Object.entries(merged)) {
|
|
18605
|
+
const target = cache3[server] ?? (cache3[server] = {});
|
|
18606
|
+
for (const id of Object.keys(target)) if (!(id in rows)) delete target[id];
|
|
18607
|
+
Object.assign(target, rows);
|
|
18608
|
+
}
|
|
18609
|
+
} else {
|
|
18610
|
+
cache3 = merged;
|
|
18611
|
+
}
|
|
18612
|
+
base = snapshot(disk);
|
|
18613
|
+
diskStamp = stamp;
|
|
18555
18614
|
return cache3;
|
|
18556
18615
|
}
|
|
18557
|
-
function persistNow(
|
|
18616
|
+
function persistNow() {
|
|
18558
18617
|
const path = ledgerPath();
|
|
18559
18618
|
mkdirSync6(dirname15(path), { recursive: true });
|
|
18560
|
-
|
|
18561
|
-
|
|
18619
|
+
load();
|
|
18620
|
+
const tmp = `${path}.tmp-${process.pid}`;
|
|
18621
|
+
writeFileSync5(tmp, JSON.stringify(cache3 ?? {}));
|
|
18562
18622
|
renameSync4(tmp, path);
|
|
18623
|
+
base = snapshot(cache3 ?? {});
|
|
18624
|
+
diskStamp = stampOf(path);
|
|
18563
18625
|
pendingWrite = false;
|
|
18564
18626
|
}
|
|
18565
|
-
function persist(
|
|
18627
|
+
function persist(_data) {
|
|
18566
18628
|
pendingWrite = true;
|
|
18567
18629
|
if (flushTimer) return;
|
|
18568
18630
|
flushTimer = setTimeout(() => {
|
|
18569
18631
|
flushTimer = null;
|
|
18570
18632
|
if (pendingWrite) {
|
|
18571
18633
|
try {
|
|
18572
|
-
persistNow(
|
|
18634
|
+
persistNow();
|
|
18573
18635
|
} catch {
|
|
18574
18636
|
}
|
|
18575
18637
|
}
|
|
@@ -18603,7 +18665,7 @@ function pruneLedgerTargets(configuredServers) {
|
|
|
18603
18665
|
}
|
|
18604
18666
|
const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
|
|
18605
18667
|
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.`);
|
|
18606
|
-
persistNow(
|
|
18668
|
+
persistNow();
|
|
18607
18669
|
return names.length;
|
|
18608
18670
|
}
|
|
18609
18671
|
function flushLedger() {
|
|
@@ -18612,7 +18674,7 @@ function flushLedger() {
|
|
|
18612
18674
|
flushTimer = null;
|
|
18613
18675
|
}
|
|
18614
18676
|
if (!pendingWrite || !cache3) return;
|
|
18615
|
-
persistNow(
|
|
18677
|
+
persistNow();
|
|
18616
18678
|
}
|
|
18617
18679
|
function loadItemVersionsAll() {
|
|
18618
18680
|
if (itemVersionsCache) return itemVersionsCache;
|
|
@@ -18688,13 +18750,13 @@ function markSynced(server, rows) {
|
|
|
18688
18750
|
const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
|
|
18689
18751
|
const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
|
|
18690
18752
|
const ev = extractorVersionForId(r.id);
|
|
18691
|
-
const
|
|
18753
|
+
const base4 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
|
|
18692
18754
|
if (o > 0 || s > 0) {
|
|
18693
|
-
|
|
18694
|
-
|
|
18755
|
+
base4.o = o;
|
|
18756
|
+
base4.s = s;
|
|
18695
18757
|
}
|
|
18696
|
-
if (r.hash !== void 0)
|
|
18697
|
-
forServer[r.id] =
|
|
18758
|
+
if (r.hash !== void 0) base4.h = r.hash;
|
|
18759
|
+
forServer[r.id] = base4;
|
|
18698
18760
|
}
|
|
18699
18761
|
persist(data);
|
|
18700
18762
|
}
|
|
@@ -18769,7 +18831,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
18769
18831
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
18770
18832
|
return "full";
|
|
18771
18833
|
}
|
|
18772
|
-
var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
18834
|
+
var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
18773
18835
|
var init_sync_ledger = __esm({
|
|
18774
18836
|
"src/sync-ledger.ts"() {
|
|
18775
18837
|
"use strict";
|
|
@@ -18777,6 +18839,9 @@ var init_sync_ledger = __esm({
|
|
|
18777
18839
|
init_extractor_version();
|
|
18778
18840
|
ledgerPath = () => join38(getDataDir(), "sync-ledger.json");
|
|
18779
18841
|
cache3 = null;
|
|
18842
|
+
base = /* @__PURE__ */ new Map();
|
|
18843
|
+
diskStamp = null;
|
|
18844
|
+
rowKey = (server, id) => `${server}\0${id}`;
|
|
18780
18845
|
LEDGER_FLUSH_MS = 2e3;
|
|
18781
18846
|
pendingWrite = false;
|
|
18782
18847
|
flushTimer = null;
|
|
@@ -18815,7 +18880,7 @@ var init_sync_fields = __esm({
|
|
|
18815
18880
|
});
|
|
18816
18881
|
|
|
18817
18882
|
// ../engine/dist/core/index-lock.js
|
|
18818
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync7, openSync as openSync8, writeFileSync as writeFileSync6, readFileSync as readFileSync30, rmSync as rmSync4, statSync as
|
|
18883
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync7, openSync as openSync8, writeFileSync as writeFileSync6, readFileSync as readFileSync30, rmSync as rmSync4, statSync as statSync36, closeSync as closeSync8 } from "fs";
|
|
18819
18884
|
import { dirname as dirname16, join as join39 } from "path";
|
|
18820
18885
|
function acquireIndexLock(opts) {
|
|
18821
18886
|
const lockPath = lockFilePath(opts.file);
|
|
@@ -18865,7 +18930,7 @@ function lockFilePath(file = ".compact.lock") {
|
|
|
18865
18930
|
}
|
|
18866
18931
|
function stealStaleLock(lockPath, staleAfterMs) {
|
|
18867
18932
|
try {
|
|
18868
|
-
const s =
|
|
18933
|
+
const s = statSync36(lockPath);
|
|
18869
18934
|
const age = Date.now() - s.mtimeMs;
|
|
18870
18935
|
let payload;
|
|
18871
18936
|
try {
|
|
@@ -18937,7 +19002,7 @@ var init_http = __esm({
|
|
|
18937
19002
|
CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
18938
19003
|
} catch {
|
|
18939
19004
|
try {
|
|
18940
|
-
if (true) CLI_VERSION = "0.7.
|
|
19005
|
+
if (true) CLI_VERSION = "0.7.15";
|
|
18941
19006
|
} catch {
|
|
18942
19007
|
}
|
|
18943
19008
|
}
|
|
@@ -19435,7 +19500,7 @@ var init_telemetry = __esm({
|
|
|
19435
19500
|
init_sync_client();
|
|
19436
19501
|
cliVersion2 = () => {
|
|
19437
19502
|
try {
|
|
19438
|
-
return true ? "0.7.
|
|
19503
|
+
return true ? "0.7.15" : "dev";
|
|
19439
19504
|
} catch {
|
|
19440
19505
|
return "dev";
|
|
19441
19506
|
}
|
|
@@ -19611,11 +19676,11 @@ __export(server_probe_exports, {
|
|
|
19611
19676
|
function probeOk(r) {
|
|
19612
19677
|
return r.kind === "ok" && r.apiVersion >= 2;
|
|
19613
19678
|
}
|
|
19614
|
-
async function probeServer(
|
|
19679
|
+
async function probeServer(base4, opts = {}) {
|
|
19615
19680
|
const f = opts.fetchImpl || fetch;
|
|
19616
19681
|
let res;
|
|
19617
19682
|
try {
|
|
19618
|
-
res = await f(`${
|
|
19683
|
+
res = await f(`${base4.replace(/\/+$/, "")}/api/capabilities`, {
|
|
19619
19684
|
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
19620
19685
|
});
|
|
19621
19686
|
} catch (err) {
|
|
@@ -19652,34 +19717,34 @@ async function probeServer(base3, opts = {}) {
|
|
|
19652
19717
|
raw: parsed
|
|
19653
19718
|
};
|
|
19654
19719
|
}
|
|
19655
|
-
function probeAdvice(r,
|
|
19720
|
+
function probeAdvice(r, base4) {
|
|
19656
19721
|
switch (r.kind) {
|
|
19657
19722
|
case "ok":
|
|
19658
19723
|
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`;
|
|
19659
19724
|
case "moved":
|
|
19660
|
-
return `HTTP ${r.status} \u2014 nothing is served at ${
|
|
19725
|
+
return `HTTP ${r.status} \u2014 nothing is served at ${base4}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
|
|
19661
19726
|
case "unauthorized":
|
|
19662
|
-
return `HTTP ${r.status} \u2014 ${
|
|
19727
|
+
return `HTTP ${r.status} \u2014 ${base4} rejected the credential. Re-login: \`chat-recall login ` + base4 + "`";
|
|
19663
19728
|
case "server_error":
|
|
19664
|
-
return `HTTP ${r.status} \u2014 ${
|
|
19729
|
+
return `HTTP ${r.status} \u2014 ${base4} is up but failing. Nothing to fix locally; check the server.`;
|
|
19665
19730
|
case "not_api":
|
|
19666
|
-
return `${
|
|
19731
|
+
return `${base4} 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`;
|
|
19667
19732
|
case "unreachable":
|
|
19668
19733
|
switch (r.reason) {
|
|
19669
19734
|
case "dns":
|
|
19670
|
-
return `cannot resolve the host in ${
|
|
19735
|
+
return `cannot resolve the host in ${base4} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
|
|
19671
19736
|
case "refused":
|
|
19672
|
-
return `${
|
|
19737
|
+
return `${base4} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
|
|
19673
19738
|
case "tls":
|
|
19674
|
-
return `the TLS certificate at ${
|
|
19739
|
+
return `the TLS certificate at ${base4} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
|
|
19675
19740
|
case "timeout":
|
|
19676
|
-
return `${
|
|
19741
|
+
return `${base4} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
|
|
19677
19742
|
case "reset":
|
|
19678
|
-
return `the connection to ${
|
|
19743
|
+
return `the connection to ${base4} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
|
|
19679
19744
|
case "bad_port":
|
|
19680
|
-
return `${
|
|
19745
|
+
return `${base4} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
|
|
19681
19746
|
default:
|
|
19682
|
-
return `no HTTP response from ${
|
|
19747
|
+
return `no HTTP response from ${base4} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
|
|
19683
19748
|
}
|
|
19684
19749
|
}
|
|
19685
19750
|
}
|
|
@@ -19712,8 +19777,8 @@ function describeCause(err) {
|
|
|
19712
19777
|
const code2 = e.code;
|
|
19713
19778
|
if (typeof code2 === "string" && code2 && !parts.includes(code2)) parts.push(code2);
|
|
19714
19779
|
}
|
|
19715
|
-
const
|
|
19716
|
-
return parts.length ? `${
|
|
19780
|
+
const base4 = err instanceof Error ? err.message : String(err);
|
|
19781
|
+
return parts.length ? `${base4}: ${parts.join(" \u2192 ")}` : base4;
|
|
19717
19782
|
}
|
|
19718
19783
|
function describeUnreachable(err) {
|
|
19719
19784
|
const reason = classifyUnreachable(err);
|
|
@@ -19826,7 +19891,7 @@ __export(auto_update_exports, {
|
|
|
19826
19891
|
import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
|
|
19827
19892
|
import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
|
|
19828
19893
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
19829
|
-
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as
|
|
19894
|
+
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync37, mkdirSync as mkdirSync9 } from "node:fs";
|
|
19830
19895
|
import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
19831
19896
|
import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
|
|
19832
19897
|
import { createHash as createHash8 } from "node:crypto";
|
|
@@ -19858,12 +19923,12 @@ function installedVersion() {
|
|
|
19858
19923
|
return null;
|
|
19859
19924
|
}
|
|
19860
19925
|
}
|
|
19861
|
-
function planAutoUpdate(
|
|
19926
|
+
function planAutoUpdate(base4, caps, ownVersion3, flag) {
|
|
19862
19927
|
const rel = caps.cli;
|
|
19863
19928
|
if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
|
|
19864
19929
|
if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
|
|
19865
19930
|
if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
|
|
19866
|
-
return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(
|
|
19931
|
+
return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base4, rel.version), fallbackUrl: tarballUrl(base4), sha256: rel.sha256, from: ownVersion3, to: rel.version };
|
|
19867
19932
|
}
|
|
19868
19933
|
function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
19869
19934
|
const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
|
|
@@ -19879,7 +19944,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
|
19879
19944
|
if (!MKDTEMP_SUFFIX.test(name)) continue;
|
|
19880
19945
|
const dir = join41(root, name);
|
|
19881
19946
|
try {
|
|
19882
|
-
const st =
|
|
19947
|
+
const st = statSync37(dir);
|
|
19883
19948
|
if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
|
|
19884
19949
|
const inside = readdirSync30(dir);
|
|
19885
19950
|
if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
|
|
@@ -20043,20 +20108,20 @@ function clearUpdateFailures() {
|
|
|
20043
20108
|
function stopAutoUpdates() {
|
|
20044
20109
|
stopRequested = true;
|
|
20045
20110
|
}
|
|
20046
|
-
async function runAutoUpdate(
|
|
20111
|
+
async function runAutoUpdate(base4, authHeaders, ownVersion3, deps) {
|
|
20047
20112
|
let caps;
|
|
20048
20113
|
try {
|
|
20049
|
-
const res = await fetchWithTimeout(`${
|
|
20114
|
+
const res = await fetchWithTimeout(`${base4.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
|
|
20050
20115
|
if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
|
|
20051
20116
|
caps = await res.json();
|
|
20052
20117
|
} catch (e) {
|
|
20053
20118
|
return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
|
|
20054
20119
|
}
|
|
20055
20120
|
const effectiveOwn = newerOf(ownVersion3, installedVersion());
|
|
20056
|
-
const plan = planAutoUpdate(
|
|
20121
|
+
const plan = planAutoUpdate(base4, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20057
20122
|
if (!plan.update) {
|
|
20058
|
-
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(
|
|
20059
|
-
reportedStandingSkip.add(
|
|
20123
|
+
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base4)) {
|
|
20124
|
+
reportedStandingSkip.add(base4);
|
|
20060
20125
|
try {
|
|
20061
20126
|
const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
|
|
20062
20127
|
reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
|
|
@@ -20112,7 +20177,7 @@ var init_auto_update = __esm({
|
|
|
20112
20177
|
"use strict";
|
|
20113
20178
|
init_http();
|
|
20114
20179
|
init_index_lock();
|
|
20115
|
-
tarballUrl = (
|
|
20180
|
+
tarballUrl = (base4, version2) => `${base4.replace(/\/+$/, "")}/install/${version2 ? `chat-recall-${version2}.tgz` : "chat-recall.tgz"}`;
|
|
20116
20181
|
GIVE_UP_AFTER = 3;
|
|
20117
20182
|
reportedStandingSkip = /* @__PURE__ */ new Set();
|
|
20118
20183
|
STOPPING_REASON = "not installed: this process is shutting down";
|
|
@@ -20157,7 +20222,7 @@ __export(sync_client_exports, {
|
|
|
20157
20222
|
syncSessions: () => syncSessions
|
|
20158
20223
|
});
|
|
20159
20224
|
import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
|
|
20160
|
-
import { readFileSync as readFileSync35, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as
|
|
20225
|
+
import { readFileSync as readFileSync35, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as statSync38 } from "node:fs";
|
|
20161
20226
|
import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
|
|
20162
20227
|
import { createHash as createHash9 } from "node:crypto";
|
|
20163
20228
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -20220,15 +20285,15 @@ function loadAllCredentials() {
|
|
|
20220
20285
|
return [];
|
|
20221
20286
|
}
|
|
20222
20287
|
async function fetchTenantSecurityConfig(cred) {
|
|
20223
|
-
const
|
|
20224
|
-
const cached = _securityConfigCache.get(
|
|
20288
|
+
const base4 = cred.serverUrl.replace(/\/+$/, "");
|
|
20289
|
+
const cached = _securityConfigCache.get(base4);
|
|
20225
20290
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20226
20291
|
const headers = { "content-type": "application/json" };
|
|
20227
20292
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
20228
20293
|
try {
|
|
20229
20294
|
const [rulesRes, settingsRes] = await Promise.all([
|
|
20230
|
-
fetchWithTimeout(`${
|
|
20231
|
-
fetchWithTimeout(`${
|
|
20295
|
+
fetchWithTimeout(`${base4}/api/secrets/rules`, { headers }),
|
|
20296
|
+
fetchWithTimeout(`${base4}/api/teams/security-config`, { headers }).catch(() => null)
|
|
20232
20297
|
]);
|
|
20233
20298
|
let tenantRules = [];
|
|
20234
20299
|
let rulePackVersion = null;
|
|
@@ -20253,18 +20318,18 @@ async function fetchTenantSecurityConfig(cred) {
|
|
|
20253
20318
|
const body2 = await settingsRes.json().catch(() => ({}));
|
|
20254
20319
|
if (typeof body2.verifySecrets === "boolean") verifySecrets = body2.verifySecrets;
|
|
20255
20320
|
if (typeof body2.telemetry === "boolean") {
|
|
20256
|
-
setTelemetryEligible(
|
|
20321
|
+
setTelemetryEligible(base4, body2.telemetry);
|
|
20257
20322
|
try {
|
|
20258
20323
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
20259
20324
|
updateCollectorHealth({
|
|
20260
|
-
telemetryEligible: { ...prior, [
|
|
20325
|
+
telemetryEligible: { ...prior, [base4]: { allowed: body2.telemetry, at: Date.now() } }
|
|
20261
20326
|
});
|
|
20262
20327
|
} catch {
|
|
20263
20328
|
}
|
|
20264
20329
|
}
|
|
20265
20330
|
}
|
|
20266
20331
|
const config2 = { tenantRules, verifySecrets, rulePackVersion };
|
|
20267
|
-
_securityConfigCache.set(
|
|
20332
|
+
_securityConfigCache.set(base4, { fetchedAt: Date.now(), config: config2 });
|
|
20268
20333
|
return config2;
|
|
20269
20334
|
} catch {
|
|
20270
20335
|
return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
|
|
@@ -20283,18 +20348,18 @@ function readPersistedSyncConfigs() {
|
|
|
20283
20348
|
return {};
|
|
20284
20349
|
}
|
|
20285
20350
|
}
|
|
20286
|
-
function persistSyncConfig(
|
|
20351
|
+
function persistSyncConfig(base4, config2) {
|
|
20287
20352
|
try {
|
|
20288
20353
|
const all = readPersistedSyncConfigs();
|
|
20289
|
-
all[
|
|
20354
|
+
all[base4] = { fetchedAt: Date.now(), config: config2 };
|
|
20290
20355
|
mkdirSync10(dirname19(syncConfigCachePath()), { recursive: true });
|
|
20291
20356
|
writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
|
|
20292
20357
|
} catch {
|
|
20293
20358
|
}
|
|
20294
20359
|
}
|
|
20295
20360
|
async function fetchTenantSyncConfig(cred) {
|
|
20296
|
-
const
|
|
20297
|
-
const cached = _syncConfigCache.get(
|
|
20361
|
+
const base4 = cred.serverUrl.replace(/\/+$/, "");
|
|
20362
|
+
const cached = _syncConfigCache.get(base4);
|
|
20298
20363
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20299
20364
|
const headers = { "content-type": "application/json" };
|
|
20300
20365
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
@@ -20302,7 +20367,7 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20302
20367
|
try {
|
|
20303
20368
|
const sources3 = discoverSessionSources();
|
|
20304
20369
|
if (sources3.length > 0) {
|
|
20305
|
-
await fetchWithTimeout(`${
|
|
20370
|
+
await fetchWithTimeout(`${base4}/api/sync-config/sources`, {
|
|
20306
20371
|
method: "POST",
|
|
20307
20372
|
headers,
|
|
20308
20373
|
body: JSON.stringify({ device: deviceLabel(), sources: sources3 })
|
|
@@ -20310,12 +20375,12 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20310
20375
|
}
|
|
20311
20376
|
} catch {
|
|
20312
20377
|
}
|
|
20313
|
-
const res = await fetchWithTimeout(`${
|
|
20378
|
+
const res = await fetchWithTimeout(`${base4}/api/sync-config`, { headers });
|
|
20314
20379
|
if (res.status === 404) {
|
|
20315
|
-
_syncConfigCache.set(
|
|
20380
|
+
_syncConfigCache.set(base4, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
|
|
20316
20381
|
return EMPTY_SYNC_CONFIG;
|
|
20317
20382
|
}
|
|
20318
|
-
if (!res.ok) return lastKnownSyncConfig(
|
|
20383
|
+
if (!res.ok) return lastKnownSyncConfig(base4, `HTTP ${res.status}`);
|
|
20319
20384
|
const body2 = await res.json().catch(() => ({}));
|
|
20320
20385
|
const config2 = {
|
|
20321
20386
|
excludeTools: Array.isArray(body2.excludeTools) ? body2.excludeTools.filter((t) => typeof t === "string") : [],
|
|
@@ -20352,22 +20417,22 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20352
20417
|
if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
|
|
20353
20418
|
} catch {
|
|
20354
20419
|
}
|
|
20355
|
-
_syncConfigCache.set(
|
|
20356
|
-
persistSyncConfig(
|
|
20420
|
+
_syncConfigCache.set(base4, { fetchedAt: Date.now(), config: config2 });
|
|
20421
|
+
persistSyncConfig(base4, config2);
|
|
20357
20422
|
return config2;
|
|
20358
20423
|
} catch (err) {
|
|
20359
20424
|
if (isSyncRulesRefusal(err)) throw err;
|
|
20360
|
-
return lastKnownSyncConfig(
|
|
20425
|
+
return lastKnownSyncConfig(base4, err instanceof Error ? err.message : "request failed");
|
|
20361
20426
|
}
|
|
20362
20427
|
}
|
|
20363
|
-
function lastKnownSyncConfig(
|
|
20364
|
-
const remembered = _syncConfigCache.get(
|
|
20428
|
+
function lastKnownSyncConfig(base4, reason) {
|
|
20429
|
+
const remembered = _syncConfigCache.get(base4) ?? readPersistedSyncConfigs()[base4];
|
|
20365
20430
|
if (remembered) {
|
|
20366
20431
|
console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
|
|
20367
20432
|
return remembered.config;
|
|
20368
20433
|
}
|
|
20369
20434
|
const refusal = new Error(
|
|
20370
|
-
`Cannot read the server-side sync rules from ${
|
|
20435
|
+
`Cannot read the server-side sync rules from ${base4} (${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.`
|
|
20371
20436
|
);
|
|
20372
20437
|
refusal[SYNC_RULES_REFUSAL] = true;
|
|
20373
20438
|
throw refusal;
|
|
@@ -20488,25 +20553,25 @@ async function syncSessions(opts = {}) {
|
|
|
20488
20553
|
${errors.join("\n ")}`);
|
|
20489
20554
|
return { ...agg, perTarget };
|
|
20490
20555
|
}
|
|
20491
|
-
async function postFieldBatch(
|
|
20556
|
+
async function postFieldBatch(base4, token, rows) {
|
|
20492
20557
|
const headers = { "content-type": "application/json" };
|
|
20493
20558
|
if (token) headers.authorization = `Bearer ${token}`;
|
|
20494
20559
|
const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
20495
20560
|
for (let attempt = 0; ; attempt++) {
|
|
20496
|
-
const res = await fetchWithTimeout(`${
|
|
20561
|
+
const res = await fetchWithTimeout(`${base4}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
|
|
20497
20562
|
if (res.ok) return;
|
|
20498
20563
|
const retryable = res.status === 429 || res.status >= 500;
|
|
20499
|
-
if (!retryable || attempt >= 5) throw new Error(`${
|
|
20564
|
+
if (!retryable || attempt >= 5) throw new Error(`${base4}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
20500
20565
|
const ra = Number(res.headers.get("retry-after")) || 0;
|
|
20501
20566
|
await sleep2(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
|
|
20502
20567
|
}
|
|
20503
20568
|
}
|
|
20504
20569
|
async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
20505
|
-
const
|
|
20506
|
-
const ledger = getSyncedRows(
|
|
20570
|
+
const base4 = cred.serverUrl.replace(/\/+$/, "");
|
|
20571
|
+
const ledger = getSyncedRows(base4);
|
|
20507
20572
|
let pushed = 0, absent = 0, scanned = 0;
|
|
20508
20573
|
for (const field of SYNC_FIELDS) {
|
|
20509
|
-
const needFull = !!opts.force || fieldNeedsFullPass(
|
|
20574
|
+
const needFull = !!opts.force || fieldNeedsFullPass(base4, field);
|
|
20510
20575
|
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
20511
20576
|
const send = [];
|
|
20512
20577
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
@@ -20522,15 +20587,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
20522
20587
|
}
|
|
20523
20588
|
for (let i = 0; i < send.length; i += 200) {
|
|
20524
20589
|
const chunk = send.slice(i, i + 200);
|
|
20525
|
-
await postFieldBatch(
|
|
20526
|
-
markFieldCoverage(
|
|
20590
|
+
await postFieldBatch(base4, cred.token, chunk);
|
|
20591
|
+
markFieldCoverage(base4, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
|
|
20527
20592
|
pushed += chunk.length;
|
|
20528
20593
|
}
|
|
20529
20594
|
if (absentIds.length) {
|
|
20530
|
-
markFieldCoverage(
|
|
20595
|
+
markFieldCoverage(base4, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
|
|
20531
20596
|
absent += absentIds.length;
|
|
20532
20597
|
}
|
|
20533
|
-
if (needFull) markFieldFullPassDone(
|
|
20598
|
+
if (needFull) markFieldFullPassDone(base4, field);
|
|
20534
20599
|
}
|
|
20535
20600
|
return { pushed, absent, scanned };
|
|
20536
20601
|
}
|
|
@@ -20568,7 +20633,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
|
|
|
20568
20633
|
if (!name.startsWith("cr-batchscan-")) continue;
|
|
20569
20634
|
const p = join42(dir, name);
|
|
20570
20635
|
try {
|
|
20571
|
-
if (now -
|
|
20636
|
+
if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
|
|
20572
20637
|
rmSync6(p, { recursive: true, force: true });
|
|
20573
20638
|
reaped++;
|
|
20574
20639
|
} catch {
|
|
@@ -20647,25 +20712,25 @@ function serverIngestConcurrency(serverUrl) {
|
|
|
20647
20712
|
return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
|
|
20648
20713
|
}
|
|
20649
20714
|
async function verifyServerApi(serverUrl, minApi) {
|
|
20650
|
-
const
|
|
20651
|
-
const seen = capsOk.get(
|
|
20715
|
+
const base4 = serverUrl.replace(/\/$/, "");
|
|
20716
|
+
const seen = capsOk.get(base4);
|
|
20652
20717
|
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
20653
20718
|
const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
20654
|
-
const probe = await probeServer2(
|
|
20719
|
+
const probe = await probeServer2(base4, {
|
|
20655
20720
|
fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
|
|
20656
20721
|
});
|
|
20657
|
-
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe,
|
|
20722
|
+
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base4));
|
|
20658
20723
|
const caps = probe.raw;
|
|
20659
20724
|
if ((caps.apiVersion ?? 0) < minApi) {
|
|
20660
20725
|
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
20661
20726
|
}
|
|
20662
20727
|
const adv = caps.limits?.ingestConcurrencyPerTenant;
|
|
20663
20728
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
20664
|
-
advertisedIngestConc.set(
|
|
20729
|
+
advertisedIngestConc.set(base4, Math.floor(adv));
|
|
20665
20730
|
}
|
|
20666
|
-
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(
|
|
20667
|
-
else advertisedGzipBody.delete(
|
|
20668
|
-
capsOk.set(
|
|
20731
|
+
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base4);
|
|
20732
|
+
else advertisedGzipBody.delete(base4);
|
|
20733
|
+
capsOk.set(base4, Date.now());
|
|
20669
20734
|
return true;
|
|
20670
20735
|
}
|
|
20671
20736
|
async function syncToTarget(cred, opts = {}) {
|
|
@@ -20730,7 +20795,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20730
20795
|
const ac = new AbortController();
|
|
20731
20796
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
20732
20797
|
try {
|
|
20733
|
-
const res = await fetch(`${
|
|
20798
|
+
const res = await fetch(`${base4}/api/sync`, {
|
|
20734
20799
|
method: "POST",
|
|
20735
20800
|
// No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
|
|
20736
20801
|
// accepts it as the single 'default' tenant.
|
|
@@ -20746,26 +20811,26 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20746
20811
|
acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
|
|
20747
20812
|
const body3 = await res.json().catch(() => ({}));
|
|
20748
20813
|
if (typeof body3.telemetry === "boolean") {
|
|
20749
|
-
setTelemetryEligible(
|
|
20814
|
+
setTelemetryEligible(base4, body3.telemetry);
|
|
20750
20815
|
try {
|
|
20751
20816
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
20752
20817
|
updateCollectorHealth({
|
|
20753
|
-
telemetryEligible: { ...prior, [
|
|
20818
|
+
telemetryEligible: { ...prior, [base4]: { allowed: body3.telemetry, at: Date.now() } }
|
|
20754
20819
|
});
|
|
20755
20820
|
} catch {
|
|
20756
20821
|
}
|
|
20757
20822
|
}
|
|
20758
20823
|
const adv = body3.limits?.ingestConcurrencyPerTenant;
|
|
20759
20824
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
20760
|
-
setServerIngestConcurrency(
|
|
20825
|
+
setServerIngestConcurrency(base4, Math.floor(adv));
|
|
20761
20826
|
}
|
|
20762
20827
|
if (body3.cli && body3.cli.version) {
|
|
20763
20828
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
20764
20829
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
20765
|
-
const plan = planAutoUpdate2(
|
|
20830
|
+
const plan = planAutoUpdate2(base4, { cli: body3.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20766
20831
|
sweepStaleStaging2();
|
|
20767
20832
|
if (plan.update) {
|
|
20768
|
-
void runAutoUpdate2(
|
|
20833
|
+
void runAutoUpdate2(base4, authHeaders, ownVersion).catch(() => {
|
|
20769
20834
|
});
|
|
20770
20835
|
}
|
|
20771
20836
|
}
|
|
@@ -20774,7 +20839,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20774
20839
|
const retryable = res.status === 429 || res.status >= 500;
|
|
20775
20840
|
const text = await res.text().catch(() => "");
|
|
20776
20841
|
if (res.status === 401 || res.status === 403) {
|
|
20777
|
-
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${
|
|
20842
|
+
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base4}`);
|
|
20778
20843
|
}
|
|
20779
20844
|
if (res.status === 402) {
|
|
20780
20845
|
let detail = text;
|
|
@@ -20795,7 +20860,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20795
20860
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
20796
20861
|
const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
|
|
20797
20862
|
const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
|
|
20798
|
-
console.error(`[sync] HTTP ${res.status} from ${
|
|
20863
|
+
console.error(`[sync] HTTP ${res.status} from ${base4}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
|
|
20799
20864
|
await sleep2(waitMs);
|
|
20800
20865
|
continue;
|
|
20801
20866
|
} catch (err) {
|
|
@@ -20863,11 +20928,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20863
20928
|
}
|
|
20864
20929
|
};
|
|
20865
20930
|
};
|
|
20866
|
-
const
|
|
20867
|
-
const ledger = opts.useLedger ? getSyncedRows(
|
|
20931
|
+
const base4 = cred.serverUrl.replace(/\/$/, "");
|
|
20932
|
+
const ledger = opts.useLedger ? getSyncedRows(base4) : null;
|
|
20868
20933
|
const convBatch = makeBatcher("conversations", 25, false, (rows) => {
|
|
20869
20934
|
try {
|
|
20870
|
-
markSynced(
|
|
20935
|
+
markSynced(base4, rows.map((r) => {
|
|
20871
20936
|
const off = typeof r.from_offset === "number" ? r.from_offset : 0;
|
|
20872
20937
|
const hash = shippedHash.get(r.session_id);
|
|
20873
20938
|
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 };
|
|
@@ -20882,7 +20947,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20882
20947
|
const ac = new AbortController();
|
|
20883
20948
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
20884
20949
|
try {
|
|
20885
|
-
const res = await fetch(`${
|
|
20950
|
+
const res = await fetch(`${base4}/api/sync`, {
|
|
20886
20951
|
method: "POST",
|
|
20887
20952
|
headers,
|
|
20888
20953
|
body: JSON.stringify({ conversations: convs }),
|
|
@@ -20893,10 +20958,10 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20893
20958
|
if (body2.cli && body2.cli.version) {
|
|
20894
20959
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
20895
20960
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
20896
|
-
const plan = planAutoUpdate2(
|
|
20961
|
+
const plan = planAutoUpdate2(base4, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20897
20962
|
sweepStaleStaging2();
|
|
20898
20963
|
if (plan.update) {
|
|
20899
|
-
void runAutoUpdate2(
|
|
20964
|
+
void runAutoUpdate2(base4, authHeaders, ownVersion).catch(() => {
|
|
20900
20965
|
});
|
|
20901
20966
|
}
|
|
20902
20967
|
}
|
|
@@ -20904,7 +20969,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20904
20969
|
const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
|
|
20905
20970
|
if (acked.length > 0) {
|
|
20906
20971
|
try {
|
|
20907
|
-
markSynced(
|
|
20972
|
+
markSynced(base4, acked.map((c) => ({
|
|
20908
20973
|
id: c.session_id,
|
|
20909
20974
|
mtime: c.mtime,
|
|
20910
20975
|
offset: c.from_offset,
|
|
@@ -20928,7 +20993,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20928
20993
|
const ac = new AbortController();
|
|
20929
20994
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
20930
20995
|
try {
|
|
20931
|
-
const res = await fetch(`${
|
|
20996
|
+
const res = await fetch(`${base4}/api/sync`, {
|
|
20932
20997
|
method: "POST",
|
|
20933
20998
|
headers,
|
|
20934
20999
|
body: JSON.stringify({ conversations: [conv] }),
|
|
@@ -20941,11 +21006,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20941
21006
|
const mtime = conv.mtime;
|
|
20942
21007
|
try {
|
|
20943
21008
|
if (!guarded) {
|
|
20944
|
-
markSynced(
|
|
21009
|
+
markSynced(base4, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
|
|
20945
21010
|
} else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
|
|
20946
|
-
markSynced(
|
|
21011
|
+
markSynced(base4, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
|
|
20947
21012
|
} else {
|
|
20948
|
-
markSynced(
|
|
21013
|
+
markSynced(base4, [{ id, mtime }]);
|
|
20949
21014
|
}
|
|
20950
21015
|
} catch {
|
|
20951
21016
|
}
|
|
@@ -21011,7 +21076,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21011
21076
|
const m = process.memoryUsage();
|
|
21012
21077
|
console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
|
|
21013
21078
|
} : null;
|
|
21014
|
-
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${
|
|
21079
|
+
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base4}`);
|
|
21015
21080
|
if (upload.sessionMeta) {
|
|
21016
21081
|
try {
|
|
21017
21082
|
await reconcileFieldsForTarget(
|
|
@@ -21026,7 +21091,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21026
21091
|
{ convRefs: slice }
|
|
21027
21092
|
);
|
|
21028
21093
|
} catch (e) {
|
|
21029
|
-
console.error(`[sync] field reconcile (${
|
|
21094
|
+
console.error(`[sync] field reconcile (${base4}): ${e instanceof Error ? e.message : e}`);
|
|
21030
21095
|
}
|
|
21031
21096
|
}
|
|
21032
21097
|
trace?.("field reconcile done");
|
|
@@ -21068,7 +21133,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21068
21133
|
}
|
|
21069
21134
|
trace?.("conversation walk start");
|
|
21070
21135
|
const walkStartedAt = Date.now();
|
|
21071
|
-
const firstWalk = (ledger ?? getSyncedRows(
|
|
21136
|
+
const firstWalk = (ledger ?? getSyncedRows(base4)).size === 0;
|
|
21072
21137
|
reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
|
|
21073
21138
|
walkProgressForUpload = { done: 0, total: slice.length, complete: false };
|
|
21074
21139
|
let traceN = 0;
|
|
@@ -21108,7 +21173,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21108
21173
|
continue;
|
|
21109
21174
|
} else {
|
|
21110
21175
|
try {
|
|
21111
|
-
markSynced(
|
|
21176
|
+
markSynced(base4, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21112
21177
|
} catch {
|
|
21113
21178
|
}
|
|
21114
21179
|
skipped++;
|
|
@@ -21131,7 +21196,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21131
21196
|
const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
|
|
21132
21197
|
const priorCursor = ackRow?.s ?? 0;
|
|
21133
21198
|
const safeToAck = off > 0 && off <= priorCursor;
|
|
21134
|
-
markSynced(
|
|
21199
|
+
markSynced(base4, [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 }]);
|
|
21135
21200
|
} catch {
|
|
21136
21201
|
}
|
|
21137
21202
|
}
|
|
@@ -21141,7 +21206,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21141
21206
|
if (!built) {
|
|
21142
21207
|
if (ledger) {
|
|
21143
21208
|
try {
|
|
21144
|
-
markSynced(
|
|
21209
|
+
markSynced(base4, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21145
21210
|
} catch {
|
|
21146
21211
|
}
|
|
21147
21212
|
}
|
|
@@ -21198,7 +21263,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21198
21263
|
walked++;
|
|
21199
21264
|
if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
|
|
21200
21265
|
}
|
|
21201
|
-
const itemVersions = loadItemVersions(
|
|
21266
|
+
const itemVersions = loadItemVersions(base4);
|
|
21202
21267
|
const seenTools = /* @__PURE__ */ new Set();
|
|
21203
21268
|
const seenItemKeys = /* @__PURE__ */ new Map();
|
|
21204
21269
|
const registry = buildSourceRegistry();
|
|
@@ -21292,7 +21357,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21292
21357
|
await appendFlush();
|
|
21293
21358
|
for (const id of appendResults.fullResyncNeeded) {
|
|
21294
21359
|
try {
|
|
21295
|
-
markFullResync(
|
|
21360
|
+
markFullResync(base4, id);
|
|
21296
21361
|
} catch {
|
|
21297
21362
|
}
|
|
21298
21363
|
}
|
|
@@ -21305,7 +21370,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21305
21370
|
await findingsBatch.drain();
|
|
21306
21371
|
await drainInflight();
|
|
21307
21372
|
{
|
|
21308
|
-
const sentHashes = loadInventoryHashes(
|
|
21373
|
+
const sentHashes = loadInventoryHashes(base4);
|
|
21309
21374
|
const entries = [];
|
|
21310
21375
|
const hashes = {};
|
|
21311
21376
|
for (const [sourceType, ids] of inventory) {
|
|
@@ -21319,7 +21384,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21319
21384
|
if (entries.length > 0) {
|
|
21320
21385
|
try {
|
|
21321
21386
|
await post({ inventory: entries });
|
|
21322
|
-
saveInventoryHashes(
|
|
21387
|
+
saveInventoryHashes(base4, hashes);
|
|
21323
21388
|
} catch (err) {
|
|
21324
21389
|
console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
|
|
21325
21390
|
}
|
|
@@ -21330,7 +21395,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21330
21395
|
const rec = {};
|
|
21331
21396
|
for (const t of seenTools) rec[t] = extractorVersionForTool(t);
|
|
21332
21397
|
for (const [k, v] of seenItemKeys) rec[k] = v;
|
|
21333
|
-
saveItemVersions(
|
|
21398
|
+
saveItemVersions(base4, rec);
|
|
21334
21399
|
} catch {
|
|
21335
21400
|
}
|
|
21336
21401
|
}
|
|
@@ -21343,9 +21408,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21343
21408
|
}
|
|
21344
21409
|
if (tombstones.length > 0) {
|
|
21345
21410
|
await post({ tombstones });
|
|
21346
|
-
const data = getLedgerData(
|
|
21411
|
+
const data = getLedgerData(base4);
|
|
21347
21412
|
for (const t of tombstones) delete data[t.session_id];
|
|
21348
|
-
persistLedgerData(
|
|
21413
|
+
persistLedgerData(base4, data);
|
|
21349
21414
|
}
|
|
21350
21415
|
}
|
|
21351
21416
|
if (opts.prune) await post({ prune_empty_sessions: true });
|
|
@@ -21816,7 +21881,7 @@ var init_sync_client = __esm({
|
|
|
21816
21881
|
ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21817
21882
|
} catch {
|
|
21818
21883
|
try {
|
|
21819
|
-
if (true) ownVersion = "0.7.
|
|
21884
|
+
if (true) ownVersion = "0.7.15";
|
|
21820
21885
|
} catch {
|
|
21821
21886
|
}
|
|
21822
21887
|
}
|
|
@@ -21910,9 +21975,9 @@ async function refreshUpdateCheck(force = false) {
|
|
|
21910
21975
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
21911
21976
|
for (const cred of loadAllCredentials2()) {
|
|
21912
21977
|
if (!cred.serverUrl) continue;
|
|
21913
|
-
const
|
|
21978
|
+
const base4 = cred.serverUrl.replace(/\/+$/, "");
|
|
21914
21979
|
try {
|
|
21915
|
-
const res = await fetchWithTimeout(`${
|
|
21980
|
+
const res = await fetchWithTimeout(`${base4}/api/capabilities`, {
|
|
21916
21981
|
headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
|
|
21917
21982
|
}, 5e3);
|
|
21918
21983
|
if (!res.ok) continue;
|
|
@@ -21967,11 +22032,11 @@ var init_update_notice = __esm({
|
|
|
21967
22032
|
});
|
|
21968
22033
|
|
|
21969
22034
|
// ../engine/dist/core/which.js
|
|
21970
|
-
import { existsSync as existsSync42, statSync as
|
|
22035
|
+
import { existsSync as existsSync42, statSync as statSync39, accessSync, constants } from "node:fs";
|
|
21971
22036
|
import { join as join44, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
|
|
21972
22037
|
function executable(p) {
|
|
21973
22038
|
try {
|
|
21974
|
-
if (!
|
|
22039
|
+
if (!statSync39(p).isFile())
|
|
21975
22040
|
return false;
|
|
21976
22041
|
} catch {
|
|
21977
22042
|
return false;
|
|
@@ -22300,7 +22365,7 @@ __export(companions_exports, {
|
|
|
22300
22365
|
uninstallCodeindex: () => uninstallCodeindex,
|
|
22301
22366
|
unregisterCodeindexMcp: () => unregisterCodeindexMcp
|
|
22302
22367
|
});
|
|
22303
|
-
import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as
|
|
22368
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync40, chmodSync as chmodSync4, unlinkSync as unlinkSync3, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync38, writeFileSync as writeFileSync13 } from "node:fs";
|
|
22304
22369
|
import { homedir as homedir17 } from "node:os";
|
|
22305
22370
|
import { join as join47 } from "node:path";
|
|
22306
22371
|
import { execSync as execSync3 } from "node:child_process";
|
|
@@ -22351,7 +22416,7 @@ function checkCodeindexStatus() {
|
|
|
22351
22416
|
status.installed = true;
|
|
22352
22417
|
status.path = foundPath;
|
|
22353
22418
|
try {
|
|
22354
|
-
status.size =
|
|
22419
|
+
status.size = statSync40(foundPath).size;
|
|
22355
22420
|
} catch {
|
|
22356
22421
|
}
|
|
22357
22422
|
try {
|
|
@@ -22501,7 +22566,7 @@ __export(install_skills_exports, {
|
|
|
22501
22566
|
skillsSourceDir: () => skillsSourceDir,
|
|
22502
22567
|
uninstallSkills: () => uninstallSkills
|
|
22503
22568
|
});
|
|
22504
|
-
import { readdirSync as readdirSync32, existsSync as existsSync46, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync39, statSync as
|
|
22569
|
+
import { readdirSync as readdirSync32, existsSync as existsSync46, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync14, readFileSync as readFileSync39, statSync as statSync41, realpathSync as realpathSync4 } from "fs";
|
|
22505
22570
|
import { createHash as createHash11 } from "crypto";
|
|
22506
22571
|
import { join as join48, basename as basename21 } from "path";
|
|
22507
22572
|
function skillsSourceDir() {
|
|
@@ -22720,10 +22785,10 @@ function parseAgentText(content, format, fallbackName) {
|
|
|
22720
22785
|
return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body2.trim() };
|
|
22721
22786
|
}
|
|
22722
22787
|
function readCommand(filePath, format) {
|
|
22723
|
-
return parseCommandText(readFileSync40(filePath, "utf-8"), format,
|
|
22788
|
+
return parseCommandText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
|
|
22724
22789
|
}
|
|
22725
22790
|
function readAgent(filePath, format) {
|
|
22726
|
-
return parseAgentText(readFileSync40(filePath, "utf-8"), format,
|
|
22791
|
+
return parseAgentText(readFileSync40(filePath, "utf-8"), format, base2(filePath));
|
|
22727
22792
|
}
|
|
22728
22793
|
function readInstructions(filePath, name) {
|
|
22729
22794
|
const content = readFileSync40(filePath, "utf-8");
|
|
@@ -22823,7 +22888,7 @@ function emit(type, art, toTool, projectPath) {
|
|
|
22823
22888
|
content: stringifyFrontmatter({ name: art.name, description: art.description, ...art.tools ? { tools: art.tools } : {} }, art.body)
|
|
22824
22889
|
};
|
|
22825
22890
|
}
|
|
22826
|
-
function
|
|
22891
|
+
function base2(filePath) {
|
|
22827
22892
|
return basename22(filePath).replace(/\.(md|toml)$/, "");
|
|
22828
22893
|
}
|
|
22829
22894
|
var init_artifact_codec = __esm({
|
|
@@ -23308,11 +23373,11 @@ __export(toolkit_pull_exports, {
|
|
|
23308
23373
|
platformRefusal: () => platformRefusal,
|
|
23309
23374
|
portableCommand: () => portableCommand
|
|
23310
23375
|
});
|
|
23311
|
-
import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as
|
|
23376
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync42, writeFileSync as writeFileSync16 } from "node:fs";
|
|
23312
23377
|
import { dirname as dirname23, join as join51, basename as basename24, isAbsolute as isAbsolute3 } from "node:path";
|
|
23313
23378
|
function isExecutableFile(p) {
|
|
23314
23379
|
try {
|
|
23315
|
-
return
|
|
23380
|
+
return statSync42(p).isFile();
|
|
23316
23381
|
} catch {
|
|
23317
23382
|
return false;
|
|
23318
23383
|
}
|
|
@@ -23326,9 +23391,9 @@ function portableCommand(cmd) {
|
|
|
23326
23391
|
}
|
|
23327
23392
|
if (isExecutableFile(cmd))
|
|
23328
23393
|
return { command: cmd, rewritten: false };
|
|
23329
|
-
const
|
|
23330
|
-
if (onPath(
|
|
23331
|
-
return { command:
|
|
23394
|
+
const base4 = basename24(cmd);
|
|
23395
|
+
if (onPath(base4))
|
|
23396
|
+
return { command: base4, rewritten: true };
|
|
23332
23397
|
return { missing: cmd };
|
|
23333
23398
|
}
|
|
23334
23399
|
function entryFromSpec(spec) {
|
|
@@ -24162,8 +24227,8 @@ import { homedir as homedir20 } from "os";
|
|
|
24162
24227
|
import { join as join53 } from "path";
|
|
24163
24228
|
function opencodeConfigDir() {
|
|
24164
24229
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
24165
|
-
const
|
|
24166
|
-
return join53(
|
|
24230
|
+
const base4 = xdg && xdg.trim() ? xdg : join53(homedir20(), ".config");
|
|
24231
|
+
return join53(base4, "opencode");
|
|
24167
24232
|
}
|
|
24168
24233
|
function opencodePluginDir() {
|
|
24169
24234
|
return join53(opencodeConfigDir(), "plugins");
|
|
@@ -24750,17 +24815,17 @@ async function collectCode(opts) {
|
|
|
24750
24815
|
return r;
|
|
24751
24816
|
};
|
|
24752
24817
|
log6(`indexing ${ws} + analyses \u2026`);
|
|
24753
|
-
const
|
|
24818
|
+
const base4 = await runMcp(bin, ws, [
|
|
24754
24819
|
call(1, "index_workspace", { path: ws }),
|
|
24755
24820
|
call(2, "status"),
|
|
24756
24821
|
call(3, "get_tree"),
|
|
24757
24822
|
...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
|
|
24758
24823
|
]);
|
|
24759
|
-
const st = parseJson(
|
|
24760
|
-
const tree = parseJson(
|
|
24824
|
+
const st = parseJson(base4, 2, {});
|
|
24825
|
+
const tree = parseJson(base4, 3, []);
|
|
24761
24826
|
const A = {};
|
|
24762
24827
|
ANALYSES.forEach((a, i) => {
|
|
24763
|
-
A[a] = parseJson(
|
|
24828
|
+
A[a] = parseJson(base4, 10 + i, {});
|
|
24764
24829
|
});
|
|
24765
24830
|
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;
|
|
24766
24831
|
if (tree.length === 0) {
|
|
@@ -25589,7 +25654,7 @@ __export(project_tasks_exports, {
|
|
|
25589
25654
|
pushProjectTaskStatuses: () => pushProjectTaskStatuses,
|
|
25590
25655
|
renderTeamTasksMd: () => renderTeamTasksMd
|
|
25591
25656
|
});
|
|
25592
|
-
import { existsSync as existsSync51, readFileSync as readFileSync44, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as
|
|
25657
|
+
import { existsSync as existsSync51, readFileSync as readFileSync44, writeFileSync as writeFileSync18, mkdirSync as mkdirSync18, statSync as statSync43 } from "node:fs";
|
|
25593
25658
|
import { join as join55, dirname as dirname25 } from "node:path";
|
|
25594
25659
|
import { homedir as homedir21 } from "node:os";
|
|
25595
25660
|
function isTeamTaskStatus(v) {
|
|
@@ -25660,14 +25725,14 @@ function writeLedger(l) {
|
|
|
25660
25725
|
} catch {
|
|
25661
25726
|
}
|
|
25662
25727
|
}
|
|
25663
|
-
async function pushProjectTaskStatuses(
|
|
25728
|
+
async function pushProjectTaskStatuses(base4, authHeaders, opts = {}) {
|
|
25664
25729
|
const out = { files: 0, pushedTasks: 0 };
|
|
25665
25730
|
const ledger = readLedger();
|
|
25666
25731
|
let ledgerDirty = false;
|
|
25667
25732
|
for (const fk of FILE_KINDS) {
|
|
25668
25733
|
let projects;
|
|
25669
25734
|
try {
|
|
25670
|
-
const res = await fetchWithTimeout(`${
|
|
25735
|
+
const res = await fetchWithTimeout(`${base4}${fk.trackedPath}`, { headers: authHeaders });
|
|
25671
25736
|
if (!res.ok) continue;
|
|
25672
25737
|
projects = (await res.json()).projects || [];
|
|
25673
25738
|
} catch {
|
|
@@ -25678,7 +25743,7 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
|
|
|
25678
25743
|
if (!existsSync51(file)) continue;
|
|
25679
25744
|
let mtime;
|
|
25680
25745
|
try {
|
|
25681
|
-
mtime =
|
|
25746
|
+
mtime = statSync43(file).mtimeMs;
|
|
25682
25747
|
} catch {
|
|
25683
25748
|
continue;
|
|
25684
25749
|
}
|
|
@@ -25695,7 +25760,7 @@ async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
|
|
|
25695
25760
|
continue;
|
|
25696
25761
|
}
|
|
25697
25762
|
try {
|
|
25698
|
-
const res = await fetchWithTimeout(`${
|
|
25763
|
+
const res = await fetchWithTimeout(`${base4}${fk.statusPath}`, {
|
|
25699
25764
|
method: "POST",
|
|
25700
25765
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
25701
25766
|
body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
|
|
@@ -25821,16 +25886,16 @@ ${block}`);
|
|
|
25821
25886
|
return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
|
|
25822
25887
|
}
|
|
25823
25888
|
}
|
|
25824
|
-
async function runPull(
|
|
25889
|
+
async function runPull(base4, opts) {
|
|
25825
25890
|
const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
|
|
25826
25891
|
const { hostname: hostname3 } = await import("node:os");
|
|
25827
|
-
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") ===
|
|
25892
|
+
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base4.replace(/\/+$/, ""));
|
|
25828
25893
|
const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
|
|
25829
25894
|
const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
|
|
25830
25895
|
const rows = [];
|
|
25831
25896
|
for (const type of wanted) {
|
|
25832
25897
|
try {
|
|
25833
|
-
const res = await fetchWithTimeout(`${
|
|
25898
|
+
const res = await fetchWithTimeout(`${base4}/api/toolkit/browse/${type}?limit=1000`, { headers });
|
|
25834
25899
|
if (!res.ok) continue;
|
|
25835
25900
|
const body2 = await res.json();
|
|
25836
25901
|
for (const it of body2.items || []) rows.push(it);
|
|
@@ -25899,20 +25964,20 @@ async function runIntent(intent, ctx) {
|
|
|
25899
25964
|
async function drainSyncIntents(opts = {}) {
|
|
25900
25965
|
const out = { processed: 0, done: 0, errored: 0 };
|
|
25901
25966
|
for (const cred of loadAllCredentials()) {
|
|
25902
|
-
const
|
|
25967
|
+
const base4 = cred.serverUrl.replace(/\/+$/, "");
|
|
25903
25968
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
25904
25969
|
let pending;
|
|
25905
25970
|
try {
|
|
25906
|
-
const res = await fetchWithTimeout(`${
|
|
25971
|
+
const res = await fetchWithTimeout(`${base4}/api/sync-intents/pending`, { headers: authHeaders });
|
|
25907
25972
|
if (!res.ok) continue;
|
|
25908
25973
|
const data = await res.json();
|
|
25909
25974
|
pending = data.intents || [];
|
|
25910
25975
|
if (data.cli && data.cli.version) {
|
|
25911
25976
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
25912
|
-
const plan = planAutoUpdate2(
|
|
25977
|
+
const plan = planAutoUpdate2(base4, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
25913
25978
|
sweepStaleStaging2();
|
|
25914
25979
|
if (plan.update) {
|
|
25915
|
-
void runAutoUpdate2(
|
|
25980
|
+
void runAutoUpdate2(base4, authHeaders, ownVersion2).catch(() => {
|
|
25916
25981
|
});
|
|
25917
25982
|
}
|
|
25918
25983
|
}
|
|
@@ -25920,7 +25985,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
25920
25985
|
continue;
|
|
25921
25986
|
}
|
|
25922
25987
|
for (const intent of pending) {
|
|
25923
|
-
const { status, result } = await runIntent(intent, { base:
|
|
25988
|
+
const { status, result } = await runIntent(intent, { base: base4 });
|
|
25924
25989
|
out.processed++;
|
|
25925
25990
|
if (status === "done") out.done++;
|
|
25926
25991
|
else out.errored++;
|
|
@@ -25929,7 +25994,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
25929
25994
|
console.error(`[sync-intent] ${label}: ${status}`);
|
|
25930
25995
|
}
|
|
25931
25996
|
try {
|
|
25932
|
-
await fetchWithTimeout(`${
|
|
25997
|
+
await fetchWithTimeout(`${base4}/api/sync-intents/${intent.id}/ack`, {
|
|
25933
25998
|
method: "POST",
|
|
25934
25999
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
25935
26000
|
body: JSON.stringify({ status, result })
|
|
@@ -25938,7 +26003,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
25938
26003
|
}
|
|
25939
26004
|
}
|
|
25940
26005
|
try {
|
|
25941
|
-
await pushProjectTaskStatuses(
|
|
26006
|
+
await pushProjectTaskStatuses(base4, authHeaders, { verbose: opts.verbose });
|
|
25942
26007
|
} catch {
|
|
25943
26008
|
}
|
|
25944
26009
|
}
|
|
@@ -25978,7 +26043,7 @@ var init_intent_drain = __esm({
|
|
|
25978
26043
|
ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25979
26044
|
} catch {
|
|
25980
26045
|
try {
|
|
25981
|
-
if (true) ownVersion2 = "0.7.
|
|
26046
|
+
if (true) ownVersion2 = "0.7.15";
|
|
25982
26047
|
} catch {
|
|
25983
26048
|
}
|
|
25984
26049
|
}
|
|
@@ -26179,7 +26244,7 @@ var team_merge_exports = {};
|
|
|
26179
26244
|
__export(team_merge_exports, {
|
|
26180
26245
|
mergePullResult: () => mergePullResult
|
|
26181
26246
|
});
|
|
26182
|
-
import { existsSync as existsSync53, mkdirSync as mkdirSync20, readFileSync as readFileSync46, rmSync as rmSync8, writeFileSync as writeFileSync20, statSync as
|
|
26247
|
+
import { existsSync as existsSync53, mkdirSync as mkdirSync20, readFileSync as readFileSync46, rmSync as rmSync8, writeFileSync as writeFileSync20, statSync as statSync44 } from "fs";
|
|
26183
26248
|
import { dirname as dirname27, join as join57 } from "path";
|
|
26184
26249
|
import { createHash as createHash14 } from "crypto";
|
|
26185
26250
|
function installPathFor(art, tool) {
|
|
@@ -26316,7 +26381,7 @@ function readFileIfExists(path) {
|
|
|
26316
26381
|
try {
|
|
26317
26382
|
if (!existsSync53(path))
|
|
26318
26383
|
return null;
|
|
26319
|
-
const s =
|
|
26384
|
+
const s = statSync44(path);
|
|
26320
26385
|
if (!s.isFile())
|
|
26321
26386
|
return null;
|
|
26322
26387
|
return readFileSync46(path);
|
|
@@ -26400,7 +26465,7 @@ var init_vault_crypto = __esm({
|
|
|
26400
26465
|
});
|
|
26401
26466
|
|
|
26402
26467
|
// ../engine/dist/core/vault-source.js
|
|
26403
|
-
import { existsSync as existsSync54, readdirSync as readdirSync33, statSync as
|
|
26468
|
+
import { existsSync as existsSync54, readdirSync as readdirSync33, statSync as statSync45 } from "fs";
|
|
26404
26469
|
import { extname, join as join58 } from "path";
|
|
26405
26470
|
function* walkVaultSources() {
|
|
26406
26471
|
const t = loadSettings().team.vault;
|
|
@@ -26416,7 +26481,7 @@ function* walkVaultSources() {
|
|
|
26416
26481
|
}
|
|
26417
26482
|
function safeStat(path) {
|
|
26418
26483
|
try {
|
|
26419
|
-
const s =
|
|
26484
|
+
const s = statSync45(path);
|
|
26420
26485
|
if (!s.isFile())
|
|
26421
26486
|
return null;
|
|
26422
26487
|
return { mtimeMs: s.mtimeMs, size: s.size };
|
|
@@ -26501,8 +26566,8 @@ function* walkCodex() {
|
|
|
26501
26566
|
const s = safeStat(path);
|
|
26502
26567
|
if (!s)
|
|
26503
26568
|
continue;
|
|
26504
|
-
const
|
|
26505
|
-
yield { sessionId: `codex_${
|
|
26569
|
+
const base4 = e.name.replace(/\.jsonl$/, "");
|
|
26570
|
+
yield { sessionId: `codex_${base4}`, tool: "codex", path, mtimeMs: s.mtimeMs, sizeBytes: s.size };
|
|
26506
26571
|
}
|
|
26507
26572
|
}
|
|
26508
26573
|
}
|
|
@@ -26519,7 +26584,7 @@ function* walkAgy() {
|
|
|
26519
26584
|
for (const rawId of sessionDirs) {
|
|
26520
26585
|
const sessionPath = join58(brainDir, rawId);
|
|
26521
26586
|
try {
|
|
26522
|
-
if (!
|
|
26587
|
+
if (!statSync45(sessionPath).isDirectory())
|
|
26523
26588
|
continue;
|
|
26524
26589
|
} catch {
|
|
26525
26590
|
continue;
|
|
@@ -26644,11 +26709,11 @@ function vaultEnable(passphrase, opts = {}) {
|
|
|
26644
26709
|
}
|
|
26645
26710
|
async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
|
|
26646
26711
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
26647
|
-
const
|
|
26712
|
+
const base4 = remote.baseUrl.replace(/\/+$/, "");
|
|
26648
26713
|
const headers = { authorization: `Bearer ${remote.token}`, "content-type": "application/json" };
|
|
26649
26714
|
let published = { saltHex: null, keyId: null };
|
|
26650
26715
|
try {
|
|
26651
|
-
const r = await doFetch(`${
|
|
26716
|
+
const r = await doFetch(`${base4}/api/vault/salt`, { headers });
|
|
26652
26717
|
if (r.ok)
|
|
26653
26718
|
published = await r.json();
|
|
26654
26719
|
} catch {
|
|
@@ -26662,7 +26727,7 @@ async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
|
|
|
26662
26727
|
}
|
|
26663
26728
|
const result = vaultEnable(passphrase);
|
|
26664
26729
|
try {
|
|
26665
|
-
const r = await doFetch(`${
|
|
26730
|
+
const r = await doFetch(`${base4}/api/vault/salt`, {
|
|
26666
26731
|
method: "POST",
|
|
26667
26732
|
headers,
|
|
26668
26733
|
body: JSON.stringify({ saltHex: result.saltHex, keyId: result.keyId })
|
|
@@ -26755,8 +26820,8 @@ async function vaultSync(passphrase) {
|
|
|
26755
26820
|
return report;
|
|
26756
26821
|
}
|
|
26757
26822
|
function importedPathFor(tool, sessionId) {
|
|
26758
|
-
const
|
|
26759
|
-
return join59(IMPORTED_ROOT(), tool, `${
|
|
26823
|
+
const base4 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^agy_/, "").replace(/^cursor_/, "").replace(/^opencode_/, "");
|
|
26824
|
+
return join59(IMPORTED_ROOT(), tool, `${base4}.jsonl`);
|
|
26760
26825
|
}
|
|
26761
26826
|
async function vaultRestore(passphrase, opts = {}) {
|
|
26762
26827
|
const ctx = context2();
|
|
@@ -27157,8 +27222,8 @@ var init_decision_guard = __esm({
|
|
|
27157
27222
|
isManifest = (p) => {
|
|
27158
27223
|
if (!p)
|
|
27159
27224
|
return false;
|
|
27160
|
-
const
|
|
27161
|
-
return MANIFESTS.includes(
|
|
27225
|
+
const base4 = p.split(/[\\/]/).pop()?.toLowerCase() ?? "";
|
|
27226
|
+
return MANIFESTS.includes(base4);
|
|
27162
27227
|
};
|
|
27163
27228
|
}
|
|
27164
27229
|
});
|
|
@@ -27756,8 +27821,8 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
27756
27821
|
throw new Error("device-auth timed out \u2014 the code expired before approval.");
|
|
27757
27822
|
}
|
|
27758
27823
|
async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
27759
|
-
const
|
|
27760
|
-
const startRes = await fetch(`${
|
|
27824
|
+
const base4 = serverUrl.replace(/\/+$/, "");
|
|
27825
|
+
const startRes = await fetch(`${base4}/api/auth/device/code`, {
|
|
27761
27826
|
method: "POST",
|
|
27762
27827
|
headers: { "content-type": "application/json" },
|
|
27763
27828
|
body: JSON.stringify({ client_id: BETTER_AUTH_CLI_CLIENT_ID })
|
|
@@ -27765,7 +27830,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27765
27830
|
if (!startRes.ok) {
|
|
27766
27831
|
throw new Error(`device-auth init failed: HTTP ${startRes.status} ${await startRes.text().catch(() => "")}`);
|
|
27767
27832
|
}
|
|
27768
|
-
const start = await readDeviceCode(startRes,
|
|
27833
|
+
const start = await readDeviceCode(startRes, base4);
|
|
27769
27834
|
onPrompt({
|
|
27770
27835
|
url: start.verification_uri_complete || start.verification_uri,
|
|
27771
27836
|
userCode: start.user_code,
|
|
@@ -27775,7 +27840,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27775
27840
|
let interval = (start.interval ?? 5) * 1e3;
|
|
27776
27841
|
while (Date.now() < deadline) {
|
|
27777
27842
|
await sleep(interval);
|
|
27778
|
-
const res = await fetch(`${
|
|
27843
|
+
const res = await fetch(`${base4}/api/auth/device/token`, {
|
|
27779
27844
|
method: "POST",
|
|
27780
27845
|
headers: { "content-type": "application/json" },
|
|
27781
27846
|
body: JSON.stringify({
|
|
@@ -27877,7 +27942,7 @@ async function selectSessions(target, opts, fetchImpl = fetch) {
|
|
|
27877
27942
|
const qs = new URLSearchParams({ limit: String(PAGE), offset: String(offset) });
|
|
27878
27943
|
if (opts.project) qs.set("project", opts.project);
|
|
27879
27944
|
if (opts.tool) qs.set("tool", opts.tool);
|
|
27880
|
-
const res = await fetchImpl(`${
|
|
27945
|
+
const res = await fetchImpl(`${base3(target.serverUrl)}/api/conversations/recent?${qs}`, {
|
|
27881
27946
|
headers: { authorization: `Bearer ${target.token}` }
|
|
27882
27947
|
});
|
|
27883
27948
|
if (!res.ok) throw new Error(`list failed: HTTP ${res.status}`);
|
|
@@ -27906,7 +27971,7 @@ async function bulkDelete(ids, opts = {}) {
|
|
|
27906
27971
|
try {
|
|
27907
27972
|
for (let i = 0; i < unique.length; i += BATCH) {
|
|
27908
27973
|
const slice = unique.slice(i, i + BATCH);
|
|
27909
|
-
const res = await fetchImpl(`${
|
|
27974
|
+
const res = await fetchImpl(`${base3(t.serverUrl)}/api/sync`, {
|
|
27910
27975
|
method: "POST",
|
|
27911
27976
|
headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
|
|
27912
27977
|
body: JSON.stringify({
|
|
@@ -27942,7 +28007,7 @@ async function bulkDelete(ids, opts = {}) {
|
|
|
27942
28007
|
return out;
|
|
27943
28008
|
}
|
|
27944
28009
|
async function listTombstones(target, limit = 500, fetchImpl = fetch) {
|
|
27945
|
-
const res = await fetchImpl(`${
|
|
28010
|
+
const res = await fetchImpl(`${base3(target.serverUrl)}/api/data/tombstones?limit=${limit}`, {
|
|
27946
28011
|
headers: { authorization: `Bearer ${target.token}` }
|
|
27947
28012
|
});
|
|
27948
28013
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
@@ -27959,7 +28024,7 @@ async function restoreSessions(ids, opts = {}) {
|
|
|
27959
28024
|
try {
|
|
27960
28025
|
let restored = 0, notDeleted = 0;
|
|
27961
28026
|
for (let i = 0; i < unique.length; i += BATCH) {
|
|
27962
|
-
const res = await fetchImpl(`${
|
|
28027
|
+
const res = await fetchImpl(`${base3(t.serverUrl)}/api/data/restore`, {
|
|
27963
28028
|
method: "POST",
|
|
27964
28029
|
headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
|
|
27965
28030
|
body: JSON.stringify({ session_ids: unique.slice(i, i + BATCH) })
|
|
@@ -27982,7 +28047,7 @@ function needsConfirmation(opts) {
|
|
|
27982
28047
|
const enumeratedByCaller = opts.argvIds > 0 && !opts.project && !opts.stdin;
|
|
27983
28048
|
return !enumeratedByCaller;
|
|
27984
28049
|
}
|
|
27985
|
-
var PAGE, BATCH,
|
|
28050
|
+
var PAGE, BATCH, base3;
|
|
27986
28051
|
var init_bulk_delete = __esm({
|
|
27987
28052
|
"src/bulk-delete.ts"() {
|
|
27988
28053
|
"use strict";
|
|
@@ -27990,7 +28055,7 @@ var init_bulk_delete = __esm({
|
|
|
27990
28055
|
init_sync_ledger();
|
|
27991
28056
|
PAGE = 200;
|
|
27992
28057
|
BATCH = 250;
|
|
27993
|
-
|
|
28058
|
+
base3 = (url) => url.replace(/\/+$/, "");
|
|
27994
28059
|
}
|
|
27995
28060
|
});
|
|
27996
28061
|
|
|
@@ -28355,13 +28420,13 @@ function requireTarget() {
|
|
|
28355
28420
|
}
|
|
28356
28421
|
return t;
|
|
28357
28422
|
}
|
|
28358
|
-
async function readJsonBody(res,
|
|
28423
|
+
async function readJsonBody(res, base4, what) {
|
|
28359
28424
|
const text = await res.text().catch(() => "");
|
|
28360
28425
|
try {
|
|
28361
28426
|
return JSON.parse(text);
|
|
28362
28427
|
} catch {
|
|
28363
28428
|
throw new Error(
|
|
28364
|
-
`${
|
|
28429
|
+
`${base4} 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`
|
|
28365
28430
|
);
|
|
28366
28431
|
}
|
|
28367
28432
|
}
|
|
@@ -29167,9 +29232,9 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
29167
29232
|
return;
|
|
29168
29233
|
}
|
|
29169
29234
|
const target = firstTarget();
|
|
29170
|
-
const
|
|
29235
|
+
const base4 = target?.base || (process.env.CHAT_RECALL_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
|
|
29171
29236
|
try {
|
|
29172
|
-
const res = await fetch(`${
|
|
29237
|
+
const res = await fetch(`${base4}/api/contact/feedback`, {
|
|
29173
29238
|
method: "POST",
|
|
29174
29239
|
headers: {
|
|
29175
29240
|
"content-type": "application/json",
|
|
@@ -29196,14 +29261,14 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
29196
29261
|
console.log(chalk2.dim(" Add --email <address> next time if you want a reply."));
|
|
29197
29262
|
}
|
|
29198
29263
|
} catch (err) {
|
|
29199
|
-
console.error(chalk2.red(`Could not reach ${
|
|
29264
|
+
console.error(chalk2.red(`Could not reach ${base4}.`));
|
|
29200
29265
|
console.error(chalk2.dim(" Your message, so it is not lost:"));
|
|
29201
29266
|
console.error(chalk2.dim(` ${message}`));
|
|
29202
29267
|
process.exitCode = 1;
|
|
29203
29268
|
}
|
|
29204
29269
|
});
|
|
29205
29270
|
program.command("doctor").description("Quick health check across login, server, credentials, hooks, MCP server, and codeindex").option("--purge-local", "Remove the legacy local index (cache.db + vector/KG files) left by pre-thin-collector versions \u2014 storage is server-side now. Requires login; keeps credentials, sync ledger, identity, and the audit log.").action(async (opts) => {
|
|
29206
|
-
const { existsSync: existsSync58, readFileSync: readFileSync50, statSync:
|
|
29271
|
+
const { existsSync: existsSync58, readFileSync: readFileSync50, statSync: statSync46 } = await import("fs");
|
|
29207
29272
|
const { execSync: execSync6 } = await import("child_process");
|
|
29208
29273
|
const rows = [];
|
|
29209
29274
|
const note = (ok, label, detail) => rows.push({ ok, label, detail });
|
|
@@ -29271,7 +29336,7 @@ program.command("doctor").description("Quick health check across login, server,
|
|
|
29271
29336
|
note(false, "Credentials file", `missing \u2014 run \`chat-recall login <server-url>\``);
|
|
29272
29337
|
} else {
|
|
29273
29338
|
try {
|
|
29274
|
-
const mode =
|
|
29339
|
+
const mode = statSync46(credFile).mode & 511;
|
|
29275
29340
|
const isWin = process.platform === "win32";
|
|
29276
29341
|
const safe = isWin || (mode & 63) === 0;
|
|
29277
29342
|
note(safe, "Credentials file", isWin ? `${credFile} (Windows ACL \u2014 POSIX mode does not apply)` : `${credFile} (mode ${mode.toString(8).padStart(3, "0")}${safe ? "" : " \u2014 should be 600"})`);
|
|
@@ -29801,13 +29866,13 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
|
|
|
29801
29866
|
}
|
|
29802
29867
|
const { fetchWithTimeout: fetchWithTimeout2 } = await Promise.resolve().then(() => (init_http(), http_exports));
|
|
29803
29868
|
for (const t of targets) {
|
|
29804
|
-
const
|
|
29869
|
+
const base4 = t.serverUrl.replace(/\/+$/, "");
|
|
29805
29870
|
const headers = {};
|
|
29806
29871
|
if (t.token) headers.authorization = `Bearer ${t.token}`;
|
|
29807
29872
|
let deleted = 0, missing = 0, failed = 0;
|
|
29808
29873
|
for (const id of ids) {
|
|
29809
29874
|
try {
|
|
29810
|
-
const res = await fetchWithTimeout2(`${
|
|
29875
|
+
const res = await fetchWithTimeout2(`${base4}/api/conversations/${encodeURIComponent(id)}`, { method: "DELETE", headers }, 3e4);
|
|
29811
29876
|
if (res.ok) deleted++;
|
|
29812
29877
|
else if (res.status === 404) missing++;
|
|
29813
29878
|
else failed++;
|
|
@@ -29815,7 +29880,7 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
|
|
|
29815
29880
|
failed++;
|
|
29816
29881
|
}
|
|
29817
29882
|
}
|
|
29818
|
-
const line = ` ${
|
|
29883
|
+
const line = ` ${base4}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk2.red(`, ${failed} FAILED`) : "");
|
|
29819
29884
|
console.log(failed ? chalk2.yellow(line) : chalk2.green(line));
|
|
29820
29885
|
if (failed) process.exitCode = 1;
|
|
29821
29886
|
}
|
|
@@ -30597,7 +30662,7 @@ program.command("task-hook").description("Move a board card when a prompt or a c
|
|
|
30597
30662
|
}
|
|
30598
30663
|
});
|
|
30599
30664
|
program.command("install-hooks").description("Install Claude Code hooks (Stop + PreCompact + UserPromptSubmit + SessionEnd + SessionStart) into every Claude profile").option("--uninstall", "Remove hooks instead of installing them").option("--no-resume-hint", "Don't install the UserPromptSubmit resume-hint hook").option("--no-escalate", "Don't install the SessionEnd learnings-escalation hook").option("--no-wakeup", "Don't install the SessionStart wake-up hook").option("--no-guard", "Don't install the PreToolUse decision guard").option("--no-task-board", "Don't install the hooks that claim and close board cards").action(async (opts) => {
|
|
30600
|
-
const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync58, readFileSync: readFileSync50, writeFileSync: writeFileSync24, statSync:
|
|
30665
|
+
const { mkdirSync: mkdirSync23, copyFileSync: copyFileSync4, chmodSync: chmodSync5, existsSync: existsSync58, readFileSync: readFileSync50, writeFileSync: writeFileSync24, statSync: statSync46, unlinkSync: unlinkSync4 } = await import("fs");
|
|
30601
30666
|
const { fileURLToPath: fileURLToPath6 } = await import("url");
|
|
30602
30667
|
const { boardHookEntries: boardHookEntries2, isBoardHookEntry: isBoardHookEntry2, registerBoardHooks: registerBoardHooks2, resolveCliEntry: resolveCliEntry2 } = await Promise.resolve().then(() => (init_board_hooks(), board_hooks_exports));
|
|
30603
30668
|
const here = fileURLToPath6(new URL(".", import.meta.url));
|
|
@@ -30812,18 +30877,18 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30812
30877
|
writeFileSync24(hooksJson, JSON.stringify(config2, null, 2) + "\n");
|
|
30813
30878
|
}
|
|
30814
30879
|
if (installGuard) await addGuardToOtherTools(installedGuardHook);
|
|
30815
|
-
const saveSz =
|
|
30880
|
+
const saveSz = statSync46(installedSaveHook).size;
|
|
30816
30881
|
console.log(chalk2.green(`\u2713 Installed chat-recall save hook (${saveSz} bytes)`));
|
|
30817
30882
|
if (installResume) {
|
|
30818
|
-
const resumeSz =
|
|
30883
|
+
const resumeSz = statSync46(installedResumeHook).size;
|
|
30819
30884
|
console.log(chalk2.green(`\u2713 Installed chat-recall resume-hint hook (${resumeSz} bytes)`));
|
|
30820
30885
|
}
|
|
30821
30886
|
if (installEscalate) {
|
|
30822
|
-
const escalateSz =
|
|
30887
|
+
const escalateSz = statSync46(installedEscalateHook).size;
|
|
30823
30888
|
console.log(chalk2.green(`\u2713 Installed chat-recall learnings-escalation hook (${escalateSz} bytes)`));
|
|
30824
30889
|
}
|
|
30825
30890
|
if (installGuard) {
|
|
30826
|
-
const guardSz =
|
|
30891
|
+
const guardSz = statSync46(installedGuardHook).size;
|
|
30827
30892
|
console.log(chalk2.green(`\u2713 Installed chat-recall decision guard (${guardSz} bytes)`));
|
|
30828
30893
|
}
|
|
30829
30894
|
if (installTaskBoard) {
|
|
@@ -30831,7 +30896,7 @@ program.command("install-hooks").description("Install Claude Code hooks (Stop +
|
|
|
30831
30896
|
console.log(chalk2.dim(" A prompt naming a card id claims it; a commit message naming one closes it."));
|
|
30832
30897
|
}
|
|
30833
30898
|
if (installWakeup) {
|
|
30834
|
-
const wakeupSz =
|
|
30899
|
+
const wakeupSz = statSync46(installedWakeupHook).size;
|
|
30835
30900
|
console.log(chalk2.green(`\u2713 Installed chat-recall wake-up hook (${wakeupSz} bytes)`));
|
|
30836
30901
|
for (const f of wakeupSkipped) {
|
|
30837
30902
|
console.log(chalk2.dim(` (SessionStart already wired in ${f} \u2014 left as is, not duplicated)`));
|
|
@@ -30948,10 +31013,10 @@ program.command("service <action>").description("Manage the per-user background
|
|
|
30948
31013
|
});
|
|
30949
31014
|
async function runLogin(serverUrl, opts) {
|
|
30950
31015
|
const { saveCredentials: saveCredentials2, loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
30951
|
-
const
|
|
31016
|
+
const base4 = serverUrl.replace(/\/+$/, "");
|
|
30952
31017
|
const verifyToken = async (token) => {
|
|
30953
31018
|
try {
|
|
30954
|
-
const res = await fetch(`${
|
|
31019
|
+
const res = await fetch(`${base4}/api/status`, {
|
|
30955
31020
|
headers: token ? { authorization: `Bearer ${token}` } : {},
|
|
30956
31021
|
signal: AbortSignal.timeout(1e4)
|
|
30957
31022
|
});
|
|
@@ -30967,36 +31032,36 @@ async function runLogin(serverUrl, opts) {
|
|
|
30967
31032
|
return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
|
|
30968
31033
|
}
|
|
30969
31034
|
const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30970
|
-
const who = await identifyServer(
|
|
30971
|
-
if (!identified(who)) return failLogin(opts, identifyAdvice(who,
|
|
31035
|
+
const who = await identifyServer(base4, { timeoutMs: 1e4 });
|
|
31036
|
+
if (!identified(who)) return failLogin(opts, identifyAdvice(who, base4));
|
|
30972
31037
|
const check = await verifyToken(token);
|
|
30973
31038
|
if (!check.ok) {
|
|
30974
31039
|
if (check.status === 401 || check.status === 403) {
|
|
30975
31040
|
console.error(chalk2.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
|
|
30976
|
-
return failLogin(opts, `${
|
|
31041
|
+
return failLogin(opts, `${base4} rejected the token (HTTP ${check.status})`);
|
|
30977
31042
|
}
|
|
30978
31043
|
if (check.status !== void 0 && check.status >= 500) {
|
|
30979
|
-
return failLogin(opts, `${
|
|
31044
|
+
return failLogin(opts, `${base4} answered HTTP ${check.status} \u2014 the server is up but failing. The token was never checked. Nothing to fix locally.`);
|
|
30980
31045
|
}
|
|
30981
31046
|
if (check.status === 404 || check.status === 410) {
|
|
30982
|
-
return failLogin(opts, `${
|
|
31047
|
+
return failLogin(opts, `${base4} does not serve the chat-recall API (HTTP ${check.status}). If the server moved, log in to its new URL.`);
|
|
30983
31048
|
}
|
|
30984
|
-
return failLogin(opts, `could not verify the token against ${
|
|
31049
|
+
return failLogin(opts, `could not verify the token against ${base4}: ${check.error || `HTTP ${check.status}`}`);
|
|
30985
31050
|
}
|
|
30986
31051
|
saveCredentials2({ serverUrl, token });
|
|
30987
31052
|
console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` server: ${serverUrl} (token verified)`));
|
|
30988
31053
|
return;
|
|
30989
31054
|
}
|
|
30990
|
-
const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") ===
|
|
31055
|
+
const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base4);
|
|
30991
31056
|
if (existing && (await verifyToken(existing.token)).ok) {
|
|
30992
31057
|
console.log(chalk2.green("\u2713 Already connected.") + chalk2.dim(` server: ${serverUrl} (existing token verified)`));
|
|
30993
31058
|
return;
|
|
30994
31059
|
}
|
|
30995
31060
|
try {
|
|
30996
31061
|
const { probeServer: probeServer2, probeOk: probeOk2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30997
|
-
const identified = await probeServer2(
|
|
31062
|
+
const identified = await probeServer2(base4, { timeoutMs: 8e3 });
|
|
30998
31063
|
if (probeOk2(identified)) {
|
|
30999
|
-
const probe = await fetch(`${
|
|
31064
|
+
const probe = await fetch(`${base4}/api/status`, { signal: AbortSignal.timeout(8e3) });
|
|
31000
31065
|
if (probe.status === 200) {
|
|
31001
31066
|
saveCredentials2({ serverUrl, token: "" });
|
|
31002
31067
|
console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
|
|
@@ -31017,16 +31082,16 @@ async function runLogin(serverUrl, opts) {
|
|
|
31017
31082
|
if (!issuer) {
|
|
31018
31083
|
const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
31019
31084
|
for (let attempt = 1; attempt <= 3 && !authProvider; attempt++) {
|
|
31020
|
-
const probe = await probeServer2(
|
|
31085
|
+
const probe = await probeServer2(base4, { timeoutMs: 15e3 });
|
|
31021
31086
|
if (probeOk2(probe)) {
|
|
31022
31087
|
const caps = probe.raw;
|
|
31023
31088
|
authProvider = caps?.authProvider;
|
|
31024
31089
|
if (caps?.oidcIssuer) issuer = caps.oidcIssuer;
|
|
31025
31090
|
capsError = null;
|
|
31026
31091
|
} else if (probe.kind === "moved" || probe.kind === "not_api") {
|
|
31027
|
-
return failLogin(opts, probeAdvice2(probe,
|
|
31092
|
+
return failLogin(opts, probeAdvice2(probe, base4));
|
|
31028
31093
|
} else {
|
|
31029
|
-
capsError = probeAdvice2(probe,
|
|
31094
|
+
capsError = probeAdvice2(probe, base4);
|
|
31030
31095
|
}
|
|
31031
31096
|
if (!authProvider && attempt < 3) await new Promise((r) => setTimeout(r, attempt * 1e3));
|
|
31032
31097
|
}
|
|
@@ -31035,7 +31100,7 @@ async function runLogin(serverUrl, opts) {
|
|
|
31035
31100
|
authProvider = "better-auth";
|
|
31036
31101
|
if (capsError) {
|
|
31037
31102
|
console.log(` ${chalk2.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
|
|
31038
|
-
void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(
|
|
31103
|
+
void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(base4, {
|
|
31039
31104
|
step: "cli_login_probe",
|
|
31040
31105
|
reason: capsError?.slice(0, 40) ?? null,
|
|
31041
31106
|
message: capsError
|
|
@@ -31057,20 +31122,20 @@ async function runLogin(serverUrl, opts) {
|
|
|
31057
31122
|
console.log(chalk2.dim(` If the page asks for a code: ${chalk2.bold(p.userCode)}`));
|
|
31058
31123
|
console.log(chalk2.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
|
|
31059
31124
|
};
|
|
31060
|
-
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(
|
|
31125
|
+
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base4, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
|
|
31061
31126
|
const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
|
|
31062
|
-
const meRes = await fetch(`${
|
|
31063
|
-
if (!meRes.ok) throw new Error(`${
|
|
31064
|
-
const me = await readJsonBody(meRes,
|
|
31127
|
+
const meRes = await fetch(`${base4}/api/me`, { headers: authHdr });
|
|
31128
|
+
if (!meRes.ok) throw new Error(`${base4}/api/me: HTTP ${meRes.status} ${await meRes.text().catch(() => "")}`);
|
|
31129
|
+
const me = await readJsonBody(meRes, base4, "GET /api/me");
|
|
31065
31130
|
const teams = me.teams || [];
|
|
31066
31131
|
let slug = opts.team;
|
|
31067
31132
|
if (!slug) {
|
|
31068
31133
|
if (teams.length === 1) slug = teams[0].team_slug;
|
|
31069
31134
|
else if (teams.length === 0) {
|
|
31070
31135
|
const name = me.user?.email?.split("@")[0]?.replace(/[^a-z0-9]/gi, "") || "workspace";
|
|
31071
|
-
const created = await fetch(`${
|
|
31136
|
+
const created = await fetch(`${base4}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
|
|
31072
31137
|
if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
|
|
31073
|
-
slug = (await readJsonBody(created,
|
|
31138
|
+
slug = (await readJsonBody(created, base4, "POST /api/teams")).slug;
|
|
31074
31139
|
console.log(chalk2.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
|
|
31075
31140
|
} else {
|
|
31076
31141
|
teams.forEach((t) => console.error(` ${t.team_slug} ${chalk2.dim(t.name)}`));
|
|
@@ -31078,13 +31143,13 @@ async function runLogin(serverUrl, opts) {
|
|
|
31078
31143
|
}
|
|
31079
31144
|
}
|
|
31080
31145
|
const deviceId = opts.deviceId || (await import("node:os")).hostname();
|
|
31081
|
-
const mint = await fetch(`${
|
|
31146
|
+
const mint = await fetch(`${base4}/api/teams/${encodeURIComponent(slug)}/tokens`, {
|
|
31082
31147
|
method: "POST",
|
|
31083
31148
|
headers: authHdr,
|
|
31084
31149
|
body: JSON.stringify({ device_id: deviceId })
|
|
31085
31150
|
});
|
|
31086
31151
|
if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
|
|
31087
|
-
const { token } = await readJsonBody(mint,
|
|
31152
|
+
const { token } = await readJsonBody(mint, base4, "POST /api/teams/:slug/tokens");
|
|
31088
31153
|
saveCredentials2({ serverUrl, token });
|
|
31089
31154
|
console.log(chalk2.green(`\u2713 Logged in to ${chalk2.bold(slug)}`) + chalk2.dim(` (device: ${deviceId}) server: ${serverUrl}`));
|
|
31090
31155
|
if (!opts.fromInit) {
|
|
@@ -31561,16 +31626,16 @@ program.command("update").description("Update this CLI now from the server you s
|
|
|
31561
31626
|
}
|
|
31562
31627
|
let installFailed = false;
|
|
31563
31628
|
for (const cred of targets) {
|
|
31564
|
-
const
|
|
31629
|
+
const base4 = cred.serverUrl.replace(/\/+$/, "");
|
|
31565
31630
|
const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
31566
|
-
const r = await runAutoUpdate2(
|
|
31631
|
+
const r = await runAutoUpdate2(base4, headers, cliVersion3());
|
|
31567
31632
|
if (r.updated) {
|
|
31568
|
-
console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${
|
|
31633
|
+
console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base4})`));
|
|
31569
31634
|
continue;
|
|
31570
31635
|
}
|
|
31571
31636
|
const benign = /already current|no CLI release|disabled/.test(r.reason);
|
|
31572
31637
|
if (/install failed|download failed|checksum/.test(r.reason)) installFailed = true;
|
|
31573
|
-
console.log((benign ? chalk2.dim("\u2022 ") : chalk2.red("\u2717 ")) + r.reason + chalk2.dim(` (${
|
|
31638
|
+
console.log((benign ? chalk2.dim("\u2022 ") : chalk2.red("\u2717 ")) + r.reason + chalk2.dim(` (${base4})`));
|
|
31574
31639
|
}
|
|
31575
31640
|
const check = await refreshUpdateCheck2(true);
|
|
31576
31641
|
if (installFailed) {
|