chat-recall 0.5.30 → 0.5.32
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/auto-update.d.ts +0 -4
- package/dist/auto-update.d.ts.map +1 -1
- package/dist/auto-update.js +20 -1
- package/dist/auto-update.js.map +1 -1
- package/dist/bulk-delete.d.ts +131 -0
- package/dist/bulk-delete.d.ts.map +1 -0
- package/dist/bulk-delete.js +211 -0
- package/dist/bulk-delete.js.map +1 -0
- package/dist/cli.js +765 -467
- package/dist/cli.js.map +1 -1
- package/dist/mcp.js +273 -221
- package/dist/scan-worker.js +61 -35
- package/dist/sync-client.d.ts +37 -0
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +109 -16
- package/dist/sync-client.js.map +1 -1
- package/dist/target-breaker.d.ts +13 -0
- package/dist/target-breaker.d.ts.map +1 -1
- package/dist/target-breaker.js +6 -4
- package/dist/target-breaker.js.map +1 -1
- package/dist/telemetry.d.ts +14 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +23 -0
- package/dist/telemetry.js.map +1 -1
- package/dist/watch.js +276 -225
- 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: base3,
|
|
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 (base3 !== null) {
|
|
4302
4302
|
if (name === void 0) {
|
|
4303
|
-
chindings = coreChindings(
|
|
4303
|
+
chindings = coreChindings(base3);
|
|
4304
4304
|
} else {
|
|
4305
|
-
chindings = coreChindings(Object.assign({},
|
|
4305
|
+
chindings = coreChindings(Object.assign({}, base3, { name }));
|
|
4306
4306
|
}
|
|
4307
4307
|
}
|
|
4308
4308
|
const time2 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime;
|
|
@@ -4743,56 +4743,56 @@ function freshDefaults() {
|
|
|
4743
4743
|
team: defaultTeam()
|
|
4744
4744
|
};
|
|
4745
4745
|
}
|
|
4746
|
-
function mergeSources(
|
|
4746
|
+
function mergeSources(base3, partial) {
|
|
4747
4747
|
if (!partial)
|
|
4748
|
-
return
|
|
4748
|
+
return base3;
|
|
4749
4749
|
const enabled = {
|
|
4750
|
-
claude: { ...
|
|
4751
|
-
gemini: { ...
|
|
4752
|
-
opencode: { ...
|
|
4753
|
-
codex: { ...
|
|
4754
|
-
agy: { ...
|
|
4755
|
-
cursor: { ...
|
|
4756
|
-
shared: { ...
|
|
4757
|
-
common: { ...
|
|
4750
|
+
claude: { ...base3.enabled.claude, ...partial.enabled?.claude ?? {} },
|
|
4751
|
+
gemini: { ...base3.enabled.gemini, ...partial.enabled?.gemini ?? {} },
|
|
4752
|
+
opencode: { ...base3.enabled.opencode, ...partial.enabled?.opencode ?? {} },
|
|
4753
|
+
codex: { ...base3.enabled.codex, ...partial.enabled?.codex ?? {} },
|
|
4754
|
+
agy: { ...base3.enabled.agy, ...partial.enabled?.agy ?? {} },
|
|
4755
|
+
cursor: { ...base3.enabled.cursor, ...partial.enabled?.cursor ?? {} },
|
|
4756
|
+
shared: { ...base3.enabled.shared, ...partial.enabled?.shared ?? {} },
|
|
4757
|
+
common: { ...base3.enabled.common, ...partial.enabled?.common ?? {} }
|
|
4758
4758
|
};
|
|
4759
4759
|
return {
|
|
4760
|
-
claudeHome: partial.claudeHome ??
|
|
4761
|
-
geminiHome: partial.geminiHome ??
|
|
4762
|
-
codexHome: partial.codexHome ??
|
|
4763
|
-
opencodeDbPath: partial.opencodeDbPath ??
|
|
4764
|
-
agyHome: partial.agyHome ??
|
|
4765
|
-
cursorHome: partial.cursorHome ??
|
|
4766
|
-
cursorIdeHome: partial.cursorIdeHome ??
|
|
4767
|
-
extraClaudeHomes: partial.extraClaudeHomes ??
|
|
4768
|
-
approvedHomes: partial.approvedHomes ??
|
|
4769
|
-
declinedHomes: partial.declinedHomes ??
|
|
4770
|
-
homesGrandfathered: partial.homesGrandfathered ??
|
|
4760
|
+
claudeHome: partial.claudeHome ?? base3.claudeHome,
|
|
4761
|
+
geminiHome: partial.geminiHome ?? base3.geminiHome,
|
|
4762
|
+
codexHome: partial.codexHome ?? base3.codexHome,
|
|
4763
|
+
opencodeDbPath: partial.opencodeDbPath ?? base3.opencodeDbPath,
|
|
4764
|
+
agyHome: partial.agyHome ?? base3.agyHome,
|
|
4765
|
+
cursorHome: partial.cursorHome ?? base3.cursorHome,
|
|
4766
|
+
cursorIdeHome: partial.cursorIdeHome ?? base3.cursorIdeHome,
|
|
4767
|
+
extraClaudeHomes: partial.extraClaudeHomes ?? base3.extraClaudeHomes,
|
|
4768
|
+
approvedHomes: partial.approvedHomes ?? base3.approvedHomes,
|
|
4769
|
+
declinedHomes: partial.declinedHomes ?? base3.declinedHomes,
|
|
4770
|
+
homesGrandfathered: partial.homesGrandfathered ?? base3.homesGrandfathered,
|
|
4771
4771
|
enabled
|
|
4772
4772
|
};
|
|
4773
4773
|
}
|
|
4774
|
-
function mergePrivacy(
|
|
4774
|
+
function mergePrivacy(base3, partial) {
|
|
4775
4775
|
if (!partial)
|
|
4776
|
-
return
|
|
4777
|
-
return { ...
|
|
4776
|
+
return base3;
|
|
4777
|
+
return { ...base3, ...partial };
|
|
4778
4778
|
}
|
|
4779
|
-
function mergeSync(
|
|
4779
|
+
function mergeSync(base3, partial) {
|
|
4780
4780
|
if (!partial)
|
|
4781
|
-
return
|
|
4781
|
+
return base3;
|
|
4782
4782
|
return {
|
|
4783
|
-
...
|
|
4783
|
+
...base3,
|
|
4784
4784
|
...partial,
|
|
4785
|
-
upload: { ...
|
|
4785
|
+
upload: { ...base3.upload, ...partial.upload ?? {} }
|
|
4786
4786
|
};
|
|
4787
4787
|
}
|
|
4788
|
-
function mergeTeam(
|
|
4788
|
+
function mergeTeam(base3, partial) {
|
|
4789
4789
|
if (!partial)
|
|
4790
|
-
return
|
|
4790
|
+
return base3;
|
|
4791
4791
|
return {
|
|
4792
|
-
...
|
|
4792
|
+
...base3,
|
|
4793
4793
|
...partial,
|
|
4794
|
-
publishAllowed: { ...
|
|
4795
|
-
vault: { ...
|
|
4794
|
+
publishAllowed: { ...base3.publishAllowed, ...partial.publishAllowed ?? {} },
|
|
4795
|
+
vault: { ...base3.vault, ...partial.vault ?? {} }
|
|
4796
4796
|
};
|
|
4797
4797
|
}
|
|
4798
4798
|
function settingsFilePath() {
|
|
@@ -4910,15 +4910,15 @@ function loadSettings() {
|
|
|
4910
4910
|
}
|
|
4911
4911
|
try {
|
|
4912
4912
|
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
4913
|
-
const
|
|
4913
|
+
const base3 = freshDefaults();
|
|
4914
4914
|
const result = {
|
|
4915
4915
|
v: SCHEMA_VERSION,
|
|
4916
|
-
embedding: { ...
|
|
4917
|
-
summary: { ...
|
|
4918
|
-
sources: mergeSources(
|
|
4919
|
-
privacy: mergePrivacy(
|
|
4920
|
-
sync: mergeSync(
|
|
4921
|
-
team: mergeTeam(
|
|
4916
|
+
embedding: { ...base3.embedding, ...parsed.embedding ?? {} },
|
|
4917
|
+
summary: { ...base3.summary, ...parsed.summary ?? {} },
|
|
4918
|
+
sources: mergeSources(base3.sources, parsed.sources),
|
|
4919
|
+
privacy: mergePrivacy(base3.privacy, parsed.privacy),
|
|
4920
|
+
sync: mergeSync(base3.sync, parsed.sync),
|
|
4921
|
+
team: mergeTeam(base3.team, parsed.team)
|
|
4922
4922
|
};
|
|
4923
4923
|
if (mtimeMs >= 0)
|
|
4924
4924
|
_settingsCache = { mtimeMs, size, value: structuredClone(result) };
|
|
@@ -5125,10 +5125,10 @@ function legacyAutoSyncedHomes() {
|
|
|
5125
5125
|
{ base: join3(home, ".local", "share", "opencode"), marker: "opencode.db" },
|
|
5126
5126
|
{ base: join3(home, ".cursor"), marker: "chats" }
|
|
5127
5127
|
];
|
|
5128
|
-
for (const { base:
|
|
5129
|
-
add(
|
|
5130
|
-
const parent = dirname3(
|
|
5131
|
-
const leaf =
|
|
5128
|
+
for (const { base: base3, marker } of bases) {
|
|
5129
|
+
add(base3, marker);
|
|
5130
|
+
const parent = dirname3(base3);
|
|
5131
|
+
const leaf = base3.slice(parent.length + 1);
|
|
5132
5132
|
try {
|
|
5133
5133
|
for (const e of readdirSync2(parent, { withFileTypes: true })) {
|
|
5134
5134
|
if (!e.isDirectory())
|
|
@@ -5326,17 +5326,17 @@ function cursorHomeDir() {
|
|
|
5326
5326
|
function cursorIdeHomeDir() {
|
|
5327
5327
|
return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join4(homedir3(), "Library", "Application Support", "Cursor") : join4(homedir3(), ".config", "Cursor"));
|
|
5328
5328
|
}
|
|
5329
|
-
function siblingHomes(
|
|
5329
|
+
function siblingHomes(base3, overridden, suffix) {
|
|
5330
5330
|
const roots = [];
|
|
5331
5331
|
const add = (home) => {
|
|
5332
5332
|
const root = suffix ? join4(home, suffix) : home;
|
|
5333
5333
|
if (existsSync4(root) && !roots.includes(root))
|
|
5334
5334
|
roots.push(root);
|
|
5335
5335
|
};
|
|
5336
|
-
add(
|
|
5336
|
+
add(base3);
|
|
5337
5337
|
if (!overridden) {
|
|
5338
|
-
const parent = dirname4(
|
|
5339
|
-
const leaf = basename(
|
|
5338
|
+
const parent = dirname4(base3);
|
|
5339
|
+
const leaf = basename(base3);
|
|
5340
5340
|
try {
|
|
5341
5341
|
for (const entry of readdirSync3(parent, { withFileTypes: true })) {
|
|
5342
5342
|
if (!entry.isDirectory())
|
|
@@ -5594,8 +5594,8 @@ function _clearServerRulePack() {
|
|
|
5594
5594
|
serverPack = null;
|
|
5595
5595
|
}
|
|
5596
5596
|
function activeRules() {
|
|
5597
|
-
const
|
|
5598
|
-
return serverPack && serverPack.rules.length > 0 ? [...
|
|
5597
|
+
const base3 = settingsView().rules;
|
|
5598
|
+
return serverPack && serverPack.rules.length > 0 ? [...base3, ...serverPack.rules] : base3;
|
|
5599
5599
|
}
|
|
5600
5600
|
function isRedactionEnabled() {
|
|
5601
5601
|
const env = isEnvRedactionRequested();
|
|
@@ -6063,6 +6063,64 @@ var init_chunker = __esm({
|
|
|
6063
6063
|
}
|
|
6064
6064
|
});
|
|
6065
6065
|
|
|
6066
|
+
// ../engine/dist/core/project-dir-name.js
|
|
6067
|
+
import { readdirSync as readdirSync4 } from "node:fs";
|
|
6068
|
+
function looksWindowsEncoded(dirName) {
|
|
6069
|
+
return /^[A-Za-z]--/.test(dirName);
|
|
6070
|
+
}
|
|
6071
|
+
function decodeProjectDirName(dirName) {
|
|
6072
|
+
if (!dirName)
|
|
6073
|
+
return "";
|
|
6074
|
+
if (looksWindowsEncoded(dirName)) {
|
|
6075
|
+
const drive = dirName[0].toUpperCase();
|
|
6076
|
+
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
6077
|
+
return `${drive}:\\${rest}`;
|
|
6078
|
+
}
|
|
6079
|
+
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
6080
|
+
}
|
|
6081
|
+
function resolveProjectDirName(dirName, deps = {}) {
|
|
6082
|
+
const structural = decodeProjectDirName(dirName);
|
|
6083
|
+
if (!dirName)
|
|
6084
|
+
return structural;
|
|
6085
|
+
if (looksWindowsEncoded(dirName))
|
|
6086
|
+
return structural;
|
|
6087
|
+
const readdir3 = deps.readdir ?? ((p) => readdirSync4(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name));
|
|
6088
|
+
const encodeName = (name) => name.replace(/[-_.]/g, "-");
|
|
6089
|
+
let remaining = dirName.replace(/^-/, "");
|
|
6090
|
+
let current = "/";
|
|
6091
|
+
while (remaining) {
|
|
6092
|
+
let children;
|
|
6093
|
+
try {
|
|
6094
|
+
children = readdir3(current);
|
|
6095
|
+
} catch {
|
|
6096
|
+
break;
|
|
6097
|
+
}
|
|
6098
|
+
let best = "";
|
|
6099
|
+
for (const child of children) {
|
|
6100
|
+
const encoded = encodeName(child);
|
|
6101
|
+
if (!encoded || encoded.length < best.length)
|
|
6102
|
+
continue;
|
|
6103
|
+
if (!remaining.startsWith(encoded))
|
|
6104
|
+
continue;
|
|
6105
|
+
const next = remaining[encoded.length];
|
|
6106
|
+
if (next !== void 0 && next !== "-")
|
|
6107
|
+
continue;
|
|
6108
|
+
if (encoded.length > best.length)
|
|
6109
|
+
best = child;
|
|
6110
|
+
}
|
|
6111
|
+
if (!best)
|
|
6112
|
+
break;
|
|
6113
|
+
current = current === "/" ? `/${best}` : `${current}/${best}`;
|
|
6114
|
+
remaining = remaining.slice(encodeName(best).length).replace(/^-/, "");
|
|
6115
|
+
}
|
|
6116
|
+
return remaining ? structural : current;
|
|
6117
|
+
}
|
|
6118
|
+
var init_project_dir_name = __esm({
|
|
6119
|
+
"../engine/dist/core/project-dir-name.js"() {
|
|
6120
|
+
"use strict";
|
|
6121
|
+
}
|
|
6122
|
+
});
|
|
6123
|
+
|
|
6066
6124
|
// ../engine/dist/core/model-pricing.js
|
|
6067
6125
|
function pricingFor(modelId) {
|
|
6068
6126
|
if (!modelId)
|
|
@@ -6234,7 +6292,7 @@ var init_model_pricing = __esm({
|
|
|
6234
6292
|
});
|
|
6235
6293
|
|
|
6236
6294
|
// ../engine/dist/parsers/session.js
|
|
6237
|
-
import { createReadStream, existsSync as existsSync5, readdirSync as
|
|
6295
|
+
import { createReadStream, existsSync as existsSync5, readdirSync as readdirSync5, readFileSync as readFileSync2, statSync as statSync4, openSync, readSync, closeSync } from "fs";
|
|
6238
6296
|
import { createInterface } from "readline";
|
|
6239
6297
|
import { join as join5, basename as basename2 } from "path";
|
|
6240
6298
|
function removeCodeBlocks(text) {
|
|
@@ -6305,7 +6363,7 @@ function* iterAllSessionIndices(claudeDir) {
|
|
|
6305
6363
|
if (!existsSync5(dir)) {
|
|
6306
6364
|
return;
|
|
6307
6365
|
}
|
|
6308
|
-
const entries =
|
|
6366
|
+
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
6309
6367
|
for (const entry of entries) {
|
|
6310
6368
|
if (!entry.isDirectory())
|
|
6311
6369
|
continue;
|
|
@@ -6327,7 +6385,7 @@ function getSubagentPaths(sessionPath) {
|
|
|
6327
6385
|
const subagentsDir = join5(sessionPath.slice(0, -6), "subagents");
|
|
6328
6386
|
if (!existsSync5(subagentsDir))
|
|
6329
6387
|
return [];
|
|
6330
|
-
return
|
|
6388
|
+
return readdirSync5(subagentsDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join5(subagentsDir, f));
|
|
6331
6389
|
}
|
|
6332
6390
|
function getSubagentProjectPath(sessionPath, folderDerivedPath) {
|
|
6333
6391
|
const subagentPaths = getSubagentPaths(sessionPath);
|
|
@@ -6644,40 +6702,6 @@ ${resultText}` : resultText;
|
|
|
6644
6702
|
});
|
|
6645
6703
|
return content;
|
|
6646
6704
|
}
|
|
6647
|
-
function decodeDirName(dirName) {
|
|
6648
|
-
const segments = dirName.replace(/^-/, "").split("-");
|
|
6649
|
-
let currentPath = "/";
|
|
6650
|
-
let i = 0;
|
|
6651
|
-
while (i < segments.length) {
|
|
6652
|
-
let matched = false;
|
|
6653
|
-
const singleCandidate = join5(currentPath, segments[i]);
|
|
6654
|
-
if (existsSync5(singleCandidate)) {
|
|
6655
|
-
currentPath = singleCandidate;
|
|
6656
|
-
i++;
|
|
6657
|
-
matched = true;
|
|
6658
|
-
continue;
|
|
6659
|
-
}
|
|
6660
|
-
for (let len = 2; len <= segments.length - i; len++) {
|
|
6661
|
-
const joinedSegments = segments.slice(i, i + len);
|
|
6662
|
-
for (const sep4 of ["-", "_", "."]) {
|
|
6663
|
-
const candidate = join5(currentPath, joinedSegments.join(sep4));
|
|
6664
|
-
if (existsSync5(candidate)) {
|
|
6665
|
-
currentPath = candidate;
|
|
6666
|
-
i += len;
|
|
6667
|
-
matched = true;
|
|
6668
|
-
break;
|
|
6669
|
-
}
|
|
6670
|
-
}
|
|
6671
|
-
if (matched)
|
|
6672
|
-
break;
|
|
6673
|
-
}
|
|
6674
|
-
if (!matched) {
|
|
6675
|
-
currentPath = join5(currentPath, segments[i]);
|
|
6676
|
-
i++;
|
|
6677
|
-
}
|
|
6678
|
-
}
|
|
6679
|
-
return currentPath;
|
|
6680
|
-
}
|
|
6681
6705
|
function* getAllSessions(claudeDir) {
|
|
6682
6706
|
const seenSessionIds = /* @__PURE__ */ new Set();
|
|
6683
6707
|
const projectDirs = claudeDir ? [claudeDir] : claudeProjectDirs();
|
|
@@ -6692,12 +6716,12 @@ function* getAllSessions(claudeDir) {
|
|
|
6692
6716
|
}
|
|
6693
6717
|
if (!existsSync5(dir))
|
|
6694
6718
|
continue;
|
|
6695
|
-
const dirEntries =
|
|
6719
|
+
const dirEntries = readdirSync5(dir, { withFileTypes: true });
|
|
6696
6720
|
for (const projDirEntry of dirEntries) {
|
|
6697
6721
|
if (!projDirEntry.isDirectory())
|
|
6698
6722
|
continue;
|
|
6699
6723
|
const projectPath = join5(dir, projDirEntry.name);
|
|
6700
|
-
const files =
|
|
6724
|
+
const files = readdirSync5(projectPath);
|
|
6701
6725
|
for (const file of files) {
|
|
6702
6726
|
if (!file.endsWith(".jsonl"))
|
|
6703
6727
|
continue;
|
|
@@ -6711,7 +6735,7 @@ function* getAllSessions(claudeDir) {
|
|
|
6711
6735
|
const fullPath = join5(projectPath, file);
|
|
6712
6736
|
try {
|
|
6713
6737
|
const stat3 = statSync4(fullPath);
|
|
6714
|
-
const derivedProjectPath =
|
|
6738
|
+
const derivedProjectPath = resolveProjectDirName(projDirEntry.name);
|
|
6715
6739
|
const effectiveMtime = getSessionMtime(fullPath);
|
|
6716
6740
|
let projectPath2 = "";
|
|
6717
6741
|
if (hasSubagentsDir(fullPath)) {
|
|
@@ -6750,6 +6774,7 @@ var init_session = __esm({
|
|
|
6750
6774
|
init_chunker();
|
|
6751
6775
|
init_claude2();
|
|
6752
6776
|
init_tool_paths();
|
|
6777
|
+
init_project_dir_name();
|
|
6753
6778
|
init_model_pricing();
|
|
6754
6779
|
}
|
|
6755
6780
|
});
|
|
@@ -7487,7 +7512,7 @@ async function archiveRawSession(store, sessionId) {
|
|
|
7487
7512
|
return await store.putRawSession(sessionId, exp.tool, Math.floor(exp.mtime), gz, size);
|
|
7488
7513
|
}
|
|
7489
7514
|
function detectForkPredecessor(sessionPath) {
|
|
7490
|
-
const { readFileSync: readFileSync50, readdirSync:
|
|
7515
|
+
const { readFileSync: readFileSync50, readdirSync: readdirSync37 } = requireFs();
|
|
7491
7516
|
const { dirname: dirname28, join: join61, basename: basename30 } = requirePath();
|
|
7492
7517
|
let text;
|
|
7493
7518
|
try {
|
|
@@ -7517,7 +7542,7 @@ function detectForkPredecessor(sessionPath) {
|
|
|
7517
7542
|
const self = basename30(sessionPath);
|
|
7518
7543
|
let entries;
|
|
7519
7544
|
try {
|
|
7520
|
-
entries =
|
|
7545
|
+
entries = readdirSync37(dir);
|
|
7521
7546
|
} catch {
|
|
7522
7547
|
return null;
|
|
7523
7548
|
}
|
|
@@ -8342,7 +8367,7 @@ var init_flat_string = __esm({
|
|
|
8342
8367
|
|
|
8343
8368
|
// ../engine/dist/core/backends/gemini.js
|
|
8344
8369
|
import { createHash as createHash3 } from "crypto";
|
|
8345
|
-
import { existsSync as existsSync7, readdirSync as
|
|
8370
|
+
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync3, statSync as statSync6 } from "fs";
|
|
8346
8371
|
import { basename as basename7, join as join8 } from "path";
|
|
8347
8372
|
function readSessionId(path, format) {
|
|
8348
8373
|
try {
|
|
@@ -8456,7 +8481,7 @@ var init_gemini2 = __esm({
|
|
|
8456
8481
|
const out = [];
|
|
8457
8482
|
const seen = /* @__PURE__ */ new Map();
|
|
8458
8483
|
for (const root of geminiTmpDirs()) {
|
|
8459
|
-
for (const projDir of
|
|
8484
|
+
for (const projDir of readdirSync6(root, { withFileTypes: true })) {
|
|
8460
8485
|
if (!projDir.isDirectory())
|
|
8461
8486
|
continue;
|
|
8462
8487
|
const projectPath = projMap.get(projDir.name) || "";
|
|
@@ -8467,7 +8492,7 @@ var init_gemini2 = __esm({
|
|
|
8467
8492
|
continue;
|
|
8468
8493
|
let files;
|
|
8469
8494
|
try {
|
|
8470
|
-
files =
|
|
8495
|
+
files = readdirSync6(chatsDir);
|
|
8471
8496
|
} catch {
|
|
8472
8497
|
continue;
|
|
8473
8498
|
}
|
|
@@ -8690,7 +8715,7 @@ var init_gemini2 = __esm({
|
|
|
8690
8715
|
return [];
|
|
8691
8716
|
const projMap = this.loadProjectMap();
|
|
8692
8717
|
const candidates2 = [];
|
|
8693
|
-
for (const proj of
|
|
8718
|
+
for (const proj of readdirSync6(tmpRoot, { withFileTypes: true })) {
|
|
8694
8719
|
if (!proj.isDirectory())
|
|
8695
8720
|
continue;
|
|
8696
8721
|
const projectPath = projMap.get(proj.name) || "";
|
|
@@ -8704,7 +8729,7 @@ var init_gemini2 = __esm({
|
|
|
8704
8729
|
continue;
|
|
8705
8730
|
let files;
|
|
8706
8731
|
try {
|
|
8707
|
-
files =
|
|
8732
|
+
files = readdirSync6(chats);
|
|
8708
8733
|
} catch {
|
|
8709
8734
|
continue;
|
|
8710
8735
|
}
|
|
@@ -9370,7 +9395,7 @@ var init_opencode = __esm({
|
|
|
9370
9395
|
});
|
|
9371
9396
|
|
|
9372
9397
|
// ../engine/dist/core/backends/codex.js
|
|
9373
|
-
import { readdirSync as
|
|
9398
|
+
import { readdirSync as readdirSync7, readFileSync as readFileSync4, statSync as statSync7, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
|
|
9374
9399
|
import { basename as basename8, dirname as dirname9, join as join10 } from "path";
|
|
9375
9400
|
function parseShellWrites(cmd) {
|
|
9376
9401
|
const out = [];
|
|
@@ -9466,7 +9491,7 @@ function parseCodexPatch(input) {
|
|
|
9466
9491
|
function* walkRollouts(root) {
|
|
9467
9492
|
let entries;
|
|
9468
9493
|
try {
|
|
9469
|
-
entries =
|
|
9494
|
+
entries = readdirSync7(root, { withFileTypes: true });
|
|
9470
9495
|
} catch {
|
|
9471
9496
|
return;
|
|
9472
9497
|
}
|
|
@@ -9758,7 +9783,7 @@ var init_codex2 = __esm({
|
|
|
9758
9783
|
const dayDir = located.path.substring(0, located.path.lastIndexOf("/"));
|
|
9759
9784
|
let entries = [];
|
|
9760
9785
|
try {
|
|
9761
|
-
entries =
|
|
9786
|
+
entries = readdirSync7(dayDir);
|
|
9762
9787
|
} catch {
|
|
9763
9788
|
}
|
|
9764
9789
|
for (const entry of entries) {
|
|
@@ -9944,7 +9969,7 @@ var init_codex2 = __esm({
|
|
|
9944
9969
|
const scanDir = (dir) => {
|
|
9945
9970
|
let entries;
|
|
9946
9971
|
try {
|
|
9947
|
-
entries =
|
|
9972
|
+
entries = readdirSync7(dir, { withFileTypes: true });
|
|
9948
9973
|
} catch {
|
|
9949
9974
|
return;
|
|
9950
9975
|
}
|
|
@@ -10037,7 +10062,7 @@ var init_codex2 = __esm({
|
|
|
10037
10062
|
if (parentId) {
|
|
10038
10063
|
const dayDir = dirname9(loc.path);
|
|
10039
10064
|
try {
|
|
10040
|
-
for (const f of
|
|
10065
|
+
for (const f of readdirSync7(dayDir)) {
|
|
10041
10066
|
if (!f.endsWith(".jsonl") || !f.startsWith("rollout-"))
|
|
10042
10067
|
continue;
|
|
10043
10068
|
const p = join10(dayDir, f);
|
|
@@ -10084,21 +10109,8 @@ var init_codex2 = __esm({
|
|
|
10084
10109
|
});
|
|
10085
10110
|
|
|
10086
10111
|
// ../engine/dist/core/backends/agy.js
|
|
10087
|
-
import { existsSync as existsSync9, readdirSync as
|
|
10112
|
+
import { existsSync as existsSync9, readdirSync as readdirSync8, readFileSync as readFileSync5, statSync as statSync8 } from "fs";
|
|
10088
10113
|
import { basename as basename9, dirname as dirname10, join as join11 } from "path";
|
|
10089
|
-
function getFallbackProjectPath(homeDir) {
|
|
10090
|
-
try {
|
|
10091
|
-
const settingsPath2 = join11(homeDir, "settings.json");
|
|
10092
|
-
if (existsSync9(settingsPath2)) {
|
|
10093
|
-
const json = JSON.parse(readFileSync5(settingsPath2, "utf-8"));
|
|
10094
|
-
if (Array.isArray(json?.trustedWorkspaces) && json.trustedWorkspaces[0]) {
|
|
10095
|
-
return json.trustedWorkspaces[0];
|
|
10096
|
-
}
|
|
10097
|
-
}
|
|
10098
|
-
} catch {
|
|
10099
|
-
}
|
|
10100
|
-
return "";
|
|
10101
|
-
}
|
|
10102
10114
|
function agyTranscriptPath(logsDir) {
|
|
10103
10115
|
const full = join11(logsDir, "transcript_full.jsonl");
|
|
10104
10116
|
if (existsSync9(full))
|
|
@@ -10111,8 +10123,8 @@ function agyTranscriptPath(logsDir) {
|
|
|
10111
10123
|
function resolveAgyProject(logsDir, homeDir) {
|
|
10112
10124
|
const deriveFrom = agyTranscriptPath(logsDir);
|
|
10113
10125
|
if (!deriveFrom)
|
|
10114
|
-
return
|
|
10115
|
-
return extractProjectPathFromTranscript(deriveFrom, homeDir)
|
|
10126
|
+
return "";
|
|
10127
|
+
return extractProjectPathFromTranscript(deriveFrom, homeDir);
|
|
10116
10128
|
}
|
|
10117
10129
|
function extractProjectPathFromTranscript(path, homeDir) {
|
|
10118
10130
|
let content;
|
|
@@ -10266,7 +10278,7 @@ var init_agy = __esm({
|
|
|
10266
10278
|
for (const brainDir of agyBrainDirs()) {
|
|
10267
10279
|
let sessionDirs;
|
|
10268
10280
|
try {
|
|
10269
|
-
sessionDirs =
|
|
10281
|
+
sessionDirs = readdirSync8(brainDir);
|
|
10270
10282
|
} catch {
|
|
10271
10283
|
continue;
|
|
10272
10284
|
}
|
|
@@ -10541,7 +10553,7 @@ var init_agy = __esm({
|
|
|
10541
10553
|
const candidates2 = [];
|
|
10542
10554
|
let sessionDirs;
|
|
10543
10555
|
try {
|
|
10544
|
-
sessionDirs =
|
|
10556
|
+
sessionDirs = readdirSync8(brainDir);
|
|
10545
10557
|
} catch {
|
|
10546
10558
|
return [];
|
|
10547
10559
|
}
|
|
@@ -10617,7 +10629,7 @@ var init_agy = __esm({
|
|
|
10617
10629
|
});
|
|
10618
10630
|
|
|
10619
10631
|
// ../engine/dist/core/backends/cursor-store.js
|
|
10620
|
-
import { existsSync as existsSync10, readdirSync as
|
|
10632
|
+
import { existsSync as existsSync10, readdirSync as readdirSync9, readFileSync as readFileSync6, statSync as statSync9 } from "fs";
|
|
10621
10633
|
import { join as join12 } from "path";
|
|
10622
10634
|
function cursorProjectSlug(absPath) {
|
|
10623
10635
|
return absPath.replace(/[^a-zA-Z0-9]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -10626,7 +10638,7 @@ function listChatsIn(chatsRoot) {
|
|
|
10626
10638
|
const out = [];
|
|
10627
10639
|
let hashDirs;
|
|
10628
10640
|
try {
|
|
10629
|
-
hashDirs =
|
|
10641
|
+
hashDirs = readdirSync9(chatsRoot);
|
|
10630
10642
|
} catch {
|
|
10631
10643
|
return out;
|
|
10632
10644
|
}
|
|
@@ -10636,7 +10648,7 @@ function listChatsIn(chatsRoot) {
|
|
|
10636
10648
|
try {
|
|
10637
10649
|
if (!statSync9(hashPath3).isDirectory())
|
|
10638
10650
|
continue;
|
|
10639
|
-
chatIds =
|
|
10651
|
+
chatIds = readdirSync9(hashPath3);
|
|
10640
10652
|
} catch {
|
|
10641
10653
|
continue;
|
|
10642
10654
|
}
|
|
@@ -10681,7 +10693,7 @@ function findChat(chatsRoots, chatId) {
|
|
|
10681
10693
|
for (const root of chatsRoots) {
|
|
10682
10694
|
let hashDirs;
|
|
10683
10695
|
try {
|
|
10684
|
-
hashDirs =
|
|
10696
|
+
hashDirs = readdirSync9(root);
|
|
10685
10697
|
} catch {
|
|
10686
10698
|
continue;
|
|
10687
10699
|
}
|
|
@@ -11002,7 +11014,7 @@ var init_cursor_store = __esm({
|
|
|
11002
11014
|
});
|
|
11003
11015
|
|
|
11004
11016
|
// ../engine/dist/core/backends/cursor-ide.js
|
|
11005
|
-
import { existsSync as existsSync11, readFileSync as readFileSync7, readdirSync as
|
|
11017
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, readdirSync as readdirSync10, statSync as statSync10 } from "fs";
|
|
11006
11018
|
import { dirname as dirname11, join as join13 } from "path";
|
|
11007
11019
|
function jsonOf(value) {
|
|
11008
11020
|
if (value == null)
|
|
@@ -11065,7 +11077,7 @@ function workspaceIndex(workspaceRoots) {
|
|
|
11065
11077
|
for (const root of workspaceRoots) {
|
|
11066
11078
|
let entries;
|
|
11067
11079
|
try {
|
|
11068
|
-
entries =
|
|
11080
|
+
entries = readdirSync10(root);
|
|
11069
11081
|
} catch {
|
|
11070
11082
|
continue;
|
|
11071
11083
|
}
|
|
@@ -11152,7 +11164,7 @@ function listComposers(globalDbPath, workspaceRoots) {
|
|
|
11152
11164
|
for (const root of workspaceRoots) {
|
|
11153
11165
|
let entries;
|
|
11154
11166
|
try {
|
|
11155
|
-
entries =
|
|
11167
|
+
entries = readdirSync10(root);
|
|
11156
11168
|
} catch {
|
|
11157
11169
|
continue;
|
|
11158
11170
|
}
|
|
@@ -12052,28 +12064,8 @@ var init_shadow = __esm({
|
|
|
12052
12064
|
}
|
|
12053
12065
|
});
|
|
12054
12066
|
|
|
12055
|
-
// ../engine/dist/core/project-dir-name.js
|
|
12056
|
-
function looksWindowsEncoded(dirName) {
|
|
12057
|
-
return /^[A-Za-z]--/.test(dirName);
|
|
12058
|
-
}
|
|
12059
|
-
function decodeProjectDirName(dirName) {
|
|
12060
|
-
if (!dirName)
|
|
12061
|
-
return "";
|
|
12062
|
-
if (looksWindowsEncoded(dirName)) {
|
|
12063
|
-
const drive = dirName[0].toUpperCase();
|
|
12064
|
-
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
12065
|
-
return `${drive}:\\${rest}`;
|
|
12066
|
-
}
|
|
12067
|
-
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
12068
|
-
}
|
|
12069
|
-
var init_project_dir_name = __esm({
|
|
12070
|
-
"../engine/dist/core/project-dir-name.js"() {
|
|
12071
|
-
"use strict";
|
|
12072
|
-
}
|
|
12073
|
-
});
|
|
12074
|
-
|
|
12075
12067
|
// ../engine/dist/core/live-session-scan.js
|
|
12076
|
-
import { existsSync as existsSync14, readdirSync as
|
|
12068
|
+
import { existsSync as existsSync14, readdirSync as readdirSync11, readFileSync as readFileSync10, statSync as statSync13, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
|
|
12077
12069
|
import { join as join16, basename as basename10 } from "path";
|
|
12078
12070
|
import { createHash as createHash5 } from "crypto";
|
|
12079
12071
|
function lazyGeminiProjectsJson() {
|
|
@@ -12110,7 +12102,7 @@ function sessionFileIndex() {
|
|
|
12110
12102
|
seenRoots.add(root);
|
|
12111
12103
|
let entries;
|
|
12112
12104
|
try {
|
|
12113
|
-
entries =
|
|
12105
|
+
entries = readdirSync11(root, { withFileTypes: true });
|
|
12114
12106
|
} catch {
|
|
12115
12107
|
continue;
|
|
12116
12108
|
}
|
|
@@ -12120,7 +12112,7 @@ function sessionFileIndex() {
|
|
|
12120
12112
|
const dir = join16(root, entry.name);
|
|
12121
12113
|
let names;
|
|
12122
12114
|
try {
|
|
12123
|
-
names =
|
|
12115
|
+
names = readdirSync11(dir);
|
|
12124
12116
|
} catch {
|
|
12125
12117
|
continue;
|
|
12126
12118
|
}
|
|
@@ -12131,7 +12123,7 @@ function sessionFileIndex() {
|
|
|
12131
12123
|
const located = {
|
|
12132
12124
|
path: join16(dir, name),
|
|
12133
12125
|
projectDir: entry.name,
|
|
12134
|
-
projectPath:
|
|
12126
|
+
projectPath: resolveProjectDirName(entry.name)
|
|
12135
12127
|
};
|
|
12136
12128
|
const prior = byId.get(id);
|
|
12137
12129
|
if (prior)
|
|
@@ -12218,7 +12210,7 @@ function resolveSessionContentPaths(sessionFile) {
|
|
|
12218
12210
|
const subDir = join16(sessionFile.slice(0, -6), "subagents");
|
|
12219
12211
|
if (!existsSync14(subDir))
|
|
12220
12212
|
return [sessionFile];
|
|
12221
|
-
const subPaths =
|
|
12213
|
+
const subPaths = readdirSync11(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join16(subDir, f));
|
|
12222
12214
|
return [sessionFile, ...subPaths];
|
|
12223
12215
|
}
|
|
12224
12216
|
function loadGeminiProjectMap() {
|
|
@@ -12266,7 +12258,7 @@ function geminiIndex() {
|
|
|
12266
12258
|
continue;
|
|
12267
12259
|
let projs;
|
|
12268
12260
|
try {
|
|
12269
|
-
projs =
|
|
12261
|
+
projs = readdirSync11(tmpRoot, { withFileTypes: true });
|
|
12270
12262
|
} catch {
|
|
12271
12263
|
continue;
|
|
12272
12264
|
}
|
|
@@ -12278,14 +12270,14 @@ function geminiIndex() {
|
|
|
12278
12270
|
continue;
|
|
12279
12271
|
let files;
|
|
12280
12272
|
try {
|
|
12281
|
-
files =
|
|
12273
|
+
files = readdirSync11(chats);
|
|
12282
12274
|
} catch {
|
|
12283
12275
|
continue;
|
|
12284
12276
|
}
|
|
12285
12277
|
for (const f of files) {
|
|
12286
12278
|
if (!isGeminiChat(f))
|
|
12287
12279
|
continue;
|
|
12288
|
-
const
|
|
12280
|
+
const base3 = f.replace(/\.jsonl?$/, "");
|
|
12289
12281
|
const located = {
|
|
12290
12282
|
path: join16(chats, f),
|
|
12291
12283
|
projectDir: proj.name,
|
|
@@ -12293,9 +12285,9 @@ function geminiIndex() {
|
|
|
12293
12285
|
format: f.endsWith(".jsonl") ? "jsonl" : "json"
|
|
12294
12286
|
};
|
|
12295
12287
|
all.push(located);
|
|
12296
|
-
if (!byBase.has(
|
|
12297
|
-
byBase.set(
|
|
12298
|
-
const tail =
|
|
12288
|
+
if (!byBase.has(base3))
|
|
12289
|
+
byBase.set(base3, located);
|
|
12290
|
+
const tail = base3.split("-").pop() || "";
|
|
12299
12291
|
if (tail.length >= 4 && !byTail.has(tail))
|
|
12300
12292
|
byTail.set(tail, located);
|
|
12301
12293
|
}
|
|
@@ -12397,21 +12389,21 @@ function findCodexSessionFile(sessionId) {
|
|
|
12397
12389
|
function findCodexSessionFileIn(root, sessionId) {
|
|
12398
12390
|
if (!existsSync14(root))
|
|
12399
12391
|
return null;
|
|
12400
|
-
for (const year of
|
|
12392
|
+
for (const year of readdirSync11(root, { withFileTypes: true })) {
|
|
12401
12393
|
if (!year.isDirectory())
|
|
12402
12394
|
continue;
|
|
12403
12395
|
const yearPath = join16(root, year.name);
|
|
12404
|
-
for (const month of
|
|
12396
|
+
for (const month of readdirSync11(yearPath, { withFileTypes: true })) {
|
|
12405
12397
|
if (!month.isDirectory())
|
|
12406
12398
|
continue;
|
|
12407
12399
|
const monthPath = join16(yearPath, month.name);
|
|
12408
|
-
for (const day of
|
|
12400
|
+
for (const day of readdirSync11(monthPath, { withFileTypes: true })) {
|
|
12409
12401
|
if (!day.isDirectory())
|
|
12410
12402
|
continue;
|
|
12411
12403
|
const dayPath = join16(monthPath, day.name);
|
|
12412
12404
|
let files;
|
|
12413
12405
|
try {
|
|
12414
|
-
files =
|
|
12406
|
+
files = readdirSync11(dayPath);
|
|
12415
12407
|
} catch {
|
|
12416
12408
|
continue;
|
|
12417
12409
|
}
|
|
@@ -12426,7 +12418,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
12426
12418
|
}
|
|
12427
12419
|
}
|
|
12428
12420
|
function scanDir(dir) {
|
|
12429
|
-
for (const entry of
|
|
12421
|
+
for (const entry of readdirSync11(dir, { withFileTypes: true })) {
|
|
12430
12422
|
if (entry.isDirectory()) {
|
|
12431
12423
|
const found = scanDir(join16(dir, entry.name));
|
|
12432
12424
|
if (found)
|
|
@@ -12581,7 +12573,7 @@ var init_first_prompt = __esm({
|
|
|
12581
12573
|
});
|
|
12582
12574
|
|
|
12583
12575
|
// ../engine/dist/core/backends/claude.js
|
|
12584
|
-
import { existsSync as existsSync16, readdirSync as
|
|
12576
|
+
import { existsSync as existsSync16, readdirSync as readdirSync12, readFileSync as readFileSync11, statSync as statSync14, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
12585
12577
|
import { join as join17, basename as basename11 } from "path";
|
|
12586
12578
|
function stripReminders(text) {
|
|
12587
12579
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -12736,13 +12728,13 @@ var init_claude2 = __esm({
|
|
|
12736
12728
|
collectSessionsFromRoot(root, cutoff, filter, seen, out) {
|
|
12737
12729
|
if (!existsSync16(root))
|
|
12738
12730
|
return;
|
|
12739
|
-
for (const proj of
|
|
12731
|
+
for (const proj of readdirSync12(root, { withFileTypes: true })) {
|
|
12740
12732
|
if (!proj.isDirectory())
|
|
12741
12733
|
continue;
|
|
12742
12734
|
if (filter && !proj.name.toLowerCase().includes(filter))
|
|
12743
12735
|
continue;
|
|
12744
12736
|
const projPath = join17(root, proj.name);
|
|
12745
|
-
const projectPath =
|
|
12737
|
+
const projectPath = resolveProjectDirName(proj.name);
|
|
12746
12738
|
const indexPath = join17(projPath, "sessions-index.json");
|
|
12747
12739
|
if (existsSync16(indexPath)) {
|
|
12748
12740
|
try {
|
|
@@ -12773,7 +12765,7 @@ var init_claude2 = __esm({
|
|
|
12773
12765
|
}
|
|
12774
12766
|
let files;
|
|
12775
12767
|
try {
|
|
12776
|
-
files =
|
|
12768
|
+
files = readdirSync12(projPath);
|
|
12777
12769
|
} catch {
|
|
12778
12770
|
continue;
|
|
12779
12771
|
}
|
|
@@ -13042,7 +13034,7 @@ var init_claude2 = __esm({
|
|
|
13042
13034
|
for (const root of claudeProjectDirs()) {
|
|
13043
13035
|
if (!existsSync16(root))
|
|
13044
13036
|
continue;
|
|
13045
|
-
for (const projEntry of
|
|
13037
|
+
for (const projEntry of readdirSync12(root, { withFileTypes: true })) {
|
|
13046
13038
|
if (!projEntry.isDirectory())
|
|
13047
13039
|
continue;
|
|
13048
13040
|
if (opts.projectFilter && !projEntry.name.toLowerCase().includes(opts.projectFilter.toLowerCase()))
|
|
@@ -13050,7 +13042,7 @@ var init_claude2 = __esm({
|
|
|
13050
13042
|
const projPath = join17(root, projEntry.name);
|
|
13051
13043
|
let files;
|
|
13052
13044
|
try {
|
|
13053
|
-
files =
|
|
13045
|
+
files = readdirSync12(projPath);
|
|
13054
13046
|
} catch {
|
|
13055
13047
|
continue;
|
|
13056
13048
|
}
|
|
@@ -13063,7 +13055,7 @@ var init_claude2 = __esm({
|
|
|
13063
13055
|
let mtime = st.mtimeMs;
|
|
13064
13056
|
const subDir = join17(projPath, f.slice(0, -6), "subagents");
|
|
13065
13057
|
if (existsSync16(subDir)) {
|
|
13066
|
-
for (const sub of
|
|
13058
|
+
for (const sub of readdirSync12(subDir)) {
|
|
13067
13059
|
try {
|
|
13068
13060
|
const subSt = statSync14(join17(subDir, sub));
|
|
13069
13061
|
if (subSt.mtimeMs > mtime)
|
|
@@ -13180,7 +13172,7 @@ __export(project_resolver_exports, {
|
|
|
13180
13172
|
});
|
|
13181
13173
|
import { execSync } from "child_process";
|
|
13182
13174
|
import { createHash as createHash6 } from "crypto";
|
|
13183
|
-
import { existsSync as existsSync17, readFileSync as readFileSync12, realpathSync as realpathSync2, readdirSync as
|
|
13175
|
+
import { existsSync as existsSync17, readFileSync as readFileSync12, realpathSync as realpathSync2, readdirSync as readdirSync13, statSync as statSync15 } from "fs";
|
|
13184
13176
|
import { basename as basename12, dirname as dirname13, isAbsolute, join as join18, resolve, sep } from "path";
|
|
13185
13177
|
function getProjectsConfigPath() {
|
|
13186
13178
|
return join18(getDataDir(), "projects.json");
|
|
@@ -13453,7 +13445,7 @@ function countGitChildren(dir) {
|
|
|
13453
13445
|
let count = 0;
|
|
13454
13446
|
let entries;
|
|
13455
13447
|
try {
|
|
13456
|
-
entries =
|
|
13448
|
+
entries = readdirSync13(dir);
|
|
13457
13449
|
} catch {
|
|
13458
13450
|
return 0;
|
|
13459
13451
|
}
|
|
@@ -13568,7 +13560,7 @@ var init_credentials_env = __esm({
|
|
|
13568
13560
|
|
|
13569
13561
|
// ../engine/dist/core/source-discovery.js
|
|
13570
13562
|
import { createHash as createHash7 } from "crypto";
|
|
13571
|
-
import { existsSync as existsSync18, readdirSync as
|
|
13563
|
+
import { existsSync as existsSync18, readdirSync as readdirSync14, statSync as statSync16 } from "fs";
|
|
13572
13564
|
import { join as join19 } from "path";
|
|
13573
13565
|
function sourceId(path) {
|
|
13574
13566
|
return "src_" + createHash7("sha256").update(path).digest("hex").slice(0, 12);
|
|
@@ -13605,7 +13597,7 @@ function countTranscripts(root, tool) {
|
|
|
13605
13597
|
return;
|
|
13606
13598
|
let entries;
|
|
13607
13599
|
try {
|
|
13608
|
-
entries =
|
|
13600
|
+
entries = readdirSync14(dir, { withFileTypes: true });
|
|
13609
13601
|
} catch {
|
|
13610
13602
|
return;
|
|
13611
13603
|
}
|
|
@@ -13684,7 +13676,7 @@ __export(home_discovery_exports, {
|
|
|
13684
13676
|
sessionIdsInHome: () => sessionIdsInHome
|
|
13685
13677
|
});
|
|
13686
13678
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
13687
|
-
import { existsSync as existsSync19, readdirSync as
|
|
13679
|
+
import { existsSync as existsSync19, readdirSync as readdirSync15, readFileSync as readFileSync13, realpathSync as realpathSync3, statSync as statSync17 } from "fs";
|
|
13688
13680
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
13689
13681
|
import { join as join20 } from "path";
|
|
13690
13682
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -13728,7 +13720,7 @@ function dirHasTranscript(root, match, depth) {
|
|
|
13728
13720
|
return false;
|
|
13729
13721
|
let entries;
|
|
13730
13722
|
try {
|
|
13731
|
-
entries =
|
|
13723
|
+
entries = readdirSync15(root, { withFileTypes: true });
|
|
13732
13724
|
} catch {
|
|
13733
13725
|
return false;
|
|
13734
13726
|
}
|
|
@@ -13760,7 +13752,7 @@ function countSessions(dir, tool) {
|
|
|
13760
13752
|
return;
|
|
13761
13753
|
let entries;
|
|
13762
13754
|
try {
|
|
13763
|
-
entries =
|
|
13755
|
+
entries = readdirSync15(d, { withFileTypes: true });
|
|
13764
13756
|
} catch {
|
|
13765
13757
|
return;
|
|
13766
13758
|
}
|
|
@@ -13812,7 +13804,7 @@ function sessionIdsInHome(dir, tool) {
|
|
|
13812
13804
|
return [];
|
|
13813
13805
|
if (tool === "agy") {
|
|
13814
13806
|
try {
|
|
13815
|
-
for (const e of
|
|
13807
|
+
for (const e of readdirSync15(join20(dir, "brain"), { withFileTypes: true })) {
|
|
13816
13808
|
if (e.isDirectory())
|
|
13817
13809
|
out.add(`agy_${e.name}`);
|
|
13818
13810
|
}
|
|
@@ -13822,11 +13814,11 @@ function sessionIdsInHome(dir, tool) {
|
|
|
13822
13814
|
}
|
|
13823
13815
|
if (tool === "cursor") {
|
|
13824
13816
|
try {
|
|
13825
|
-
for (const hash of
|
|
13817
|
+
for (const hash of readdirSync15(join20(dir, "chats"), { withFileTypes: true })) {
|
|
13826
13818
|
if (!hash.isDirectory())
|
|
13827
13819
|
continue;
|
|
13828
13820
|
try {
|
|
13829
|
-
for (const chat of
|
|
13821
|
+
for (const chat of readdirSync15(join20(dir, "chats", hash.name), { withFileTypes: true })) {
|
|
13830
13822
|
if (chat.isDirectory())
|
|
13831
13823
|
out.add(`cursor_${chat.name}`);
|
|
13832
13824
|
}
|
|
@@ -13842,7 +13834,7 @@ function sessionIdsInHome(dir, tool) {
|
|
|
13842
13834
|
return;
|
|
13843
13835
|
let entries;
|
|
13844
13836
|
try {
|
|
13845
|
-
entries =
|
|
13837
|
+
entries = readdirSync15(d, { withFileTypes: true });
|
|
13846
13838
|
} catch {
|
|
13847
13839
|
return;
|
|
13848
13840
|
}
|
|
@@ -13914,7 +13906,7 @@ function runningToolHomes(plat = osPlatform()) {
|
|
|
13914
13906
|
if (plat === "linux") {
|
|
13915
13907
|
let pids;
|
|
13916
13908
|
try {
|
|
13917
|
-
pids =
|
|
13909
|
+
pids = readdirSync15("/proc").filter((p) => /^\d+$/.test(p));
|
|
13918
13910
|
} catch {
|
|
13919
13911
|
return out;
|
|
13920
13912
|
}
|
|
@@ -13994,7 +13986,7 @@ function walkForHomes(dir, depth, visit) {
|
|
|
13994
13986
|
return;
|
|
13995
13987
|
let entries;
|
|
13996
13988
|
try {
|
|
13997
|
-
entries =
|
|
13989
|
+
entries = readdirSync15(dir, { withFileTypes: true });
|
|
13998
13990
|
} catch {
|
|
13999
13991
|
return;
|
|
14000
13992
|
}
|
|
@@ -15670,7 +15662,7 @@ var init_session_source = __esm({
|
|
|
15670
15662
|
});
|
|
15671
15663
|
|
|
15672
15664
|
// ../engine/dist/core/utils.js
|
|
15673
|
-
import { existsSync as existsSync22, readdirSync as
|
|
15665
|
+
import { existsSync as existsSync22, readdirSync as readdirSync16 } from "fs";
|
|
15674
15666
|
import { homedir as homedir6 } from "os";
|
|
15675
15667
|
import { join as join23 } from "path";
|
|
15676
15668
|
function splitByHeaders(markdown) {
|
|
@@ -15721,7 +15713,7 @@ function getClaudeDirs() {
|
|
|
15721
15713
|
}
|
|
15722
15714
|
add(join23(home, ".claude"));
|
|
15723
15715
|
try {
|
|
15724
|
-
const entries =
|
|
15716
|
+
const entries = readdirSync16(home, { withFileTypes: true });
|
|
15725
15717
|
for (const entry of entries) {
|
|
15726
15718
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
15727
15719
|
const candidate = join23(home, entry.name);
|
|
@@ -15751,7 +15743,7 @@ var init_utils = __esm({
|
|
|
15751
15743
|
});
|
|
15752
15744
|
|
|
15753
15745
|
// ../engine/dist/parsers/plan-source.js
|
|
15754
|
-
import { existsSync as existsSync23, readdirSync as
|
|
15746
|
+
import { existsSync as existsSync23, readdirSync as readdirSync17, readFileSync as readFileSync16, statSync as statSync21 } from "fs";
|
|
15755
15747
|
import { homedir as homedir7 } from "os";
|
|
15756
15748
|
import { join as join24, basename as basename13 } from "path";
|
|
15757
15749
|
import { createHash as createHash9 } from "crypto";
|
|
@@ -15778,7 +15770,7 @@ function parseFrontmatter(content) {
|
|
|
15778
15770
|
}
|
|
15779
15771
|
function safeReaddir(dir) {
|
|
15780
15772
|
try {
|
|
15781
|
-
return
|
|
15773
|
+
return readdirSync17(dir);
|
|
15782
15774
|
} catch {
|
|
15783
15775
|
return [];
|
|
15784
15776
|
}
|
|
@@ -15814,11 +15806,11 @@ var init_plan_source = __esm({
|
|
|
15814
15806
|
if (!existsSync23(projectsDir))
|
|
15815
15807
|
return this._knownProjectDirs;
|
|
15816
15808
|
try {
|
|
15817
|
-
const entries =
|
|
15809
|
+
const entries = readdirSync17(projectsDir, { withFileTypes: true });
|
|
15818
15810
|
for (const entry of entries) {
|
|
15819
15811
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
15820
15812
|
continue;
|
|
15821
|
-
const projectPath =
|
|
15813
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
15822
15814
|
if (existsSync23(projectPath)) {
|
|
15823
15815
|
this._knownProjectDirs.push(projectPath);
|
|
15824
15816
|
}
|
|
@@ -15846,7 +15838,7 @@ var init_plan_source = __esm({
|
|
|
15846
15838
|
for (const plansDir of this.plansDirs) {
|
|
15847
15839
|
if (!existsSync23(plansDir))
|
|
15848
15840
|
continue;
|
|
15849
|
-
const files =
|
|
15841
|
+
const files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
|
|
15850
15842
|
for (const file of files) {
|
|
15851
15843
|
if (seenClaude.has(file))
|
|
15852
15844
|
continue;
|
|
@@ -15890,7 +15882,7 @@ var init_plan_source = __esm({
|
|
|
15890
15882
|
return;
|
|
15891
15883
|
let files;
|
|
15892
15884
|
try {
|
|
15893
|
-
files =
|
|
15885
|
+
files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
|
|
15894
15886
|
} catch {
|
|
15895
15887
|
return;
|
|
15896
15888
|
}
|
|
@@ -15937,7 +15929,7 @@ var init_plan_source = __esm({
|
|
|
15937
15929
|
}
|
|
15938
15930
|
let projDirs;
|
|
15939
15931
|
try {
|
|
15940
|
-
projDirs =
|
|
15932
|
+
projDirs = readdirSync17(tmpRoot);
|
|
15941
15933
|
} catch {
|
|
15942
15934
|
return;
|
|
15943
15935
|
}
|
|
@@ -15946,7 +15938,7 @@ var init_plan_source = __esm({
|
|
|
15946
15938
|
const projRoot = join24(tmpRoot, projDir);
|
|
15947
15939
|
let sessions;
|
|
15948
15940
|
try {
|
|
15949
|
-
sessions =
|
|
15941
|
+
sessions = readdirSync17(projRoot);
|
|
15950
15942
|
} catch {
|
|
15951
15943
|
continue;
|
|
15952
15944
|
}
|
|
@@ -15956,7 +15948,7 @@ var init_plan_source = __esm({
|
|
|
15956
15948
|
continue;
|
|
15957
15949
|
let files;
|
|
15958
15950
|
try {
|
|
15959
|
-
files =
|
|
15951
|
+
files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
|
|
15960
15952
|
} catch {
|
|
15961
15953
|
continue;
|
|
15962
15954
|
}
|
|
@@ -16165,7 +16157,7 @@ var init_plan_source = __esm({
|
|
|
16165
16157
|
return;
|
|
16166
16158
|
let sessionDirs;
|
|
16167
16159
|
try {
|
|
16168
|
-
sessionDirs =
|
|
16160
|
+
sessionDirs = readdirSync17(brainDir);
|
|
16169
16161
|
} catch {
|
|
16170
16162
|
return;
|
|
16171
16163
|
}
|
|
@@ -16179,7 +16171,7 @@ var init_plan_source = __esm({
|
|
|
16179
16171
|
}
|
|
16180
16172
|
let files;
|
|
16181
16173
|
try {
|
|
16182
|
-
files =
|
|
16174
|
+
files = readdirSync17(sessionPath).filter((f) => f.endsWith(".md"));
|
|
16183
16175
|
} catch {
|
|
16184
16176
|
continue;
|
|
16185
16177
|
}
|
|
@@ -16216,7 +16208,7 @@ var init_plan_source = __esm({
|
|
|
16216
16208
|
});
|
|
16217
16209
|
|
|
16218
16210
|
// ../engine/dist/parsers/task-source.js
|
|
16219
|
-
import { existsSync as existsSync24, readdirSync as
|
|
16211
|
+
import { existsSync as existsSync24, readdirSync as readdirSync18, readFileSync as readFileSync17, statSync as statSync22 } from "fs";
|
|
16220
16212
|
import { join as join25 } from "path";
|
|
16221
16213
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
16222
16214
|
var init_task_source = __esm({
|
|
@@ -16250,7 +16242,7 @@ var init_task_source = __esm({
|
|
|
16250
16242
|
return;
|
|
16251
16243
|
let files;
|
|
16252
16244
|
try {
|
|
16253
|
-
files =
|
|
16245
|
+
files = readdirSync18(todosDir).filter((f) => f.endsWith(".json"));
|
|
16254
16246
|
} catch {
|
|
16255
16247
|
return;
|
|
16256
16248
|
}
|
|
@@ -16299,7 +16291,7 @@ var init_task_source = __esm({
|
|
|
16299
16291
|
async *discoverInDir(tasksDir) {
|
|
16300
16292
|
if (!existsSync24(tasksDir))
|
|
16301
16293
|
return;
|
|
16302
|
-
const entries =
|
|
16294
|
+
const entries = readdirSync18(tasksDir, { withFileTypes: true });
|
|
16303
16295
|
for (const entry of entries) {
|
|
16304
16296
|
if (!entry.isDirectory())
|
|
16305
16297
|
continue;
|
|
@@ -16307,7 +16299,7 @@ var init_task_source = __esm({
|
|
|
16307
16299
|
const taskDir = join25(tasksDir, sessionUuid);
|
|
16308
16300
|
try {
|
|
16309
16301
|
const stat3 = statSync22(taskDir);
|
|
16310
|
-
const taskFiles =
|
|
16302
|
+
const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
|
|
16311
16303
|
if (taskFiles.length === 0)
|
|
16312
16304
|
continue;
|
|
16313
16305
|
const tasks2 = this.readTasks(taskDir, taskFiles);
|
|
@@ -16341,7 +16333,7 @@ var init_task_source = __esm({
|
|
|
16341
16333
|
const taskDir = item.filePath;
|
|
16342
16334
|
if (!existsSync24(taskDir))
|
|
16343
16335
|
return [];
|
|
16344
|
-
const taskFiles =
|
|
16336
|
+
const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
|
|
16345
16337
|
const tasks2 = this.readTasks(taskDir, taskFiles);
|
|
16346
16338
|
if (tasks2.length === 0)
|
|
16347
16339
|
return [];
|
|
@@ -16452,7 +16444,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
16452
16444
|
});
|
|
16453
16445
|
|
|
16454
16446
|
// ../engine/dist/parsers/claude-md-source.js
|
|
16455
|
-
import { existsSync as existsSync25, readFileSync as readFileSync18, readdirSync as
|
|
16447
|
+
import { existsSync as existsSync25, readFileSync as readFileSync18, readdirSync as readdirSync19, statSync as statSync23 } from "fs";
|
|
16456
16448
|
import { homedir as homedir8 } from "os";
|
|
16457
16449
|
import { join as join26, basename as basename14, dirname as dirname14 } from "path";
|
|
16458
16450
|
import { createHash as createHash10 } from "crypto";
|
|
@@ -16469,11 +16461,11 @@ function discoverProjectDirs(claudeDir) {
|
|
|
16469
16461
|
if (!existsSync25(projectsDir))
|
|
16470
16462
|
return;
|
|
16471
16463
|
try {
|
|
16472
|
-
const entries =
|
|
16464
|
+
const entries = readdirSync19(projectsDir, { withFileTypes: true });
|
|
16473
16465
|
for (const entry of entries) {
|
|
16474
16466
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16475
16467
|
continue;
|
|
16476
|
-
const projectPath =
|
|
16468
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
16477
16469
|
addProject(projectPath);
|
|
16478
16470
|
}
|
|
16479
16471
|
} catch {
|
|
@@ -16486,7 +16478,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
16486
16478
|
const home = homedir8();
|
|
16487
16479
|
scanProjectsDir(claudeBackend.projectsDir());
|
|
16488
16480
|
try {
|
|
16489
|
-
for (const entry of
|
|
16481
|
+
for (const entry of readdirSync19(home, { withFileTypes: true })) {
|
|
16490
16482
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
16491
16483
|
scanProjectsDir(join26(home, entry.name, "projects"));
|
|
16492
16484
|
}
|
|
@@ -16588,7 +16580,7 @@ var init_claude_md_source = __esm({
|
|
|
16588
16580
|
}
|
|
16589
16581
|
}
|
|
16590
16582
|
try {
|
|
16591
|
-
const entries =
|
|
16583
|
+
const entries = readdirSync19(searchDir, { withFileTypes: true });
|
|
16592
16584
|
for (const entry of entries) {
|
|
16593
16585
|
if (!entry.isDirectory())
|
|
16594
16586
|
continue;
|
|
@@ -16678,7 +16670,7 @@ var init_claude_md_source = __esm({
|
|
|
16678
16670
|
});
|
|
16679
16671
|
|
|
16680
16672
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
16681
|
-
import { existsSync as existsSync26, readFileSync as readFileSync19, readdirSync as
|
|
16673
|
+
import { existsSync as existsSync26, readFileSync as readFileSync19, readdirSync as readdirSync20, statSync as statSync24 } from "fs";
|
|
16682
16674
|
import { homedir as homedir9 } from "os";
|
|
16683
16675
|
import { join as join27, basename as basename15 } from "path";
|
|
16684
16676
|
function parseFrontmatter2(content) {
|
|
@@ -16706,7 +16698,7 @@ function parseFrontmatter2(content) {
|
|
|
16706
16698
|
return { fm, body };
|
|
16707
16699
|
}
|
|
16708
16700
|
function projectHashToPath(hashDir) {
|
|
16709
|
-
return
|
|
16701
|
+
return resolveProjectDirName(hashDir);
|
|
16710
16702
|
}
|
|
16711
16703
|
function discoverMemoryDirs() {
|
|
16712
16704
|
const out = [];
|
|
@@ -16720,7 +16712,7 @@ function discoverMemoryDirs() {
|
|
|
16720
16712
|
const home = homedir9();
|
|
16721
16713
|
const claudeRoots = [claudeBackend.projectsDir()];
|
|
16722
16714
|
try {
|
|
16723
|
-
for (const entry of
|
|
16715
|
+
for (const entry of readdirSync20(home, { withFileTypes: true })) {
|
|
16724
16716
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
16725
16717
|
claudeRoots.push(join27(home, entry.name, "projects"));
|
|
16726
16718
|
}
|
|
@@ -16731,7 +16723,7 @@ function discoverMemoryDirs() {
|
|
|
16731
16723
|
if (!existsSync26(projectsDir))
|
|
16732
16724
|
continue;
|
|
16733
16725
|
try {
|
|
16734
|
-
for (const entry of
|
|
16726
|
+
for (const entry of readdirSync20(projectsDir, { withFileTypes: true })) {
|
|
16735
16727
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16736
16728
|
continue;
|
|
16737
16729
|
add(join27(projectsDir, entry.name, "memory"), entry.name);
|
|
@@ -16760,7 +16752,7 @@ var init_agent_memory_source = __esm({
|
|
|
16760
16752
|
for (const { memoryDir, projectHash } of discoverMemoryDirs()) {
|
|
16761
16753
|
const projectPath = projectHashToPath(projectHash);
|
|
16762
16754
|
try {
|
|
16763
|
-
for (const entry of
|
|
16755
|
+
for (const entry of readdirSync20(memoryDir, { withFileTypes: true })) {
|
|
16764
16756
|
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
16765
16757
|
continue;
|
|
16766
16758
|
const filePath = join27(memoryDir, entry.name);
|
|
@@ -16863,7 +16855,7 @@ var init_agent_memory_source = __esm({
|
|
|
16863
16855
|
});
|
|
16864
16856
|
|
|
16865
16857
|
// ../engine/dist/parsers/history-source.js
|
|
16866
|
-
import { existsSync as existsSync27, readdirSync as
|
|
16858
|
+
import { existsSync as existsSync27, readdirSync as readdirSync21, statSync as statSync25 } from "fs";
|
|
16867
16859
|
import { createReadStream as createReadStream3 } from "fs";
|
|
16868
16860
|
import { createInterface as createInterface2 } from "readline";
|
|
16869
16861
|
import { homedir as homedir10 } from "os";
|
|
@@ -16890,7 +16882,7 @@ var init_history_source = __esm({
|
|
|
16890
16882
|
};
|
|
16891
16883
|
tryAdd(claudeBackend.historyFile());
|
|
16892
16884
|
try {
|
|
16893
|
-
for (const entry of
|
|
16885
|
+
for (const entry of readdirSync21(home, { withFileTypes: true })) {
|
|
16894
16886
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
16895
16887
|
tryAdd(join28(home, entry.name, "history.jsonl"));
|
|
16896
16888
|
}
|
|
@@ -17047,7 +17039,7 @@ var init_history_source = __esm({
|
|
|
17047
17039
|
});
|
|
17048
17040
|
|
|
17049
17041
|
// ../engine/dist/parsers/paste-source.js
|
|
17050
|
-
import { existsSync as existsSync28, readdirSync as
|
|
17042
|
+
import { existsSync as existsSync28, readdirSync as readdirSync22, readFileSync as readFileSync20, statSync as statSync26 } from "fs";
|
|
17051
17043
|
import { homedir as homedir11 } from "os";
|
|
17052
17044
|
import { join as join29, basename as basename16 } from "path";
|
|
17053
17045
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -17073,7 +17065,7 @@ var init_paste_source = __esm({
|
|
|
17073
17065
|
};
|
|
17074
17066
|
tryAdd(claudeBackend.pasteCacheDir());
|
|
17075
17067
|
try {
|
|
17076
|
-
for (const entry of
|
|
17068
|
+
for (const entry of readdirSync22(home, { withFileTypes: true })) {
|
|
17077
17069
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
17078
17070
|
tryAdd(join29(home, entry.name, "paste-cache"));
|
|
17079
17071
|
}
|
|
@@ -17090,7 +17082,7 @@ var init_paste_source = __esm({
|
|
|
17090
17082
|
for (const cacheDir of this.cacheDirs) {
|
|
17091
17083
|
if (!existsSync28(cacheDir))
|
|
17092
17084
|
continue;
|
|
17093
|
-
const files =
|
|
17085
|
+
const files = readdirSync22(cacheDir).filter((f) => f.endsWith(".txt"));
|
|
17094
17086
|
for (const file of files) {
|
|
17095
17087
|
if (seen.has(file))
|
|
17096
17088
|
continue;
|
|
@@ -17147,7 +17139,7 @@ var init_paste_source = __esm({
|
|
|
17147
17139
|
});
|
|
17148
17140
|
|
|
17149
17141
|
// ../engine/dist/parsers/gemini-source.js
|
|
17150
|
-
import { existsSync as existsSync29, readdirSync as
|
|
17142
|
+
import { existsSync as existsSync29, readdirSync as readdirSync23, readFileSync as readFileSync21, statSync as statSync27 } from "fs";
|
|
17151
17143
|
import { join as join30, basename as basename17 } from "path";
|
|
17152
17144
|
import { createHash as createHash11 } from "crypto";
|
|
17153
17145
|
function loadGeminiProjectMap2() {
|
|
@@ -17189,13 +17181,13 @@ var init_gemini_source = __esm({
|
|
|
17189
17181
|
return;
|
|
17190
17182
|
const seen = /* @__PURE__ */ new Set();
|
|
17191
17183
|
try {
|
|
17192
|
-
for (const projectDirEntry of
|
|
17184
|
+
for (const projectDirEntry of readdirSync23(tmpDir, { withFileTypes: true })) {
|
|
17193
17185
|
if (!projectDirEntry.isDirectory())
|
|
17194
17186
|
continue;
|
|
17195
17187
|
const chatsDir = join30(tmpDir, projectDirEntry.name, "chats");
|
|
17196
17188
|
if (!existsSync29(chatsDir))
|
|
17197
17189
|
continue;
|
|
17198
|
-
for (const file of
|
|
17190
|
+
for (const file of readdirSync23(chatsDir)) {
|
|
17199
17191
|
if (!file.endsWith(".json") || !file.startsWith("session-"))
|
|
17200
17192
|
continue;
|
|
17201
17193
|
const filePath = join30(chatsDir, file);
|
|
@@ -17330,7 +17322,7 @@ var init_gemini_source = __esm({
|
|
|
17330
17322
|
});
|
|
17331
17323
|
|
|
17332
17324
|
// ../engine/dist/parsers/gemini-brain-source.js
|
|
17333
|
-
import { existsSync as existsSync30, readdirSync as
|
|
17325
|
+
import { existsSync as existsSync30, readdirSync as readdirSync24, readFileSync as readFileSync22, statSync as statSync28 } from "fs";
|
|
17334
17326
|
import { join as join31 } from "path";
|
|
17335
17327
|
var MAX_CHUNK_CHARS8, GeminiBrainSource;
|
|
17336
17328
|
var init_gemini_brain_source = __esm({
|
|
@@ -17351,12 +17343,12 @@ var init_gemini_brain_source = __esm({
|
|
|
17351
17343
|
return;
|
|
17352
17344
|
if (!existsSync30(this.brainDir))
|
|
17353
17345
|
return;
|
|
17354
|
-
const sessions =
|
|
17346
|
+
const sessions = readdirSync24(this.brainDir, { withFileTypes: true });
|
|
17355
17347
|
for (const entry of sessions) {
|
|
17356
17348
|
if (!entry.isDirectory())
|
|
17357
17349
|
continue;
|
|
17358
17350
|
const sessionDir = join31(this.brainDir, entry.name);
|
|
17359
|
-
const files =
|
|
17351
|
+
const files = readdirSync24(sessionDir).filter((f) => f.endsWith(".md") && !f.includes(".resolved") && !f.includes(".metadata"));
|
|
17360
17352
|
if (files.length === 0)
|
|
17361
17353
|
continue;
|
|
17362
17354
|
for (const file of files) {
|
|
@@ -17744,7 +17736,7 @@ var init_opencode_todo_source = __esm({
|
|
|
17744
17736
|
});
|
|
17745
17737
|
|
|
17746
17738
|
// ../engine/dist/parsers/codex-session-source.js
|
|
17747
|
-
import { existsSync as existsSync33, readdirSync as
|
|
17739
|
+
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as readFileSync23, statSync as statSync29 } from "fs";
|
|
17748
17740
|
import { join as join32, basename as basename18 } from "path";
|
|
17749
17741
|
function getCodexSessionsDir() {
|
|
17750
17742
|
return codexBackend.sessionsDir();
|
|
@@ -17965,7 +17957,7 @@ var init_codex_session_source = __esm({
|
|
|
17965
17957
|
const results = [];
|
|
17966
17958
|
if (!existsSync33(dir))
|
|
17967
17959
|
return results;
|
|
17968
|
-
for (const entry of
|
|
17960
|
+
for (const entry of readdirSync25(dir, { withFileTypes: true })) {
|
|
17969
17961
|
const fullPath = join32(dir, entry.name);
|
|
17970
17962
|
if (entry.isDirectory()) {
|
|
17971
17963
|
results.push(...this.collectJsonlFiles(fullPath));
|
|
@@ -17980,7 +17972,7 @@ var init_codex_session_source = __esm({
|
|
|
17980
17972
|
});
|
|
17981
17973
|
|
|
17982
17974
|
// ../engine/dist/parsers/diary-source.js
|
|
17983
|
-
import { existsSync as existsSync34, mkdirSync as mkdirSync5, readdirSync as
|
|
17975
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync5, readdirSync as readdirSync26, readFileSync as readFileSync24, writeFileSync as writeFileSync4, statSync as statSync30 } from "fs";
|
|
17984
17976
|
import { join as join33, basename as basename19 } from "path";
|
|
17985
17977
|
var MAX_CHUNK_CHARS11, DiarySource;
|
|
17986
17978
|
var init_diary_source = __esm({
|
|
@@ -17998,10 +17990,10 @@ var init_diary_source = __esm({
|
|
|
17998
17990
|
async *discover() {
|
|
17999
17991
|
if (!existsSync34(this.diaryDir))
|
|
18000
17992
|
return;
|
|
18001
|
-
const agents =
|
|
17993
|
+
const agents = readdirSync26(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
18002
17994
|
for (const agentDir of agents) {
|
|
18003
17995
|
const agentPath2 = join33(this.diaryDir, agentDir.name);
|
|
18004
|
-
const files =
|
|
17996
|
+
const files = readdirSync26(agentPath2).filter((f) => f.endsWith(".json"));
|
|
18005
17997
|
for (const file of files) {
|
|
18006
17998
|
const filePath = join33(agentPath2, file);
|
|
18007
17999
|
try {
|
|
@@ -18092,7 +18084,7 @@ var init_diary_source = __esm({
|
|
|
18092
18084
|
const agentDir = join33(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
18093
18085
|
if (!existsSync34(agentDir))
|
|
18094
18086
|
return [];
|
|
18095
|
-
const files =
|
|
18087
|
+
const files = readdirSync26(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
|
|
18096
18088
|
const entries = [];
|
|
18097
18089
|
for (const file of files) {
|
|
18098
18090
|
try {
|
|
@@ -18141,7 +18133,7 @@ var init_redact_inline = __esm({
|
|
|
18141
18133
|
});
|
|
18142
18134
|
|
|
18143
18135
|
// ../engine/dist/parsers/skills-source.js
|
|
18144
|
-
import { existsSync as existsSync35, readdirSync as
|
|
18136
|
+
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
18145
18137
|
import { homedir as homedir12 } from "os";
|
|
18146
18138
|
import { join as join34 } from "path";
|
|
18147
18139
|
function rebuildBody(content) {
|
|
@@ -18222,7 +18214,7 @@ var init_skills_source = __esm({
|
|
|
18222
18214
|
return;
|
|
18223
18215
|
const codexPluginsDir = codexBackend.pluginsDir();
|
|
18224
18216
|
if (existsSync35(codexPluginsDir)) {
|
|
18225
|
-
for (const pluginName of
|
|
18217
|
+
for (const pluginName of readdirSync27(codexPluginsDir)) {
|
|
18226
18218
|
const skillsDir = join34(codexPluginsDir, pluginName, "skills");
|
|
18227
18219
|
if (!existsSync35(skillsDir))
|
|
18228
18220
|
continue;
|
|
@@ -18233,7 +18225,7 @@ var init_skills_source = __esm({
|
|
|
18233
18225
|
async *fromSkillRoot(root, pluginName) {
|
|
18234
18226
|
let entries;
|
|
18235
18227
|
try {
|
|
18236
|
-
entries =
|
|
18228
|
+
entries = readdirSync27(root.path);
|
|
18237
18229
|
} catch {
|
|
18238
18230
|
return;
|
|
18239
18231
|
}
|
|
@@ -18267,14 +18259,14 @@ var init_skills_source = __esm({
|
|
|
18267
18259
|
}
|
|
18268
18260
|
const subdirs = {};
|
|
18269
18261
|
try {
|
|
18270
|
-
for (const sub of
|
|
18262
|
+
for (const sub of readdirSync27(skillDir)) {
|
|
18271
18263
|
const subPath = join34(skillDir, sub);
|
|
18272
18264
|
try {
|
|
18273
18265
|
const ss = statSync31(subPath);
|
|
18274
18266
|
if (ss.isDirectory()) {
|
|
18275
18267
|
let count = 0;
|
|
18276
18268
|
try {
|
|
18277
|
-
count =
|
|
18269
|
+
count = readdirSync27(subPath).length;
|
|
18278
18270
|
} catch {
|
|
18279
18271
|
}
|
|
18280
18272
|
subdirs[sub] = count;
|
|
@@ -18340,7 +18332,7 @@ var init_skills_source = __esm({
|
|
|
18340
18332
|
});
|
|
18341
18333
|
|
|
18342
18334
|
// ../engine/dist/parsers/mcps-source.js
|
|
18343
|
-
import { existsSync as existsSync36, readdirSync as
|
|
18335
|
+
import { existsSync as existsSync36, readdirSync as readdirSync28, readFileSync as readFileSync26, statSync as statSync32 } from "fs";
|
|
18344
18336
|
import { homedir as homedir13 } from "os";
|
|
18345
18337
|
import { join as join35 } from "path";
|
|
18346
18338
|
function readJson(path) {
|
|
@@ -18454,7 +18446,7 @@ var init_mcps_source = __esm({
|
|
|
18454
18446
|
yield* this.fromCodexToml(codexBackend.configToml());
|
|
18455
18447
|
const pluginsDir = codexBackend.pluginsDir();
|
|
18456
18448
|
if (existsSync36(pluginsDir)) {
|
|
18457
|
-
for (const plugin of
|
|
18449
|
+
for (const plugin of readdirSync28(pluginsDir)) {
|
|
18458
18450
|
const mcpPath = join35(pluginsDir, plugin, ".mcp.json");
|
|
18459
18451
|
yield* this.fromObject(readJson(mcpPath)?.mcpServers, {
|
|
18460
18452
|
tool: "codex",
|
|
@@ -18678,7 +18670,7 @@ var init_toolkit_format = __esm({
|
|
|
18678
18670
|
});
|
|
18679
18671
|
|
|
18680
18672
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
18681
|
-
import { existsSync as existsSync37, readdirSync as
|
|
18673
|
+
import { existsSync as existsSync37, readdirSync as readdirSync29, readFileSync as readFileSync27, statSync as statSync33 } from "fs";
|
|
18682
18674
|
import { join as join36, basename as basename20 } from "path";
|
|
18683
18675
|
function rebuildBody2(content) {
|
|
18684
18676
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -18733,10 +18725,10 @@ var init_slash_commands_source = __esm({
|
|
|
18733
18725
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18734
18726
|
if (existsSync37(projectsRoot)) {
|
|
18735
18727
|
try {
|
|
18736
|
-
for (const entry of
|
|
18728
|
+
for (const entry of readdirSync29(projectsRoot, { withFileTypes: true })) {
|
|
18737
18729
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18738
18730
|
continue;
|
|
18739
|
-
const projectPath =
|
|
18731
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
18740
18732
|
const cmdDir = join36(projectPath, ".claude", "commands");
|
|
18741
18733
|
if (existsSync37(cmdDir))
|
|
18742
18734
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -18764,7 +18756,7 @@ var init_slash_commands_source = __esm({
|
|
|
18764
18756
|
const ext = root.format === "toml" ? ".toml" : ".md";
|
|
18765
18757
|
let files;
|
|
18766
18758
|
try {
|
|
18767
|
-
files =
|
|
18759
|
+
files = readdirSync29(root.path).filter((f) => f.endsWith(ext));
|
|
18768
18760
|
} catch {
|
|
18769
18761
|
continue;
|
|
18770
18762
|
}
|
|
@@ -18824,7 +18816,7 @@ var init_slash_commands_source = __esm({
|
|
|
18824
18816
|
});
|
|
18825
18817
|
|
|
18826
18818
|
// ../engine/dist/parsers/subagents-source.js
|
|
18827
|
-
import { existsSync as existsSync38, readdirSync as
|
|
18819
|
+
import { existsSync as existsSync38, readdirSync as readdirSync30, readFileSync as readFileSync28, statSync as statSync34 } from "fs";
|
|
18828
18820
|
import { join as join37, basename as basename21 } from "path";
|
|
18829
18821
|
function rebuildBody3(content) {
|
|
18830
18822
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -18881,10 +18873,10 @@ var init_subagents_source = __esm({
|
|
|
18881
18873
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18882
18874
|
if (existsSync38(projectsRoot)) {
|
|
18883
18875
|
try {
|
|
18884
|
-
for (const entry of
|
|
18876
|
+
for (const entry of readdirSync30(projectsRoot, { withFileTypes: true })) {
|
|
18885
18877
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18886
18878
|
continue;
|
|
18887
|
-
const projectPath =
|
|
18879
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
18888
18880
|
const agentDir = join37(projectPath, ".claude", "agents");
|
|
18889
18881
|
if (existsSync38(agentDir))
|
|
18890
18882
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -18912,7 +18904,7 @@ var init_subagents_source = __esm({
|
|
|
18912
18904
|
const ext = root.format === "toml" ? ".toml" : ".md";
|
|
18913
18905
|
let files;
|
|
18914
18906
|
try {
|
|
18915
|
-
files =
|
|
18907
|
+
files = readdirSync30(root.path).filter((f) => f.endsWith(ext));
|
|
18916
18908
|
} catch {
|
|
18917
18909
|
continue;
|
|
18918
18910
|
}
|
|
@@ -18973,7 +18965,7 @@ var init_subagents_source = __esm({
|
|
|
18973
18965
|
});
|
|
18974
18966
|
|
|
18975
18967
|
// ../engine/dist/parsers/hooks-source.js
|
|
18976
|
-
import { existsSync as existsSync39, readFileSync as readFileSync29, readdirSync as
|
|
18968
|
+
import { existsSync as existsSync39, readFileSync as readFileSync29, readdirSync as readdirSync31, statSync as statSync35 } from "fs";
|
|
18977
18969
|
import { join as join38 } from "path";
|
|
18978
18970
|
function readJson2(path) {
|
|
18979
18971
|
if (!existsSync39(path))
|
|
@@ -19000,10 +18992,10 @@ var init_hooks_source = __esm({
|
|
|
19000
18992
|
const projectsRoot = claudeBackend.projectsDir();
|
|
19001
18993
|
if (existsSync39(projectsRoot)) {
|
|
19002
18994
|
try {
|
|
19003
|
-
for (const entry of
|
|
18995
|
+
for (const entry of readdirSync31(projectsRoot, { withFileTypes: true })) {
|
|
19004
18996
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
19005
18997
|
continue;
|
|
19006
|
-
const projectPath =
|
|
18998
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
19007
18999
|
const settingsPath2 = join38(projectPath, ".claude", "settings.json");
|
|
19008
19000
|
if (existsSync39(settingsPath2)) {
|
|
19009
19001
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
@@ -19096,7 +19088,7 @@ var init_hooks_source = __esm({
|
|
|
19096
19088
|
});
|
|
19097
19089
|
|
|
19098
19090
|
// ../engine/dist/parsers/plugins-source.js
|
|
19099
|
-
import { existsSync as existsSync40, readFileSync as readFileSync30, readdirSync as
|
|
19091
|
+
import { existsSync as existsSync40, readFileSync as readFileSync30, readdirSync as readdirSync32, statSync as statSync36 } from "fs";
|
|
19100
19092
|
import { homedir as homedir14 } from "os";
|
|
19101
19093
|
import { join as join39 } from "path";
|
|
19102
19094
|
function readJson3(path) {
|
|
@@ -19158,7 +19150,7 @@ var init_plugins_source = __esm({
|
|
|
19158
19150
|
if (isSourceEnabled("gemini", "extensions") && existsSync40(gemRoot)) {
|
|
19159
19151
|
let entries;
|
|
19160
19152
|
try {
|
|
19161
|
-
entries =
|
|
19153
|
+
entries = readdirSync32(gemRoot);
|
|
19162
19154
|
} catch {
|
|
19163
19155
|
entries = [];
|
|
19164
19156
|
}
|
|
@@ -19206,7 +19198,7 @@ var init_plugins_source = __esm({
|
|
|
19206
19198
|
if (isSourceEnabled("codex", "plugins") && existsSync40(codexPluginsRoot)) {
|
|
19207
19199
|
let entries;
|
|
19208
19200
|
try {
|
|
19209
|
-
entries =
|
|
19201
|
+
entries = readdirSync32(codexPluginsRoot);
|
|
19210
19202
|
} catch {
|
|
19211
19203
|
entries = [];
|
|
19212
19204
|
}
|
|
@@ -19362,7 +19354,7 @@ var init_extractor_version = __esm({
|
|
|
19362
19354
|
command: 1
|
|
19363
19355
|
};
|
|
19364
19356
|
TOOL_EXTRACTOR_BUMP = {
|
|
19365
|
-
agy:
|
|
19357
|
+
agy: 3,
|
|
19366
19358
|
claude: 1,
|
|
19367
19359
|
codex: 1
|
|
19368
19360
|
};
|
|
@@ -19502,13 +19494,13 @@ function markSynced(server, rows) {
|
|
|
19502
19494
|
const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
|
|
19503
19495
|
const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
|
|
19504
19496
|
const ev = extractorVersionForId(r.id);
|
|
19505
|
-
const
|
|
19497
|
+
const base3 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
|
|
19506
19498
|
if (o > 0 || s > 0) {
|
|
19507
|
-
|
|
19508
|
-
|
|
19499
|
+
base3.o = o;
|
|
19500
|
+
base3.s = s;
|
|
19509
19501
|
}
|
|
19510
|
-
if (r.hash !== void 0)
|
|
19511
|
-
forServer[r.id] =
|
|
19502
|
+
if (r.hash !== void 0) base3.h = r.hash;
|
|
19503
|
+
forServer[r.id] = base3;
|
|
19512
19504
|
}
|
|
19513
19505
|
persist(data);
|
|
19514
19506
|
}
|
|
@@ -19750,7 +19742,7 @@ var init_http = __esm({
|
|
|
19750
19742
|
CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19751
19743
|
} catch {
|
|
19752
19744
|
try {
|
|
19753
|
-
if (true) CLI_VERSION = "0.5.
|
|
19745
|
+
if (true) CLI_VERSION = "0.5.32";
|
|
19754
19746
|
} catch {
|
|
19755
19747
|
}
|
|
19756
19748
|
}
|
|
@@ -20100,9 +20092,9 @@ function cooldownFor(failures) {
|
|
|
20100
20092
|
function breakerState(serverUrl, now = Date.now()) {
|
|
20101
20093
|
const s = state.get(key(serverUrl));
|
|
20102
20094
|
if (!s || s.openUntil <= now) {
|
|
20103
|
-
return { open: false, retryInMs: 0, failures: s?.failures ?? 0, lastError: s?.lastError ?? "" };
|
|
20095
|
+
return { open: false, retryInMs: 0, failures: s?.failures ?? 0, lastError: s?.lastError ?? "", tripped: false };
|
|
20104
20096
|
}
|
|
20105
|
-
return { open: true, retryInMs: s.openUntil - now, failures: s.failures, lastError: s.lastError };
|
|
20097
|
+
return { open: true, retryInMs: s.openUntil - now, failures: s.failures, lastError: s.lastError, tripped: false };
|
|
20106
20098
|
}
|
|
20107
20099
|
function noteTargetSuccess(serverUrl) {
|
|
20108
20100
|
state.delete(key(serverUrl));
|
|
@@ -20114,11 +20106,11 @@ function noteTargetFailure(serverUrl, error, now = Date.now()) {
|
|
|
20114
20106
|
const lastError = error.slice(0, 200);
|
|
20115
20107
|
if (failures < TRIP_AFTER_FAILURES) {
|
|
20116
20108
|
state.set(k, { failures, openUntil: 0, lastError });
|
|
20117
|
-
return { open: false, retryInMs: 0, failures, lastError };
|
|
20109
|
+
return { open: false, retryInMs: 0, failures, lastError, tripped: false };
|
|
20118
20110
|
}
|
|
20119
20111
|
const cooldown = cooldownFor(failures);
|
|
20120
20112
|
state.set(k, { failures, openUntil: now + cooldown, lastError });
|
|
20121
|
-
return { open: true, retryInMs: cooldown, failures, lastError };
|
|
20113
|
+
return { open: true, retryInMs: cooldown, failures, lastError, tripped: failures === TRIP_AFTER_FAILURES };
|
|
20122
20114
|
}
|
|
20123
20115
|
function breakerNotice(serverUrl, v) {
|
|
20124
20116
|
if (!v.open) return null;
|
|
@@ -20245,6 +20237,14 @@ async function flush() {
|
|
|
20245
20237
|
}
|
|
20246
20238
|
}));
|
|
20247
20239
|
}
|
|
20240
|
+
function stableMark(value) {
|
|
20241
|
+
try {
|
|
20242
|
+
const { createHash: createHash20 } = __require("node:crypto");
|
|
20243
|
+
return createHash20("sha256").update(value).digest("hex").slice(0, 12);
|
|
20244
|
+
} catch {
|
|
20245
|
+
return "";
|
|
20246
|
+
}
|
|
20247
|
+
}
|
|
20248
20248
|
function hashHost() {
|
|
20249
20249
|
try {
|
|
20250
20250
|
const { createHash: createHash20 } = __require("node:crypto");
|
|
@@ -20262,7 +20262,7 @@ var init_telemetry = __esm({
|
|
|
20262
20262
|
init_sync_client();
|
|
20263
20263
|
cliVersion2 = () => {
|
|
20264
20264
|
try {
|
|
20265
|
-
return true ? "0.5.
|
|
20265
|
+
return true ? "0.5.32" : "dev";
|
|
20266
20266
|
} catch {
|
|
20267
20267
|
return "dev";
|
|
20268
20268
|
}
|
|
@@ -20399,11 +20399,11 @@ __export(server_probe_exports, {
|
|
|
20399
20399
|
function probeOk(r) {
|
|
20400
20400
|
return r.kind === "ok" && r.apiVersion >= 2;
|
|
20401
20401
|
}
|
|
20402
|
-
async function probeServer(
|
|
20402
|
+
async function probeServer(base3, opts = {}) {
|
|
20403
20403
|
const f = opts.fetchImpl || fetch;
|
|
20404
20404
|
let res;
|
|
20405
20405
|
try {
|
|
20406
|
-
res = await f(`${
|
|
20406
|
+
res = await f(`${base3.replace(/\/+$/, "")}/api/capabilities`, {
|
|
20407
20407
|
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
20408
20408
|
});
|
|
20409
20409
|
} catch (err) {
|
|
@@ -20440,34 +20440,34 @@ async function probeServer(base2, opts = {}) {
|
|
|
20440
20440
|
raw: parsed
|
|
20441
20441
|
};
|
|
20442
20442
|
}
|
|
20443
|
-
function probeAdvice(r,
|
|
20443
|
+
function probeAdvice(r, base3) {
|
|
20444
20444
|
switch (r.kind) {
|
|
20445
20445
|
case "ok":
|
|
20446
20446
|
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`;
|
|
20447
20447
|
case "moved":
|
|
20448
|
-
return `HTTP ${r.status} \u2014 nothing is served at ${
|
|
20448
|
+
return `HTTP ${r.status} \u2014 nothing is served at ${base3}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
|
|
20449
20449
|
case "unauthorized":
|
|
20450
|
-
return `HTTP ${r.status} \u2014 ${
|
|
20450
|
+
return `HTTP ${r.status} \u2014 ${base3} rejected the credential. Re-login: \`chat-recall login ` + base3 + "`";
|
|
20451
20451
|
case "server_error":
|
|
20452
|
-
return `HTTP ${r.status} \u2014 ${
|
|
20452
|
+
return `HTTP ${r.status} \u2014 ${base3} is up but failing. Nothing to fix locally; check the server.`;
|
|
20453
20453
|
case "not_api":
|
|
20454
|
-
return `${
|
|
20454
|
+
return `${base3} 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`;
|
|
20455
20455
|
case "unreachable":
|
|
20456
20456
|
switch (r.reason) {
|
|
20457
20457
|
case "dns":
|
|
20458
|
-
return `cannot resolve the host in ${
|
|
20458
|
+
return `cannot resolve the host in ${base3} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
|
|
20459
20459
|
case "refused":
|
|
20460
|
-
return `${
|
|
20460
|
+
return `${base3} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
|
|
20461
20461
|
case "tls":
|
|
20462
|
-
return `the TLS certificate at ${
|
|
20462
|
+
return `the TLS certificate at ${base3} was rejected (${r.error}) \u2014 expired, self-signed, or issued for another host. A corporate proxy that re-signs traffic does this.`;
|
|
20463
20463
|
case "timeout":
|
|
20464
|
-
return `${
|
|
20464
|
+
return `${base3} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
|
|
20465
20465
|
case "reset":
|
|
20466
|
-
return `the connection to ${
|
|
20466
|
+
return `the connection to ${base3} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
|
|
20467
20467
|
case "bad_port":
|
|
20468
|
-
return `${
|
|
20468
|
+
return `${base3} names a port that Node and every browser refuse to open (the WHATWG bad-port list) \u2014 use the server's real port`;
|
|
20469
20469
|
default:
|
|
20470
|
-
return `no HTTP response from ${
|
|
20470
|
+
return `no HTTP response from ${base3} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
|
|
20471
20471
|
}
|
|
20472
20472
|
}
|
|
20473
20473
|
}
|
|
@@ -20500,8 +20500,8 @@ function describeCause(err) {
|
|
|
20500
20500
|
const code2 = e.code;
|
|
20501
20501
|
if (typeof code2 === "string" && code2 && !parts.includes(code2)) parts.push(code2);
|
|
20502
20502
|
}
|
|
20503
|
-
const
|
|
20504
|
-
return parts.length ? `${
|
|
20503
|
+
const base3 = err instanceof Error ? err.message : String(err);
|
|
20504
|
+
return parts.length ? `${base3}: ${parts.join(" \u2192 ")}` : base3;
|
|
20505
20505
|
}
|
|
20506
20506
|
function describeUnreachable(err) {
|
|
20507
20507
|
const reason = classifyUnreachable(err);
|
|
@@ -20605,7 +20605,7 @@ __export(auto_update_exports, {
|
|
|
20605
20605
|
import { execSync as execSync2 } from "node:child_process";
|
|
20606
20606
|
import { readFileSync as readFileSync36 } from "node:fs";
|
|
20607
20607
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20608
|
-
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as
|
|
20608
|
+
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync33, statSync as statSync38 } from "node:fs";
|
|
20609
20609
|
import { join as join43, dirname as dirname18, sep as sep2 } from "node:path";
|
|
20610
20610
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
20611
20611
|
import { createHash as createHash12 } from "node:crypto";
|
|
@@ -20637,12 +20637,12 @@ function installedVersion() {
|
|
|
20637
20637
|
return null;
|
|
20638
20638
|
}
|
|
20639
20639
|
}
|
|
20640
|
-
function planAutoUpdate(
|
|
20640
|
+
function planAutoUpdate(base3, caps, ownVersion3, flag) {
|
|
20641
20641
|
const rel = caps.cli;
|
|
20642
20642
|
if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
|
|
20643
20643
|
if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
|
|
20644
20644
|
if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
|
|
20645
|
-
return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(
|
|
20645
|
+
return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base3), sha256: rel.sha256, from: ownVersion3, to: rel.version };
|
|
20646
20646
|
}
|
|
20647
20647
|
function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
20648
20648
|
const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
|
|
@@ -20650,7 +20650,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
|
20650
20650
|
let removed = 0;
|
|
20651
20651
|
let entries;
|
|
20652
20652
|
try {
|
|
20653
|
-
entries =
|
|
20653
|
+
entries = readdirSync33(root);
|
|
20654
20654
|
} catch {
|
|
20655
20655
|
return 0;
|
|
20656
20656
|
}
|
|
@@ -20660,7 +20660,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
|
20660
20660
|
try {
|
|
20661
20661
|
const st = statSync38(dir);
|
|
20662
20662
|
if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
|
|
20663
|
-
const inside =
|
|
20663
|
+
const inside = readdirSync33(dir);
|
|
20664
20664
|
if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
|
|
20665
20665
|
rmSync5(dir, { recursive: true, force: true });
|
|
20666
20666
|
removed++;
|
|
@@ -20738,18 +20738,28 @@ function realRestart(platform2) {
|
|
|
20738
20738
|
else if (platform2 === "darwin") execSync2("launchctl kickstart -k gui/$(id -u)/com.chat-recall.watch", { stdio: "ignore", shell: "/bin/bash" });
|
|
20739
20739
|
else if (platform2 === "win32") execSync2("schtasks /End /TN chat-recall-watch & schtasks /Run /TN chat-recall-watch", { stdio: "ignore" });
|
|
20740
20740
|
}
|
|
20741
|
-
async function runAutoUpdate(
|
|
20741
|
+
async function runAutoUpdate(base3, authHeaders, ownVersion3, deps) {
|
|
20742
20742
|
let caps;
|
|
20743
20743
|
try {
|
|
20744
|
-
const res = await fetchWithTimeout(`${
|
|
20744
|
+
const res = await fetchWithTimeout(`${base3.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
|
|
20745
20745
|
if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
|
|
20746
20746
|
caps = await res.json();
|
|
20747
20747
|
} catch (e) {
|
|
20748
20748
|
return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
|
|
20749
20749
|
}
|
|
20750
20750
|
const effectiveOwn = newerOf(ownVersion3, installedVersion());
|
|
20751
|
-
const plan = planAutoUpdate(
|
|
20752
|
-
if (!plan.update)
|
|
20751
|
+
const plan = planAutoUpdate(base3, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20752
|
+
if (!plan.update) {
|
|
20753
|
+
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base3)) {
|
|
20754
|
+
reportedStandingSkip.add(base3);
|
|
20755
|
+
try {
|
|
20756
|
+
const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
|
|
20757
|
+
reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
|
|
20758
|
+
} catch {
|
|
20759
|
+
}
|
|
20760
|
+
}
|
|
20761
|
+
return { updated: false, reason: plan.reason };
|
|
20762
|
+
}
|
|
20753
20763
|
const result = await executeAutoUpdate(plan, {
|
|
20754
20764
|
download: deps?.download ?? realDownload,
|
|
20755
20765
|
install: deps?.install ?? realInstall,
|
|
@@ -20765,12 +20775,13 @@ async function runAutoUpdate(base2, authHeaders, ownVersion3, deps) {
|
|
|
20765
20775
|
}
|
|
20766
20776
|
return result;
|
|
20767
20777
|
}
|
|
20768
|
-
var tarballUrl;
|
|
20778
|
+
var tarballUrl, reportedStandingSkip;
|
|
20769
20779
|
var init_auto_update = __esm({
|
|
20770
20780
|
"src/auto-update.ts"() {
|
|
20771
20781
|
"use strict";
|
|
20772
20782
|
init_http();
|
|
20773
|
-
tarballUrl = (
|
|
20783
|
+
tarballUrl = (base3) => `${base3.replace(/\/+$/, "")}/install/chat-recall.tgz`;
|
|
20784
|
+
reportedStandingSkip = /* @__PURE__ */ new Set();
|
|
20774
20785
|
}
|
|
20775
20786
|
});
|
|
20776
20787
|
|
|
@@ -20786,6 +20797,9 @@ __export(sync_client_exports, {
|
|
|
20786
20797
|
batchScanExternal: () => batchScanExternal,
|
|
20787
20798
|
buildConversationSync: () => buildConversationSync,
|
|
20788
20799
|
buildConversationTail: () => buildConversationTail,
|
|
20800
|
+
classedError: () => classedError,
|
|
20801
|
+
classifyError: () => classifyError,
|
|
20802
|
+
isStandingFailure: () => isStandingFailure,
|
|
20789
20803
|
isSyncSkip: () => isSyncSkip,
|
|
20790
20804
|
loadAllCredentials: () => loadAllCredentials,
|
|
20791
20805
|
loadCredentials: () => loadCredentials,
|
|
@@ -20801,22 +20815,37 @@ __export(sync_client_exports, {
|
|
|
20801
20815
|
syncSessions: () => syncSessions
|
|
20802
20816
|
});
|
|
20803
20817
|
import { join as join44, dirname as dirname19, basename as basename22 } from "node:path";
|
|
20804
|
-
import { readFileSync as readFileSync37, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as
|
|
20818
|
+
import { readFileSync as readFileSync37, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync34, statSync as statSync39 } from "node:fs";
|
|
20805
20819
|
import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
|
|
20806
20820
|
import { createHash as createHash13 } from "node:crypto";
|
|
20807
20821
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
20808
20822
|
import { gzipSync as gzipSync3 } from "zlib";
|
|
20809
|
-
function
|
|
20823
|
+
function classedError(errorClass, message) {
|
|
20824
|
+
const e = new Error(message);
|
|
20825
|
+
Object.defineProperty(e, ERROR_CLASS, { value: errorClass, enumerable: false });
|
|
20826
|
+
return e;
|
|
20827
|
+
}
|
|
20828
|
+
function taggedClass(err) {
|
|
20829
|
+
const v = err?.[ERROR_CLASS];
|
|
20830
|
+
return typeof v === "string" && v ? v : null;
|
|
20831
|
+
}
|
|
20832
|
+
function isStandingFailure(err) {
|
|
20833
|
+
const c = taggedClass(err);
|
|
20834
|
+
return c !== null && STANDING_FAILURE.has(c);
|
|
20835
|
+
}
|
|
20836
|
+
function classifyError(msg, err) {
|
|
20837
|
+
const tagged = taggedClass(err);
|
|
20838
|
+
if (tagged) return tagged;
|
|
20810
20839
|
const m = msg.toLowerCase();
|
|
20811
20840
|
if (m.includes("429")) return "rate_limited";
|
|
20812
20841
|
if (m.includes("402")) return "payment_required";
|
|
20813
20842
|
if (m.includes("401") || m.includes("403") || m.includes("token")) return "auth";
|
|
20814
|
-
if (m.includes("timed out") || m.includes("etimedout")) return "timeout";
|
|
20843
|
+
if (m.includes("timed out") || m.includes("etimedout") || m.includes("aborted due to timeout")) return "timeout";
|
|
20815
20844
|
if (m.includes("econnrefused")) return "refused";
|
|
20816
20845
|
if (m.includes("enotfound") || m.includes("dns")) return "dns";
|
|
20817
20846
|
if (m.includes("fetch failed") || m.includes("econnreset")) return "network";
|
|
20818
|
-
if (m.includes("plain http") || m.includes("
|
|
20819
|
-
if (
|
|
20847
|
+
if (m.includes("over plain http") || m.includes("unsupported scheme")) return "insecure_transport";
|
|
20848
|
+
if (/\b5\d\d\b/.test(m)) return "server_error";
|
|
20820
20849
|
return "other";
|
|
20821
20850
|
}
|
|
20822
20851
|
function saveCredentials(c) {
|
|
@@ -20849,15 +20878,15 @@ function loadAllCredentials() {
|
|
|
20849
20878
|
return [];
|
|
20850
20879
|
}
|
|
20851
20880
|
async function fetchTenantSecurityConfig(cred) {
|
|
20852
|
-
const
|
|
20853
|
-
const cached = _securityConfigCache.get(
|
|
20881
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
20882
|
+
const cached = _securityConfigCache.get(base3);
|
|
20854
20883
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20855
20884
|
const headers = { "content-type": "application/json" };
|
|
20856
20885
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
20857
20886
|
try {
|
|
20858
20887
|
const [rulesRes, settingsRes] = await Promise.all([
|
|
20859
|
-
fetchWithTimeout(`${
|
|
20860
|
-
fetchWithTimeout(`${
|
|
20888
|
+
fetchWithTimeout(`${base3}/api/secrets/rules`, { headers }),
|
|
20889
|
+
fetchWithTimeout(`${base3}/api/teams/security-config`, { headers }).catch(() => null)
|
|
20861
20890
|
]);
|
|
20862
20891
|
let tenantRules = [];
|
|
20863
20892
|
let rulePackVersion = null;
|
|
@@ -20882,18 +20911,18 @@ async function fetchTenantSecurityConfig(cred) {
|
|
|
20882
20911
|
const body = await settingsRes.json().catch(() => ({}));
|
|
20883
20912
|
if (typeof body.verifySecrets === "boolean") verifySecrets = body.verifySecrets;
|
|
20884
20913
|
if (typeof body.telemetry === "boolean") {
|
|
20885
|
-
setTelemetryEligible(
|
|
20914
|
+
setTelemetryEligible(base3, body.telemetry);
|
|
20886
20915
|
try {
|
|
20887
20916
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
20888
20917
|
updateCollectorHealth({
|
|
20889
|
-
telemetryEligible: { ...prior, [
|
|
20918
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body.telemetry, at: Date.now() } }
|
|
20890
20919
|
});
|
|
20891
20920
|
} catch {
|
|
20892
20921
|
}
|
|
20893
20922
|
}
|
|
20894
20923
|
}
|
|
20895
20924
|
const config2 = { tenantRules, verifySecrets, rulePackVersion };
|
|
20896
|
-
_securityConfigCache.set(
|
|
20925
|
+
_securityConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
|
|
20897
20926
|
return config2;
|
|
20898
20927
|
} catch {
|
|
20899
20928
|
return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
|
|
@@ -20912,18 +20941,18 @@ function readPersistedSyncConfigs() {
|
|
|
20912
20941
|
return {};
|
|
20913
20942
|
}
|
|
20914
20943
|
}
|
|
20915
|
-
function persistSyncConfig(
|
|
20944
|
+
function persistSyncConfig(base3, config2) {
|
|
20916
20945
|
try {
|
|
20917
20946
|
const all = readPersistedSyncConfigs();
|
|
20918
|
-
all[
|
|
20947
|
+
all[base3] = { fetchedAt: Date.now(), config: config2 };
|
|
20919
20948
|
mkdirSync9(dirname19(syncConfigCachePath()), { recursive: true });
|
|
20920
20949
|
writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
|
|
20921
20950
|
} catch {
|
|
20922
20951
|
}
|
|
20923
20952
|
}
|
|
20924
20953
|
async function fetchTenantSyncConfig(cred) {
|
|
20925
|
-
const
|
|
20926
|
-
const cached = _syncConfigCache.get(
|
|
20954
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
20955
|
+
const cached = _syncConfigCache.get(base3);
|
|
20927
20956
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20928
20957
|
const headers = { "content-type": "application/json" };
|
|
20929
20958
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
@@ -20931,7 +20960,7 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20931
20960
|
try {
|
|
20932
20961
|
const sources3 = discoverSessionSources();
|
|
20933
20962
|
if (sources3.length > 0) {
|
|
20934
|
-
await fetchWithTimeout(`${
|
|
20963
|
+
await fetchWithTimeout(`${base3}/api/sync-config/sources`, {
|
|
20935
20964
|
method: "POST",
|
|
20936
20965
|
headers,
|
|
20937
20966
|
body: JSON.stringify({ device: deviceLabel(), sources: sources3 })
|
|
@@ -20939,12 +20968,12 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20939
20968
|
}
|
|
20940
20969
|
} catch {
|
|
20941
20970
|
}
|
|
20942
|
-
const res = await fetchWithTimeout(`${
|
|
20971
|
+
const res = await fetchWithTimeout(`${base3}/api/sync-config`, { headers });
|
|
20943
20972
|
if (res.status === 404) {
|
|
20944
|
-
_syncConfigCache.set(
|
|
20973
|
+
_syncConfigCache.set(base3, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
|
|
20945
20974
|
return EMPTY_SYNC_CONFIG;
|
|
20946
20975
|
}
|
|
20947
|
-
if (!res.ok) return lastKnownSyncConfig(
|
|
20976
|
+
if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
|
|
20948
20977
|
const body = await res.json().catch(() => ({}));
|
|
20949
20978
|
const config2 = {
|
|
20950
20979
|
excludeTools: Array.isArray(body.excludeTools) ? body.excludeTools.filter((t) => typeof t === "string") : [],
|
|
@@ -20981,22 +21010,22 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20981
21010
|
if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
|
|
20982
21011
|
} catch {
|
|
20983
21012
|
}
|
|
20984
|
-
_syncConfigCache.set(
|
|
20985
|
-
persistSyncConfig(
|
|
21013
|
+
_syncConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
|
|
21014
|
+
persistSyncConfig(base3, config2);
|
|
20986
21015
|
return config2;
|
|
20987
21016
|
} catch (err) {
|
|
20988
21017
|
if (isSyncRulesRefusal(err)) throw err;
|
|
20989
|
-
return lastKnownSyncConfig(
|
|
21018
|
+
return lastKnownSyncConfig(base3, err instanceof Error ? err.message : "request failed");
|
|
20990
21019
|
}
|
|
20991
21020
|
}
|
|
20992
|
-
function lastKnownSyncConfig(
|
|
20993
|
-
const remembered = _syncConfigCache.get(
|
|
21021
|
+
function lastKnownSyncConfig(base3, reason) {
|
|
21022
|
+
const remembered = _syncConfigCache.get(base3) ?? readPersistedSyncConfigs()[base3];
|
|
20994
21023
|
if (remembered) {
|
|
20995
21024
|
console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
|
|
20996
21025
|
return remembered.config;
|
|
20997
21026
|
}
|
|
20998
21027
|
const refusal = new Error(
|
|
20999
|
-
`Cannot read the server-side sync rules from ${
|
|
21028
|
+
`Cannot read the server-side sync rules from ${base3} (${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.`
|
|
21000
21029
|
);
|
|
21001
21030
|
refusal[SYNC_RULES_REFUSAL] = true;
|
|
21002
21031
|
throw refusal;
|
|
@@ -21034,17 +21063,23 @@ async function syncSessions(opts = {}) {
|
|
|
21034
21063
|
let agg = null;
|
|
21035
21064
|
const errors = [];
|
|
21036
21065
|
const skippedTargets = [];
|
|
21066
|
+
const perTarget = {};
|
|
21037
21067
|
for (const cred of targets) {
|
|
21038
21068
|
const verdict = breakerState(cred.serverUrl);
|
|
21039
21069
|
if (verdict.open) {
|
|
21040
21070
|
const notice = breakerNotice(cred.serverUrl, verdict);
|
|
21041
21071
|
if (notice) console.error(`[sync] ${notice}`);
|
|
21042
21072
|
skippedTargets.push(cred.serverUrl);
|
|
21073
|
+
perTarget[cred.serverUrl] = {
|
|
21074
|
+
ok: false,
|
|
21075
|
+
error: notice ?? `in failure cooldown for ~${Math.max(1, Math.round(verdict.retryInMs / 6e4))}m`
|
|
21076
|
+
};
|
|
21043
21077
|
continue;
|
|
21044
21078
|
}
|
|
21045
21079
|
try {
|
|
21046
21080
|
const r = await syncToTarget(cred, opts);
|
|
21047
21081
|
noteTargetSuccess(cred.serverUrl);
|
|
21082
|
+
perTarget[cred.serverUrl] = { ok: true };
|
|
21048
21083
|
agg = agg ? {
|
|
21049
21084
|
uploaded: agg.uploaded + r.uploaded,
|
|
21050
21085
|
skipped: agg.skipped + r.skipped,
|
|
@@ -21061,14 +21096,20 @@ async function syncSessions(opts = {}) {
|
|
|
21061
21096
|
} catch (e) {
|
|
21062
21097
|
const msg = e instanceof Error ? e.message : String(e);
|
|
21063
21098
|
errors.push(`${cred.serverUrl}: ${msg}`);
|
|
21099
|
+
perTarget[cred.serverUrl] = { ok: false, error: msg };
|
|
21064
21100
|
const next = noteTargetFailure(cred.serverUrl, msg);
|
|
21065
21101
|
const notice = breakerNotice(cred.serverUrl, next);
|
|
21066
21102
|
if (notice) console.error(`[sync] ${notice}`);
|
|
21067
21103
|
record({
|
|
21068
|
-
|
|
21104
|
+
// `tripped`, not `open`: an open breaker re-opens on every attempt until
|
|
21105
|
+
// a success clears it, so `open` counted elapsed time. Every failure is
|
|
21106
|
+
// still reported — as `target_failure`, carrying the streak in
|
|
21107
|
+
// `failures` — so nothing becomes invisible, it just stops being counted
|
|
21108
|
+
// as a fresh incident.
|
|
21109
|
+
kind: next.tripped ? "breaker_trip" : "target_failure",
|
|
21069
21110
|
failures: next.failures,
|
|
21070
21111
|
retryInMs: next.retryInMs,
|
|
21071
|
-
errorClass: classifyError(msg),
|
|
21112
|
+
errorClass: classifyError(msg, e),
|
|
21072
21113
|
local: isLocalHost(cred.serverUrl) ? 1 : 0
|
|
21073
21114
|
});
|
|
21074
21115
|
}
|
|
@@ -21099,27 +21140,27 @@ async function syncSessions(opts = {}) {
|
|
|
21099
21140
|
${errors.join("\n ")}`);
|
|
21100
21141
|
if (errors.length > 0) console.error(`[sync] ${errors.length} target(s) failed (others succeeded):
|
|
21101
21142
|
${errors.join("\n ")}`);
|
|
21102
|
-
return agg;
|
|
21143
|
+
return { ...agg, perTarget };
|
|
21103
21144
|
}
|
|
21104
|
-
async function postFieldBatch(
|
|
21145
|
+
async function postFieldBatch(base3, token, rows) {
|
|
21105
21146
|
const headers = { "content-type": "application/json" };
|
|
21106
21147
|
if (token) headers.authorization = `Bearer ${token}`;
|
|
21107
21148
|
const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
21108
21149
|
for (let attempt = 0; ; attempt++) {
|
|
21109
|
-
const res = await fetchWithTimeout(`${
|
|
21150
|
+
const res = await fetchWithTimeout(`${base3}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
|
|
21110
21151
|
if (res.ok) return;
|
|
21111
21152
|
const retryable = res.status === 429 || res.status >= 500;
|
|
21112
|
-
if (!retryable || attempt >= 5) throw new Error(`${
|
|
21153
|
+
if (!retryable || attempt >= 5) throw new Error(`${base3}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
21113
21154
|
const ra = Number(res.headers.get("retry-after")) || 0;
|
|
21114
21155
|
await sleep2(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
|
|
21115
21156
|
}
|
|
21116
21157
|
}
|
|
21117
21158
|
async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
21118
|
-
const
|
|
21119
|
-
const ledger = getSyncedRows(
|
|
21159
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
21160
|
+
const ledger = getSyncedRows(base3);
|
|
21120
21161
|
let pushed = 0, absent = 0, scanned = 0;
|
|
21121
21162
|
for (const field of SYNC_FIELDS) {
|
|
21122
|
-
const needFull = !!opts.force || fieldNeedsFullPass(
|
|
21163
|
+
const needFull = !!opts.force || fieldNeedsFullPass(base3, field);
|
|
21123
21164
|
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
21124
21165
|
const send = [];
|
|
21125
21166
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
@@ -21135,15 +21176,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
21135
21176
|
}
|
|
21136
21177
|
for (let i = 0; i < send.length; i += 200) {
|
|
21137
21178
|
const chunk = send.slice(i, i + 200);
|
|
21138
|
-
await postFieldBatch(
|
|
21139
|
-
markFieldCoverage(
|
|
21179
|
+
await postFieldBatch(base3, cred.token, chunk);
|
|
21180
|
+
markFieldCoverage(base3, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
|
|
21140
21181
|
pushed += chunk.length;
|
|
21141
21182
|
}
|
|
21142
21183
|
if (absentIds.length) {
|
|
21143
|
-
markFieldCoverage(
|
|
21184
|
+
markFieldCoverage(base3, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
|
|
21144
21185
|
absent += absentIds.length;
|
|
21145
21186
|
}
|
|
21146
|
-
if (needFull) markFieldFullPassDone(
|
|
21187
|
+
if (needFull) markFieldFullPassDone(base3, field);
|
|
21147
21188
|
}
|
|
21148
21189
|
return { pushed, absent, scanned };
|
|
21149
21190
|
}
|
|
@@ -21173,7 +21214,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
|
|
|
21173
21214
|
let reaped = 0;
|
|
21174
21215
|
let names;
|
|
21175
21216
|
try {
|
|
21176
|
-
names =
|
|
21217
|
+
names = readdirSync34(dir);
|
|
21177
21218
|
} catch {
|
|
21178
21219
|
return 0;
|
|
21179
21220
|
}
|
|
@@ -21260,25 +21301,25 @@ function serverIngestConcurrency(serverUrl) {
|
|
|
21260
21301
|
return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
|
|
21261
21302
|
}
|
|
21262
21303
|
async function verifyServerApi(serverUrl, minApi) {
|
|
21263
|
-
const
|
|
21264
|
-
const seen = capsOk.get(
|
|
21304
|
+
const base3 = serverUrl.replace(/\/$/, "");
|
|
21305
|
+
const seen = capsOk.get(base3);
|
|
21265
21306
|
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
21266
21307
|
const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
21267
|
-
const probe = await probeServer2(
|
|
21308
|
+
const probe = await probeServer2(base3, {
|
|
21268
21309
|
fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
|
|
21269
21310
|
});
|
|
21270
|
-
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe,
|
|
21311
|
+
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base3));
|
|
21271
21312
|
const caps = probe.raw;
|
|
21272
21313
|
if ((caps.apiVersion ?? 0) < minApi) {
|
|
21273
21314
|
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
21274
21315
|
}
|
|
21275
21316
|
const adv = caps.limits?.ingestConcurrencyPerTenant;
|
|
21276
21317
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
21277
|
-
advertisedIngestConc.set(
|
|
21318
|
+
advertisedIngestConc.set(base3, Math.floor(adv));
|
|
21278
21319
|
}
|
|
21279
|
-
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(
|
|
21280
|
-
else advertisedGzipBody.delete(
|
|
21281
|
-
capsOk.set(
|
|
21320
|
+
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base3);
|
|
21321
|
+
else advertisedGzipBody.delete(base3);
|
|
21322
|
+
capsOk.set(base3, Date.now());
|
|
21282
21323
|
return true;
|
|
21283
21324
|
}
|
|
21284
21325
|
async function syncToTarget(cred, opts = {}) {
|
|
@@ -21286,7 +21327,7 @@ async function syncToTarget(cred, opts = {}) {
|
|
|
21286
21327
|
}
|
|
21287
21328
|
async function syncToTargetInScope(cred, opts = {}) {
|
|
21288
21329
|
const risk = transportRisk(cred.serverUrl);
|
|
21289
|
-
if (risk) throw
|
|
21330
|
+
if (risk) throw classedError("insecure_transport", risk);
|
|
21290
21331
|
const sync = loadSettings().sync;
|
|
21291
21332
|
const serverCfg = await fetchTenantSyncConfig(cred);
|
|
21292
21333
|
const excludeTools = /* @__PURE__ */ new Set([...sync?.excludeTools ?? [], ...serverCfg.excludeTools]);
|
|
@@ -21343,7 +21384,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21343
21384
|
const ac = new AbortController();
|
|
21344
21385
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21345
21386
|
try {
|
|
21346
|
-
const res = await fetch(`${
|
|
21387
|
+
const res = await fetch(`${base3}/api/sync`, {
|
|
21347
21388
|
method: "POST",
|
|
21348
21389
|
// No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
|
|
21349
21390
|
// accepts it as the single 'default' tenant.
|
|
@@ -21358,26 +21399,26 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21358
21399
|
if (res.ok) {
|
|
21359
21400
|
const body2 = await res.json().catch(() => ({}));
|
|
21360
21401
|
if (typeof body2.telemetry === "boolean") {
|
|
21361
|
-
setTelemetryEligible(
|
|
21402
|
+
setTelemetryEligible(base3, body2.telemetry);
|
|
21362
21403
|
try {
|
|
21363
21404
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
21364
21405
|
updateCollectorHealth({
|
|
21365
|
-
telemetryEligible: { ...prior, [
|
|
21406
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
|
|
21366
21407
|
});
|
|
21367
21408
|
} catch {
|
|
21368
21409
|
}
|
|
21369
21410
|
}
|
|
21370
21411
|
const adv = body2.limits?.ingestConcurrencyPerTenant;
|
|
21371
21412
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
21372
|
-
setServerIngestConcurrency(
|
|
21413
|
+
setServerIngestConcurrency(base3, Math.floor(adv));
|
|
21373
21414
|
}
|
|
21374
21415
|
if (body2.cli && body2.cli.version) {
|
|
21375
21416
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
21376
21417
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
21377
|
-
const plan = planAutoUpdate2(
|
|
21418
|
+
const plan = planAutoUpdate2(base3, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
21378
21419
|
sweepStaleStaging2();
|
|
21379
21420
|
if (plan.update) {
|
|
21380
|
-
void runAutoUpdate2(
|
|
21421
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
21381
21422
|
});
|
|
21382
21423
|
}
|
|
21383
21424
|
}
|
|
@@ -21386,7 +21427,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21386
21427
|
const retryable = res.status === 429 || res.status >= 500;
|
|
21387
21428
|
const text = await res.text().catch(() => "");
|
|
21388
21429
|
if (res.status === 401 || res.status === 403) {
|
|
21389
|
-
throw
|
|
21430
|
+
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base3}`);
|
|
21390
21431
|
}
|
|
21391
21432
|
if (res.status === 402) {
|
|
21392
21433
|
let detail = text;
|
|
@@ -21400,17 +21441,17 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21400
21441
|
${body2.upgradeUrl}`;
|
|
21401
21442
|
} catch {
|
|
21402
21443
|
}
|
|
21403
|
-
throw
|
|
21444
|
+
throw classedError("payment_required", `sync paused by the server: ${detail}`);
|
|
21404
21445
|
}
|
|
21405
21446
|
if (!retryable) throw new Error(`sync failed: HTTP ${res.status} ${text}`);
|
|
21406
21447
|
if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
|
|
21407
21448
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
21408
21449
|
const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
|
|
21409
|
-
console.error(`[sync] HTTP ${res.status} from ${
|
|
21450
|
+
console.error(`[sync] HTTP ${res.status} from ${base3} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
|
|
21410
21451
|
await sleep2(waitMs);
|
|
21411
21452
|
continue;
|
|
21412
21453
|
} catch (err) {
|
|
21413
|
-
const fatal = err instanceof Error && /HTTP 4\d\d|sync failed after/.test(err.message);
|
|
21454
|
+
const fatal = isStandingFailure(err) || err instanceof Error && /HTTP 4\d\d|sync failed after/.test(err.message);
|
|
21414
21455
|
if (fatal || attempt >= RETRY_DELAYS_MS.length) throw err;
|
|
21415
21456
|
console.error(`[sync] upload attempt ${attempt + 1} failed (${err instanceof Error ? err.message : err}) \u2014 retrying in ${RETRY_DELAYS_MS[attempt] / 1e3}s`);
|
|
21416
21457
|
await sleep2(RETRY_DELAYS_MS[attempt]);
|
|
@@ -21473,11 +21514,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21473
21514
|
}
|
|
21474
21515
|
};
|
|
21475
21516
|
};
|
|
21476
|
-
const
|
|
21477
|
-
const ledger = opts.useLedger ? getSyncedRows(
|
|
21517
|
+
const base3 = cred.serverUrl.replace(/\/$/, "");
|
|
21518
|
+
const ledger = opts.useLedger ? getSyncedRows(base3) : null;
|
|
21478
21519
|
const convBatch = makeBatcher("conversations", 25, false, (rows) => {
|
|
21479
21520
|
try {
|
|
21480
|
-
markSynced(
|
|
21521
|
+
markSynced(base3, rows.map((r) => {
|
|
21481
21522
|
const off = typeof r.from_offset === "number" ? r.from_offset : 0;
|
|
21482
21523
|
const hash = shippedHash.get(r.session_id);
|
|
21483
21524
|
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 };
|
|
@@ -21492,7 +21533,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21492
21533
|
const ac = new AbortController();
|
|
21493
21534
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21494
21535
|
try {
|
|
21495
|
-
const res = await fetch(`${
|
|
21536
|
+
const res = await fetch(`${base3}/api/sync`, {
|
|
21496
21537
|
method: "POST",
|
|
21497
21538
|
headers,
|
|
21498
21539
|
body: JSON.stringify({ conversations: convs }),
|
|
@@ -21503,10 +21544,10 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21503
21544
|
if (body.cli && body.cli.version) {
|
|
21504
21545
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
21505
21546
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
21506
|
-
const plan = planAutoUpdate2(
|
|
21547
|
+
const plan = planAutoUpdate2(base3, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
21507
21548
|
sweepStaleStaging2();
|
|
21508
21549
|
if (plan.update) {
|
|
21509
|
-
void runAutoUpdate2(
|
|
21550
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
21510
21551
|
});
|
|
21511
21552
|
}
|
|
21512
21553
|
}
|
|
@@ -21514,7 +21555,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21514
21555
|
const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
|
|
21515
21556
|
if (acked.length > 0) {
|
|
21516
21557
|
try {
|
|
21517
|
-
markSynced(
|
|
21558
|
+
markSynced(base3, acked.map((c) => ({
|
|
21518
21559
|
id: c.session_id,
|
|
21519
21560
|
mtime: c.mtime,
|
|
21520
21561
|
offset: c.from_offset,
|
|
@@ -21584,7 +21625,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21584
21625
|
const m = process.memoryUsage();
|
|
21585
21626
|
console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
|
|
21586
21627
|
} : null;
|
|
21587
|
-
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${
|
|
21628
|
+
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base3}`);
|
|
21588
21629
|
if (upload.sessionMeta) {
|
|
21589
21630
|
try {
|
|
21590
21631
|
await reconcileFieldsForTarget(
|
|
@@ -21599,7 +21640,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21599
21640
|
{ convRefs: slice }
|
|
21600
21641
|
);
|
|
21601
21642
|
} catch (e) {
|
|
21602
|
-
console.error(`[sync] field reconcile (${
|
|
21643
|
+
console.error(`[sync] field reconcile (${base3}): ${e instanceof Error ? e.message : e}`);
|
|
21603
21644
|
}
|
|
21604
21645
|
}
|
|
21605
21646
|
trace?.("field reconcile done");
|
|
@@ -21674,7 +21715,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21674
21715
|
continue;
|
|
21675
21716
|
} else {
|
|
21676
21717
|
try {
|
|
21677
|
-
markSynced(
|
|
21718
|
+
markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21678
21719
|
} catch {
|
|
21679
21720
|
}
|
|
21680
21721
|
skipped++;
|
|
@@ -21697,7 +21738,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21697
21738
|
const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
|
|
21698
21739
|
const priorCursor = ackRow?.s ?? 0;
|
|
21699
21740
|
const safeToAck = off > 0 && off <= priorCursor;
|
|
21700
|
-
markSynced(
|
|
21741
|
+
markSynced(base3, [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 }]);
|
|
21701
21742
|
} catch {
|
|
21702
21743
|
}
|
|
21703
21744
|
}
|
|
@@ -21707,7 +21748,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21707
21748
|
if (!built) {
|
|
21708
21749
|
if (ledger) {
|
|
21709
21750
|
try {
|
|
21710
|
-
markSynced(
|
|
21751
|
+
markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21711
21752
|
} catch {
|
|
21712
21753
|
}
|
|
21713
21754
|
}
|
|
@@ -21763,7 +21804,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21763
21804
|
walked++;
|
|
21764
21805
|
if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
|
|
21765
21806
|
}
|
|
21766
|
-
const itemVersions = loadItemVersions(
|
|
21807
|
+
const itemVersions = loadItemVersions(base3);
|
|
21767
21808
|
const seenTools = /* @__PURE__ */ new Set();
|
|
21768
21809
|
const seenItemKeys = /* @__PURE__ */ new Map();
|
|
21769
21810
|
const registry = buildSourceRegistry();
|
|
@@ -21849,7 +21890,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21849
21890
|
await appendFlush();
|
|
21850
21891
|
for (const id of appendResults.fullResyncNeeded) {
|
|
21851
21892
|
try {
|
|
21852
|
-
markFullResync(
|
|
21893
|
+
markFullResync(base3, id);
|
|
21853
21894
|
} catch {
|
|
21854
21895
|
}
|
|
21855
21896
|
}
|
|
@@ -21866,7 +21907,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21866
21907
|
const rec = {};
|
|
21867
21908
|
for (const t of seenTools) rec[t] = extractorVersionForTool(t);
|
|
21868
21909
|
for (const [k, v] of seenItemKeys) rec[k] = v;
|
|
21869
|
-
saveItemVersions(
|
|
21910
|
+
saveItemVersions(base3, rec);
|
|
21870
21911
|
} catch {
|
|
21871
21912
|
}
|
|
21872
21913
|
}
|
|
@@ -21879,9 +21920,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21879
21920
|
}
|
|
21880
21921
|
if (tombstones.length > 0) {
|
|
21881
21922
|
await post({ tombstones });
|
|
21882
|
-
const data = getLedgerData(
|
|
21923
|
+
const data = getLedgerData(base3);
|
|
21883
21924
|
for (const t of tombstones) delete data[t.session_id];
|
|
21884
|
-
persistLedgerData(
|
|
21925
|
+
persistLedgerData(base3, data);
|
|
21885
21926
|
}
|
|
21886
21927
|
}
|
|
21887
21928
|
if (opts.prune) await post({ prune_empty_sessions: true });
|
|
@@ -21949,7 +21990,12 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21949
21990
|
const containerBytes = built ? built.files.reduce((n, f) => n + Buffer.byteLength(f.text), 0) : 0;
|
|
21950
21991
|
if (containerBytes > FULL_BUILD_MAX_BYTES) {
|
|
21951
21992
|
console.error(`[sync] ${ref.prefixedId} is ${(containerBytes / 1048576).toFixed(0)}MB (over the ${(FULL_BUILD_MAX_BYTES / 1048576).toFixed(0)}MB ceiling) \u2014 shipping without the raw archive and derived data to keep the walk in memory`);
|
|
21952
|
-
record({
|
|
21993
|
+
record({
|
|
21994
|
+
kind: "oversized_session",
|
|
21995
|
+
mb: Math.round(containerBytes / 1048576),
|
|
21996
|
+
tool: ref.toolId,
|
|
21997
|
+
dedupeKey: stableMark(ref.prefixedId)
|
|
21998
|
+
});
|
|
21953
21999
|
includeRaw = false;
|
|
21954
22000
|
includeMeta = false;
|
|
21955
22001
|
}
|
|
@@ -22260,7 +22306,7 @@ async function syncIncremental(opts = {}) {
|
|
|
22260
22306
|
lock.release();
|
|
22261
22307
|
}
|
|
22262
22308
|
}
|
|
22263
|
-
var ownVersion, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
22309
|
+
var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
22264
22310
|
var init_sync_client = __esm({
|
|
22265
22311
|
"src/sync-client.ts"() {
|
|
22266
22312
|
"use strict";
|
|
@@ -22306,10 +22352,16 @@ var init_sync_client = __esm({
|
|
|
22306
22352
|
ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22307
22353
|
} catch {
|
|
22308
22354
|
try {
|
|
22309
|
-
if (true) ownVersion = "0.5.
|
|
22355
|
+
if (true) ownVersion = "0.5.32";
|
|
22310
22356
|
} catch {
|
|
22311
22357
|
}
|
|
22312
22358
|
}
|
|
22359
|
+
ERROR_CLASS = "__chatRecallErrorClass";
|
|
22360
|
+
STANDING_FAILURE = /* @__PURE__ */ new Set([
|
|
22361
|
+
"auth",
|
|
22362
|
+
"payment_required",
|
|
22363
|
+
"insecure_transport"
|
|
22364
|
+
]);
|
|
22313
22365
|
walkProgressForUpload = null;
|
|
22314
22366
|
lastServerPackSpec = null;
|
|
22315
22367
|
credPath = () => join44(getDataDir(), "credentials.json");
|
|
@@ -22370,9 +22422,9 @@ async function refreshUpdateCheck(force = false) {
|
|
|
22370
22422
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
22371
22423
|
for (const cred of loadAllCredentials2()) {
|
|
22372
22424
|
if (!cred.serverUrl) continue;
|
|
22373
|
-
const
|
|
22425
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
22374
22426
|
try {
|
|
22375
|
-
const res = await fetchWithTimeout(`${
|
|
22427
|
+
const res = await fetchWithTimeout(`${base3}/api/capabilities`, {
|
|
22376
22428
|
headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
|
|
22377
22429
|
}, 5e3);
|
|
22378
22430
|
if (!res.ok) continue;
|
|
@@ -22967,7 +23019,7 @@ __export(install_skills_exports, {
|
|
|
22967
23019
|
skillsSourceDir: () => skillsSourceDir,
|
|
22968
23020
|
uninstallSkills: () => uninstallSkills
|
|
22969
23021
|
});
|
|
22970
|
-
import { readdirSync as
|
|
23022
|
+
import { readdirSync as readdirSync35, existsSync as existsSync46, mkdirSync as mkdirSync12, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync41, statSync as statSync42, realpathSync as realpathSync4 } from "fs";
|
|
22971
23023
|
import { createHash as createHash15 } from "crypto";
|
|
22972
23024
|
import { join as join49, basename as basename23 } from "path";
|
|
22973
23025
|
function skillsSourceDir() {
|
|
@@ -22993,7 +23045,7 @@ function skillsFingerprint() {
|
|
|
22993
23045
|
}
|
|
22994
23046
|
function filesUnder(dir, prefix = "") {
|
|
22995
23047
|
const out = [];
|
|
22996
|
-
for (const e of
|
|
23048
|
+
for (const e of readdirSync35(dir, { withFileTypes: true })) {
|
|
22997
23049
|
if (e.name === MARKER) continue;
|
|
22998
23050
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
22999
23051
|
if (e.isDirectory()) out.push(...filesUnder(join49(dir, e.name), rel));
|
|
@@ -23007,7 +23059,7 @@ function skillStamp() {
|
|
|
23007
23059
|
function bundledSkillNames() {
|
|
23008
23060
|
const src = skillsSourceDir();
|
|
23009
23061
|
if (!existsSync46(src)) return [];
|
|
23010
|
-
return
|
|
23062
|
+
return readdirSync35(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync46(join49(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
|
|
23011
23063
|
}
|
|
23012
23064
|
function realPathOrSelf(p) {
|
|
23013
23065
|
try {
|
|
@@ -23099,7 +23151,7 @@ function uninstallSkills() {
|
|
|
23099
23151
|
perTarget.push({ id: t.id, label: t.label, removed });
|
|
23100
23152
|
continue;
|
|
23101
23153
|
}
|
|
23102
|
-
for (const entry of
|
|
23154
|
+
for (const entry of readdirSync35(t.dir, { withFileTypes: true })) {
|
|
23103
23155
|
if (!entry.isDirectory()) continue;
|
|
23104
23156
|
const dir = join49(t.dir, entry.name);
|
|
23105
23157
|
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
@@ -23802,9 +23854,9 @@ function portableCommand(cmd) {
|
|
|
23802
23854
|
}
|
|
23803
23855
|
if (isExecutableFile(cmd))
|
|
23804
23856
|
return { command: cmd, rewritten: false };
|
|
23805
|
-
const
|
|
23806
|
-
if (onPath(
|
|
23807
|
-
return { command:
|
|
23857
|
+
const base3 = basename26(cmd);
|
|
23858
|
+
if (onPath(base3))
|
|
23859
|
+
return { command: base3, rewritten: true };
|
|
23808
23860
|
return { missing: cmd };
|
|
23809
23861
|
}
|
|
23810
23862
|
function entryFromSpec(spec) {
|
|
@@ -24870,17 +24922,17 @@ async function collectCode(opts) {
|
|
|
24870
24922
|
return r;
|
|
24871
24923
|
};
|
|
24872
24924
|
log6(`indexing ${ws} + analyses \u2026`);
|
|
24873
|
-
const
|
|
24925
|
+
const base3 = await runMcp(bin, ws, [
|
|
24874
24926
|
call(1, "index_workspace", { path: ws }),
|
|
24875
24927
|
call(2, "status"),
|
|
24876
24928
|
call(3, "get_tree"),
|
|
24877
24929
|
...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
|
|
24878
24930
|
]);
|
|
24879
|
-
const st = parseJson(
|
|
24880
|
-
const tree = parseJson(
|
|
24931
|
+
const st = parseJson(base3, 2, {});
|
|
24932
|
+
const tree = parseJson(base3, 3, []);
|
|
24881
24933
|
const A = {};
|
|
24882
24934
|
ANALYSES.forEach((a, i) => {
|
|
24883
|
-
A[a] = parseJson(
|
|
24935
|
+
A[a] = parseJson(base3, 10 + i, {});
|
|
24884
24936
|
});
|
|
24885
24937
|
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;
|
|
24886
24938
|
if (tree.length === 0) {
|
|
@@ -25780,14 +25832,14 @@ function writeLedger(l) {
|
|
|
25780
25832
|
} catch {
|
|
25781
25833
|
}
|
|
25782
25834
|
}
|
|
25783
|
-
async function pushProjectTaskStatuses(
|
|
25835
|
+
async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
|
|
25784
25836
|
const out = { files: 0, pushedTasks: 0 };
|
|
25785
25837
|
const ledger = readLedger();
|
|
25786
25838
|
let ledgerDirty = false;
|
|
25787
25839
|
for (const fk of FILE_KINDS) {
|
|
25788
25840
|
let projects;
|
|
25789
25841
|
try {
|
|
25790
|
-
const res = await fetchWithTimeout(`${
|
|
25842
|
+
const res = await fetchWithTimeout(`${base3}${fk.trackedPath}`, { headers: authHeaders });
|
|
25791
25843
|
if (!res.ok) continue;
|
|
25792
25844
|
projects = (await res.json()).projects || [];
|
|
25793
25845
|
} catch {
|
|
@@ -25815,7 +25867,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
25815
25867
|
continue;
|
|
25816
25868
|
}
|
|
25817
25869
|
try {
|
|
25818
|
-
const res = await fetchWithTimeout(`${
|
|
25870
|
+
const res = await fetchWithTimeout(`${base3}${fk.statusPath}`, {
|
|
25819
25871
|
method: "POST",
|
|
25820
25872
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
25821
25873
|
body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
|
|
@@ -25921,16 +25973,16 @@ ${block}`);
|
|
|
25921
25973
|
return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
|
|
25922
25974
|
}
|
|
25923
25975
|
}
|
|
25924
|
-
async function runPull(
|
|
25976
|
+
async function runPull(base3, opts) {
|
|
25925
25977
|
const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
|
|
25926
25978
|
const { hostname: hostname3 } = await import("node:os");
|
|
25927
|
-
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") ===
|
|
25979
|
+
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base3.replace(/\/+$/, ""));
|
|
25928
25980
|
const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
|
|
25929
25981
|
const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
|
|
25930
25982
|
const rows = [];
|
|
25931
25983
|
for (const type of wanted) {
|
|
25932
25984
|
try {
|
|
25933
|
-
const res = await fetchWithTimeout(`${
|
|
25985
|
+
const res = await fetchWithTimeout(`${base3}/api/toolkit/browse/${type}?limit=1000`, { headers });
|
|
25934
25986
|
if (!res.ok) continue;
|
|
25935
25987
|
const body = await res.json();
|
|
25936
25988
|
for (const it of body.items || []) rows.push(it);
|
|
@@ -25999,20 +26051,20 @@ async function runIntent(intent, ctx) {
|
|
|
25999
26051
|
async function drainSyncIntents(opts = {}) {
|
|
26000
26052
|
const out = { processed: 0, done: 0, errored: 0 };
|
|
26001
26053
|
for (const cred of loadAllCredentials()) {
|
|
26002
|
-
const
|
|
26054
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
26003
26055
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
26004
26056
|
let pending;
|
|
26005
26057
|
try {
|
|
26006
|
-
const res = await fetchWithTimeout(`${
|
|
26058
|
+
const res = await fetchWithTimeout(`${base3}/api/sync-intents/pending`, { headers: authHeaders });
|
|
26007
26059
|
if (!res.ok) continue;
|
|
26008
26060
|
const data = await res.json();
|
|
26009
26061
|
pending = data.intents || [];
|
|
26010
26062
|
if (data.cli && data.cli.version) {
|
|
26011
26063
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
26012
|
-
const plan = planAutoUpdate2(
|
|
26064
|
+
const plan = planAutoUpdate2(base3, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
26013
26065
|
sweepStaleStaging2();
|
|
26014
26066
|
if (plan.update) {
|
|
26015
|
-
void runAutoUpdate2(
|
|
26067
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion2).catch(() => {
|
|
26016
26068
|
});
|
|
26017
26069
|
}
|
|
26018
26070
|
}
|
|
@@ -26020,7 +26072,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
26020
26072
|
continue;
|
|
26021
26073
|
}
|
|
26022
26074
|
for (const intent of pending) {
|
|
26023
|
-
const { status, result } = await runIntent(intent, { base:
|
|
26075
|
+
const { status, result } = await runIntent(intent, { base: base3 });
|
|
26024
26076
|
out.processed++;
|
|
26025
26077
|
if (status === "done") out.done++;
|
|
26026
26078
|
else out.errored++;
|
|
@@ -26029,7 +26081,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
26029
26081
|
console.error(`[sync-intent] ${label}: ${status}`);
|
|
26030
26082
|
}
|
|
26031
26083
|
try {
|
|
26032
|
-
await fetchWithTimeout(`${
|
|
26084
|
+
await fetchWithTimeout(`${base3}/api/sync-intents/${intent.id}/ack`, {
|
|
26033
26085
|
method: "POST",
|
|
26034
26086
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
26035
26087
|
body: JSON.stringify({ status, result })
|
|
@@ -26038,7 +26090,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
26038
26090
|
}
|
|
26039
26091
|
}
|
|
26040
26092
|
try {
|
|
26041
|
-
await pushProjectTaskStatuses(
|
|
26093
|
+
await pushProjectTaskStatuses(base3, authHeaders, { verbose: opts.verbose });
|
|
26042
26094
|
} catch {
|
|
26043
26095
|
}
|
|
26044
26096
|
}
|
|
@@ -26064,7 +26116,7 @@ var init_intent_drain = __esm({
|
|
|
26064
26116
|
ownVersion2 = JSON.parse(readFileSync46(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
26065
26117
|
} catch {
|
|
26066
26118
|
try {
|
|
26067
|
-
if (true) ownVersion2 = "0.5.
|
|
26119
|
+
if (true) ownVersion2 = "0.5.32";
|
|
26068
26120
|
} catch {
|
|
26069
26121
|
}
|
|
26070
26122
|
}
|
|
@@ -26486,7 +26538,7 @@ var init_vault_crypto = __esm({
|
|
|
26486
26538
|
});
|
|
26487
26539
|
|
|
26488
26540
|
// ../engine/dist/core/vault-source.js
|
|
26489
|
-
import { existsSync as existsSync53, readdirSync as
|
|
26541
|
+
import { existsSync as existsSync53, readdirSync as readdirSync36, statSync as statSync46 } from "fs";
|
|
26490
26542
|
import { extname, join as join57 } from "path";
|
|
26491
26543
|
function* walkVaultSources() {
|
|
26492
26544
|
const t = loadSettings().team.vault;
|
|
@@ -26518,18 +26570,18 @@ function* walkClaude() {
|
|
|
26518
26570
|
return;
|
|
26519
26571
|
let projectDirs = [];
|
|
26520
26572
|
try {
|
|
26521
|
-
projectDirs =
|
|
26573
|
+
projectDirs = readdirSync36(root);
|
|
26522
26574
|
} catch {
|
|
26523
26575
|
return;
|
|
26524
26576
|
}
|
|
26525
26577
|
for (const proj of projectDirs) {
|
|
26526
26578
|
if (proj.startsWith("."))
|
|
26527
26579
|
continue;
|
|
26528
|
-
const projectPath =
|
|
26580
|
+
const projectPath = resolveProjectDirName(proj);
|
|
26529
26581
|
const projDir = join57(root, proj);
|
|
26530
26582
|
let entries = [];
|
|
26531
26583
|
try {
|
|
26532
|
-
entries =
|
|
26584
|
+
entries = readdirSync36(projDir);
|
|
26533
26585
|
} catch {
|
|
26534
26586
|
continue;
|
|
26535
26587
|
}
|
|
@@ -26551,7 +26603,7 @@ function* walkGemini() {
|
|
|
26551
26603
|
return;
|
|
26552
26604
|
let hashDirs = [];
|
|
26553
26605
|
try {
|
|
26554
|
-
hashDirs =
|
|
26606
|
+
hashDirs = readdirSync36(tmp);
|
|
26555
26607
|
} catch {
|
|
26556
26608
|
return;
|
|
26557
26609
|
}
|
|
@@ -26561,7 +26613,7 @@ function* walkGemini() {
|
|
|
26561
26613
|
continue;
|
|
26562
26614
|
let entries = [];
|
|
26563
26615
|
try {
|
|
26564
|
-
entries =
|
|
26616
|
+
entries = readdirSync36(chatsDir);
|
|
26565
26617
|
} catch {
|
|
26566
26618
|
continue;
|
|
26567
26619
|
}
|
|
@@ -26573,8 +26625,8 @@ function* walkGemini() {
|
|
|
26573
26625
|
const s = safeStat(path);
|
|
26574
26626
|
if (!s)
|
|
26575
26627
|
continue;
|
|
26576
|
-
const
|
|
26577
|
-
yield { sessionId: `gemini_${
|
|
26628
|
+
const base3 = f.replace(/^session-/, "").replace(/\.(jsonl?)$/, "");
|
|
26629
|
+
yield { sessionId: `gemini_${base3}`, tool: "gemini", path, mtimeMs: s.mtimeMs, sizeBytes: s.size };
|
|
26578
26630
|
}
|
|
26579
26631
|
}
|
|
26580
26632
|
}
|
|
@@ -26607,7 +26659,7 @@ function* walkCodex() {
|
|
|
26607
26659
|
const dir = stack.pop();
|
|
26608
26660
|
let entries = [];
|
|
26609
26661
|
try {
|
|
26610
|
-
entries =
|
|
26662
|
+
entries = readdirSync36(dir, { withFileTypes: true });
|
|
26611
26663
|
} catch {
|
|
26612
26664
|
continue;
|
|
26613
26665
|
}
|
|
@@ -26622,8 +26674,8 @@ function* walkCodex() {
|
|
|
26622
26674
|
const s = safeStat(path);
|
|
26623
26675
|
if (!s)
|
|
26624
26676
|
continue;
|
|
26625
|
-
const
|
|
26626
|
-
yield { sessionId: `codex_${
|
|
26677
|
+
const base3 = e.name.replace(/\.jsonl$/, "");
|
|
26678
|
+
yield { sessionId: `codex_${base3}`, tool: "codex", path, mtimeMs: s.mtimeMs, sizeBytes: s.size };
|
|
26627
26679
|
}
|
|
26628
26680
|
}
|
|
26629
26681
|
}
|
|
@@ -26633,7 +26685,7 @@ function* walkAgy() {
|
|
|
26633
26685
|
return;
|
|
26634
26686
|
let sessionDirs = [];
|
|
26635
26687
|
try {
|
|
26636
|
-
sessionDirs =
|
|
26688
|
+
sessionDirs = readdirSync36(brainDir);
|
|
26637
26689
|
} catch {
|
|
26638
26690
|
return;
|
|
26639
26691
|
}
|
|
@@ -26766,11 +26818,11 @@ function vaultEnable(passphrase, opts = {}) {
|
|
|
26766
26818
|
}
|
|
26767
26819
|
async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
|
|
26768
26820
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
26769
|
-
const
|
|
26821
|
+
const base3 = remote.baseUrl.replace(/\/+$/, "");
|
|
26770
26822
|
const headers = { authorization: `Bearer ${remote.token}`, "content-type": "application/json" };
|
|
26771
26823
|
let published = { saltHex: null, keyId: null };
|
|
26772
26824
|
try {
|
|
26773
|
-
const r = await doFetch(`${
|
|
26825
|
+
const r = await doFetch(`${base3}/api/vault/salt`, { headers });
|
|
26774
26826
|
if (r.ok)
|
|
26775
26827
|
published = await r.json();
|
|
26776
26828
|
} catch {
|
|
@@ -26784,7 +26836,7 @@ async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
|
|
|
26784
26836
|
}
|
|
26785
26837
|
const result = vaultEnable(passphrase);
|
|
26786
26838
|
try {
|
|
26787
|
-
const r = await doFetch(`${
|
|
26839
|
+
const r = await doFetch(`${base3}/api/vault/salt`, {
|
|
26788
26840
|
method: "POST",
|
|
26789
26841
|
headers,
|
|
26790
26842
|
body: JSON.stringify({ saltHex: result.saltHex, keyId: result.keyId })
|
|
@@ -26877,8 +26929,8 @@ async function vaultSync(passphrase) {
|
|
|
26877
26929
|
return report;
|
|
26878
26930
|
}
|
|
26879
26931
|
function importedPathFor(tool, sessionId) {
|
|
26880
|
-
const
|
|
26881
|
-
return join58(IMPORTED_ROOT(), tool, `${
|
|
26932
|
+
const base3 = sessionId.replace(/^gemini_/, "").replace(/^codex_/, "").replace(/^agy_/, "").replace(/^cursor_/, "").replace(/^opencode_/, "");
|
|
26933
|
+
return join58(IMPORTED_ROOT(), tool, `${base3}.jsonl`);
|
|
26882
26934
|
}
|
|
26883
26935
|
async function vaultRestore(passphrase, opts = {}) {
|
|
26884
26936
|
const ctx = context2();
|
|
@@ -27421,8 +27473,8 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
27421
27473
|
throw new Error("device-auth timed out \u2014 the code expired before approval.");
|
|
27422
27474
|
}
|
|
27423
27475
|
async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
27424
|
-
const
|
|
27425
|
-
const startRes = await fetch(`${
|
|
27476
|
+
const base3 = serverUrl.replace(/\/+$/, "");
|
|
27477
|
+
const startRes = await fetch(`${base3}/api/auth/device/code`, {
|
|
27426
27478
|
method: "POST",
|
|
27427
27479
|
headers: { "content-type": "application/json" },
|
|
27428
27480
|
body: JSON.stringify({ client_id: BETTER_AUTH_CLI_CLIENT_ID })
|
|
@@ -27430,7 +27482,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27430
27482
|
if (!startRes.ok) {
|
|
27431
27483
|
throw new Error(`device-auth init failed: HTTP ${startRes.status} ${await startRes.text().catch(() => "")}`);
|
|
27432
27484
|
}
|
|
27433
|
-
const start = await readDeviceCode(startRes,
|
|
27485
|
+
const start = await readDeviceCode(startRes, base3);
|
|
27434
27486
|
onPrompt({
|
|
27435
27487
|
url: start.verification_uri_complete || start.verification_uri,
|
|
27436
27488
|
userCode: start.user_code,
|
|
@@ -27440,7 +27492,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27440
27492
|
let interval = (start.interval ?? 5) * 1e3;
|
|
27441
27493
|
while (Date.now() < deadline) {
|
|
27442
27494
|
await sleep(interval);
|
|
27443
|
-
const res = await fetch(`${
|
|
27495
|
+
const res = await fetch(`${base3}/api/auth/device/token`, {
|
|
27444
27496
|
method: "POST",
|
|
27445
27497
|
headers: { "content-type": "application/json" },
|
|
27446
27498
|
body: JSON.stringify({
|
|
@@ -27525,6 +27577,140 @@ var init_install_report = __esm({
|
|
|
27525
27577
|
}
|
|
27526
27578
|
});
|
|
27527
27579
|
|
|
27580
|
+
// src/bulk-delete.ts
|
|
27581
|
+
var bulk_delete_exports = {};
|
|
27582
|
+
__export(bulk_delete_exports, {
|
|
27583
|
+
BATCH: () => BATCH,
|
|
27584
|
+
bulkDelete: () => bulkDelete,
|
|
27585
|
+
listTombstones: () => listTombstones,
|
|
27586
|
+
needsConfirmation: () => needsConfirmation,
|
|
27587
|
+
restoreSessions: () => restoreSessions,
|
|
27588
|
+
selectSessions: () => selectSessions
|
|
27589
|
+
});
|
|
27590
|
+
async function selectSessions(target, opts, fetchImpl = fetch) {
|
|
27591
|
+
const found = [];
|
|
27592
|
+
const want = opts.match?.trim();
|
|
27593
|
+
for (let offset = 0; ; offset += PAGE) {
|
|
27594
|
+
const qs = new URLSearchParams({ limit: String(PAGE), offset: String(offset) });
|
|
27595
|
+
if (opts.project) qs.set("project", opts.project);
|
|
27596
|
+
if (opts.tool) qs.set("tool", opts.tool);
|
|
27597
|
+
const res = await fetchImpl(`${base2(target.serverUrl)}/api/conversations/recent?${qs}`, {
|
|
27598
|
+
headers: { authorization: `Bearer ${target.token}` }
|
|
27599
|
+
});
|
|
27600
|
+
if (!res.ok) throw new Error(`list failed: HTTP ${res.status}`);
|
|
27601
|
+
const body = await res.json();
|
|
27602
|
+
const page = body.sessions ?? [];
|
|
27603
|
+
if (page.length === 0) break;
|
|
27604
|
+
for (const row of page) {
|
|
27605
|
+
if (!row.sessionId) continue;
|
|
27606
|
+
if (want !== void 0 && (row.firstPrompt ?? "").trim() !== want) continue;
|
|
27607
|
+
found.push(row);
|
|
27608
|
+
if (opts.limit && found.length >= opts.limit) return found;
|
|
27609
|
+
}
|
|
27610
|
+
if (page.length < PAGE) break;
|
|
27611
|
+
}
|
|
27612
|
+
return found;
|
|
27613
|
+
}
|
|
27614
|
+
async function bulkDelete(ids, opts = {}) {
|
|
27615
|
+
const unique = [...new Set(ids.filter(Boolean))];
|
|
27616
|
+
const targets = opts.targets ?? loadAllCredentials();
|
|
27617
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
27618
|
+
const out = { requested: unique.length, perTarget: {}, deleted: 0 };
|
|
27619
|
+
if (unique.length === 0 || targets.length === 0) return out;
|
|
27620
|
+
const succeeded = /* @__PURE__ */ new Set();
|
|
27621
|
+
for (const t of targets) {
|
|
27622
|
+
let deleted = 0;
|
|
27623
|
+
try {
|
|
27624
|
+
for (let i = 0; i < unique.length; i += BATCH) {
|
|
27625
|
+
const slice = unique.slice(i, i + BATCH);
|
|
27626
|
+
const res = await fetchImpl(`${base2(t.serverUrl)}/api/sync`, {
|
|
27627
|
+
method: "POST",
|
|
27628
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
|
|
27629
|
+
body: JSON.stringify({
|
|
27630
|
+
tombstones: slice.map((session_id) => ({ session_id, deleted_at: Date.now() }))
|
|
27631
|
+
})
|
|
27632
|
+
});
|
|
27633
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
27634
|
+
deleted += slice.length;
|
|
27635
|
+
for (const id of slice) succeeded.add(id);
|
|
27636
|
+
opts.onProgress?.(deleted, unique.length);
|
|
27637
|
+
}
|
|
27638
|
+
out.perTarget[t.serverUrl] = { deleted };
|
|
27639
|
+
} catch (e) {
|
|
27640
|
+
out.perTarget[t.serverUrl] = { deleted, error: e instanceof Error ? e.message : "failed" };
|
|
27641
|
+
}
|
|
27642
|
+
}
|
|
27643
|
+
out.deleted = succeeded.size;
|
|
27644
|
+
for (const t of targets) {
|
|
27645
|
+
if (!out.perTarget[t.serverUrl] || out.perTarget[t.serverUrl].error) continue;
|
|
27646
|
+
try {
|
|
27647
|
+
const data = getLedgerData(t.serverUrl);
|
|
27648
|
+
let touched = false;
|
|
27649
|
+
for (const id of succeeded) {
|
|
27650
|
+
if (id in data) {
|
|
27651
|
+
delete data[id];
|
|
27652
|
+
touched = true;
|
|
27653
|
+
}
|
|
27654
|
+
}
|
|
27655
|
+
if (touched) persistLedgerData(t.serverUrl, data);
|
|
27656
|
+
} catch {
|
|
27657
|
+
}
|
|
27658
|
+
}
|
|
27659
|
+
return out;
|
|
27660
|
+
}
|
|
27661
|
+
async function listTombstones(target, limit = 500, fetchImpl = fetch) {
|
|
27662
|
+
const res = await fetchImpl(`${base2(target.serverUrl)}/api/data/tombstones?limit=${limit}`, {
|
|
27663
|
+
headers: { authorization: `Bearer ${target.token}` }
|
|
27664
|
+
});
|
|
27665
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
27666
|
+
return await res.json();
|
|
27667
|
+
}
|
|
27668
|
+
async function restoreSessions(ids, opts = {}) {
|
|
27669
|
+
const unique = [...new Set(ids.filter(Boolean))];
|
|
27670
|
+
const targets = opts.targets ?? loadAllCredentials();
|
|
27671
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
27672
|
+
const out = { requested: unique.length, restored: 0, perTarget: {} };
|
|
27673
|
+
if (unique.length === 0 || targets.length === 0) return out;
|
|
27674
|
+
let best = 0;
|
|
27675
|
+
for (const t of targets) {
|
|
27676
|
+
try {
|
|
27677
|
+
let restored = 0, notDeleted = 0;
|
|
27678
|
+
for (let i = 0; i < unique.length; i += BATCH) {
|
|
27679
|
+
const res = await fetchImpl(`${base2(t.serverUrl)}/api/data/restore`, {
|
|
27680
|
+
method: "POST",
|
|
27681
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${t.token}` },
|
|
27682
|
+
body: JSON.stringify({ session_ids: unique.slice(i, i + BATCH) })
|
|
27683
|
+
});
|
|
27684
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
27685
|
+
const body = await res.json();
|
|
27686
|
+
restored += body.restored ?? 0;
|
|
27687
|
+
notDeleted += (body.notDeleted ?? []).length;
|
|
27688
|
+
}
|
|
27689
|
+
out.perTarget[t.serverUrl] = { restored, notDeleted };
|
|
27690
|
+
best = Math.max(best, restored);
|
|
27691
|
+
} catch (e) {
|
|
27692
|
+
out.perTarget[t.serverUrl] = { restored: 0, notDeleted: 0, error: e instanceof Error ? e.message : "failed" };
|
|
27693
|
+
}
|
|
27694
|
+
}
|
|
27695
|
+
out.restored = best;
|
|
27696
|
+
return out;
|
|
27697
|
+
}
|
|
27698
|
+
function needsConfirmation(opts) {
|
|
27699
|
+
const enumeratedByCaller = opts.argvIds > 0 && !opts.project && !opts.stdin;
|
|
27700
|
+
return !enumeratedByCaller;
|
|
27701
|
+
}
|
|
27702
|
+
var PAGE, BATCH, base2;
|
|
27703
|
+
var init_bulk_delete = __esm({
|
|
27704
|
+
"src/bulk-delete.ts"() {
|
|
27705
|
+
"use strict";
|
|
27706
|
+
init_sync_client();
|
|
27707
|
+
init_sync_ledger();
|
|
27708
|
+
PAGE = 200;
|
|
27709
|
+
BATCH = 250;
|
|
27710
|
+
base2 = (url) => url.replace(/\/+$/, "");
|
|
27711
|
+
}
|
|
27712
|
+
});
|
|
27713
|
+
|
|
27528
27714
|
// ../engine/dist/core/resume-command.js
|
|
27529
27715
|
function toolOfSessionId(sessionId) {
|
|
27530
27716
|
if (sessionId.startsWith("codex_"))
|
|
@@ -27735,13 +27921,13 @@ function requireTarget() {
|
|
|
27735
27921
|
}
|
|
27736
27922
|
return t;
|
|
27737
27923
|
}
|
|
27738
|
-
async function readJsonBody(res,
|
|
27924
|
+
async function readJsonBody(res, base3, what) {
|
|
27739
27925
|
const text = await res.text().catch(() => "");
|
|
27740
27926
|
try {
|
|
27741
27927
|
return JSON.parse(text);
|
|
27742
27928
|
} catch {
|
|
27743
27929
|
throw new Error(
|
|
27744
|
-
`${
|
|
27930
|
+
`${base3} 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`
|
|
27745
27931
|
);
|
|
27746
27932
|
}
|
|
27747
27933
|
}
|
|
@@ -28526,9 +28712,9 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
28526
28712
|
return;
|
|
28527
28713
|
}
|
|
28528
28714
|
const target = firstTarget();
|
|
28529
|
-
const
|
|
28715
|
+
const base3 = target?.base || (process.env.CHAT_RECALL_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
|
|
28530
28716
|
try {
|
|
28531
|
-
const res = await fetch(`${
|
|
28717
|
+
const res = await fetch(`${base3}/api/contact/feedback`, {
|
|
28532
28718
|
method: "POST",
|
|
28533
28719
|
headers: {
|
|
28534
28720
|
"content-type": "application/json",
|
|
@@ -28555,7 +28741,7 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
28555
28741
|
console.log(chalk2.dim(" Add --email <address> next time if you want a reply."));
|
|
28556
28742
|
}
|
|
28557
28743
|
} catch (err) {
|
|
28558
|
-
console.error(chalk2.red(`Could not reach ${
|
|
28744
|
+
console.error(chalk2.red(`Could not reach ${base3}.`));
|
|
28559
28745
|
console.error(chalk2.dim(" Your message, so it is not lost:"));
|
|
28560
28746
|
console.error(chalk2.dim(` ${message}`));
|
|
28561
28747
|
process.exitCode = 1;
|
|
@@ -29123,13 +29309,13 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
|
|
|
29123
29309
|
}
|
|
29124
29310
|
const { fetchWithTimeout: fetchWithTimeout2 } = await Promise.resolve().then(() => (init_http(), http_exports));
|
|
29125
29311
|
for (const t of targets) {
|
|
29126
|
-
const
|
|
29312
|
+
const base3 = t.serverUrl.replace(/\/+$/, "");
|
|
29127
29313
|
const headers = {};
|
|
29128
29314
|
if (t.token) headers.authorization = `Bearer ${t.token}`;
|
|
29129
29315
|
let deleted = 0, missing = 0, failed = 0;
|
|
29130
29316
|
for (const id of ids) {
|
|
29131
29317
|
try {
|
|
29132
|
-
const res = await fetchWithTimeout2(`${
|
|
29318
|
+
const res = await fetchWithTimeout2(`${base3}/api/conversations/${encodeURIComponent(id)}`, { method: "DELETE", headers }, 3e4);
|
|
29133
29319
|
if (res.ok) deleted++;
|
|
29134
29320
|
else if (res.status === 404) missing++;
|
|
29135
29321
|
else failed++;
|
|
@@ -29137,7 +29323,7 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
|
|
|
29137
29323
|
failed++;
|
|
29138
29324
|
}
|
|
29139
29325
|
}
|
|
29140
|
-
const line = ` ${
|
|
29326
|
+
const line = ` ${base3}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk2.red(`, ${failed} FAILED`) : "");
|
|
29141
29327
|
console.log(failed ? chalk2.yellow(line) : chalk2.green(line));
|
|
29142
29328
|
if (failed) process.exitCode = 1;
|
|
29143
29329
|
}
|
|
@@ -29985,10 +30171,10 @@ program.command("service <action>").description("Manage the per-user background
|
|
|
29985
30171
|
});
|
|
29986
30172
|
async function runLogin(serverUrl, opts) {
|
|
29987
30173
|
const { saveCredentials: saveCredentials2, loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
29988
|
-
const
|
|
30174
|
+
const base3 = serverUrl.replace(/\/+$/, "");
|
|
29989
30175
|
const verifyToken = async (token) => {
|
|
29990
30176
|
try {
|
|
29991
|
-
const res = await fetch(`${
|
|
30177
|
+
const res = await fetch(`${base3}/api/status`, {
|
|
29992
30178
|
headers: token ? { authorization: `Bearer ${token}` } : {},
|
|
29993
30179
|
signal: AbortSignal.timeout(1e4)
|
|
29994
30180
|
});
|
|
@@ -30004,36 +30190,36 @@ async function runLogin(serverUrl, opts) {
|
|
|
30004
30190
|
return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
|
|
30005
30191
|
}
|
|
30006
30192
|
const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30007
|
-
const who = await identifyServer(
|
|
30008
|
-
if (!identified(who)) return failLogin(opts, identifyAdvice(who,
|
|
30193
|
+
const who = await identifyServer(base3, { timeoutMs: 1e4 });
|
|
30194
|
+
if (!identified(who)) return failLogin(opts, identifyAdvice(who, base3));
|
|
30009
30195
|
const check = await verifyToken(token);
|
|
30010
30196
|
if (!check.ok) {
|
|
30011
30197
|
if (check.status === 401 || check.status === 403) {
|
|
30012
30198
|
console.error(chalk2.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
|
|
30013
|
-
return failLogin(opts, `${
|
|
30199
|
+
return failLogin(opts, `${base3} rejected the token (HTTP ${check.status})`);
|
|
30014
30200
|
}
|
|
30015
30201
|
if (check.status !== void 0 && check.status >= 500) {
|
|
30016
|
-
return failLogin(opts, `${
|
|
30202
|
+
return failLogin(opts, `${base3} answered HTTP ${check.status} \u2014 the server is up but failing. The token was never checked. Nothing to fix locally.`);
|
|
30017
30203
|
}
|
|
30018
30204
|
if (check.status === 404 || check.status === 410) {
|
|
30019
|
-
return failLogin(opts, `${
|
|
30205
|
+
return failLogin(opts, `${base3} does not serve the chat-recall API (HTTP ${check.status}). If the server moved, log in to its new URL.`);
|
|
30020
30206
|
}
|
|
30021
|
-
return failLogin(opts, `could not verify the token against ${
|
|
30207
|
+
return failLogin(opts, `could not verify the token against ${base3}: ${check.error || `HTTP ${check.status}`}`);
|
|
30022
30208
|
}
|
|
30023
30209
|
saveCredentials2({ serverUrl, token });
|
|
30024
30210
|
console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` server: ${serverUrl} (token verified)`));
|
|
30025
30211
|
return;
|
|
30026
30212
|
}
|
|
30027
|
-
const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") ===
|
|
30213
|
+
const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base3);
|
|
30028
30214
|
if (existing && (await verifyToken(existing.token)).ok) {
|
|
30029
30215
|
console.log(chalk2.green("\u2713 Already connected.") + chalk2.dim(` server: ${serverUrl} (existing token verified)`));
|
|
30030
30216
|
return;
|
|
30031
30217
|
}
|
|
30032
30218
|
try {
|
|
30033
30219
|
const { probeServer: probeServer2, probeOk: probeOk2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30034
|
-
const identified = await probeServer2(
|
|
30220
|
+
const identified = await probeServer2(base3, { timeoutMs: 8e3 });
|
|
30035
30221
|
if (probeOk2(identified)) {
|
|
30036
|
-
const probe = await fetch(`${
|
|
30222
|
+
const probe = await fetch(`${base3}/api/status`, { signal: AbortSignal.timeout(8e3) });
|
|
30037
30223
|
if (probe.status === 200) {
|
|
30038
30224
|
saveCredentials2({ serverUrl, token: "" });
|
|
30039
30225
|
console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
|
|
@@ -30054,16 +30240,16 @@ async function runLogin(serverUrl, opts) {
|
|
|
30054
30240
|
if (!issuer) {
|
|
30055
30241
|
const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30056
30242
|
for (let attempt = 1; attempt <= 3 && !authProvider; attempt++) {
|
|
30057
|
-
const probe = await probeServer2(
|
|
30243
|
+
const probe = await probeServer2(base3, { timeoutMs: 15e3 });
|
|
30058
30244
|
if (probeOk2(probe)) {
|
|
30059
30245
|
const caps = probe.raw;
|
|
30060
30246
|
authProvider = caps?.authProvider;
|
|
30061
30247
|
if (caps?.oidcIssuer) issuer = caps.oidcIssuer;
|
|
30062
30248
|
capsError = null;
|
|
30063
30249
|
} else if (probe.kind === "moved" || probe.kind === "not_api") {
|
|
30064
|
-
return failLogin(opts, probeAdvice2(probe,
|
|
30250
|
+
return failLogin(opts, probeAdvice2(probe, base3));
|
|
30065
30251
|
} else {
|
|
30066
|
-
capsError = probeAdvice2(probe,
|
|
30252
|
+
capsError = probeAdvice2(probe, base3);
|
|
30067
30253
|
}
|
|
30068
30254
|
if (!authProvider && attempt < 3) await new Promise((r) => setTimeout(r, attempt * 1e3));
|
|
30069
30255
|
}
|
|
@@ -30072,7 +30258,7 @@ async function runLogin(serverUrl, opts) {
|
|
|
30072
30258
|
authProvider = "better-auth";
|
|
30073
30259
|
if (capsError) {
|
|
30074
30260
|
console.log(` ${chalk2.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
|
|
30075
|
-
void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(
|
|
30261
|
+
void Promise.resolve().then(() => (init_install_report(), install_report_exports)).then(({ reportInstallFailure: reportInstallFailure2 }) => reportInstallFailure2(base3, {
|
|
30076
30262
|
step: "cli_login_probe",
|
|
30077
30263
|
reason: capsError?.slice(0, 40) ?? null,
|
|
30078
30264
|
message: capsError
|
|
@@ -30094,20 +30280,20 @@ async function runLogin(serverUrl, opts) {
|
|
|
30094
30280
|
console.log(chalk2.dim(` If the page asks for a code: ${chalk2.bold(p.userCode)}`));
|
|
30095
30281
|
console.log(chalk2.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
|
|
30096
30282
|
};
|
|
30097
|
-
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(
|
|
30283
|
+
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base3, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
|
|
30098
30284
|
const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
|
|
30099
|
-
const meRes = await fetch(`${
|
|
30100
|
-
if (!meRes.ok) throw new Error(`${
|
|
30101
|
-
const me = await readJsonBody(meRes,
|
|
30285
|
+
const meRes = await fetch(`${base3}/api/me`, { headers: authHdr });
|
|
30286
|
+
if (!meRes.ok) throw new Error(`${base3}/api/me: HTTP ${meRes.status} ${await meRes.text().catch(() => "")}`);
|
|
30287
|
+
const me = await readJsonBody(meRes, base3, "GET /api/me");
|
|
30102
30288
|
const teams = me.teams || [];
|
|
30103
30289
|
let slug = opts.team;
|
|
30104
30290
|
if (!slug) {
|
|
30105
30291
|
if (teams.length === 1) slug = teams[0].team_slug;
|
|
30106
30292
|
else if (teams.length === 0) {
|
|
30107
30293
|
const name = me.user?.email?.split("@")[0]?.replace(/[^a-z0-9]/gi, "") || "workspace";
|
|
30108
|
-
const created = await fetch(`${
|
|
30294
|
+
const created = await fetch(`${base3}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
|
|
30109
30295
|
if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
|
|
30110
|
-
slug = (await readJsonBody(created,
|
|
30296
|
+
slug = (await readJsonBody(created, base3, "POST /api/teams")).slug;
|
|
30111
30297
|
console.log(chalk2.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
|
|
30112
30298
|
} else {
|
|
30113
30299
|
teams.forEach((t) => console.error(` ${t.team_slug} ${chalk2.dim(t.name)}`));
|
|
@@ -30115,13 +30301,13 @@ async function runLogin(serverUrl, opts) {
|
|
|
30115
30301
|
}
|
|
30116
30302
|
}
|
|
30117
30303
|
const deviceId = opts.deviceId || (await import("node:os")).hostname();
|
|
30118
|
-
const mint = await fetch(`${
|
|
30304
|
+
const mint = await fetch(`${base3}/api/teams/${encodeURIComponent(slug)}/tokens`, {
|
|
30119
30305
|
method: "POST",
|
|
30120
30306
|
headers: authHdr,
|
|
30121
30307
|
body: JSON.stringify({ device_id: deviceId })
|
|
30122
30308
|
});
|
|
30123
30309
|
if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
|
|
30124
|
-
const { token } = await readJsonBody(mint,
|
|
30310
|
+
const { token } = await readJsonBody(mint, base3, "POST /api/teams/:slug/tokens");
|
|
30125
30311
|
saveCredentials2({ serverUrl, token });
|
|
30126
30312
|
console.log(chalk2.green(`\u2713 Logged in to ${chalk2.bold(slug)}`) + chalk2.dim(` (device: ${deviceId}) server: ${serverUrl}`));
|
|
30127
30313
|
if (!opts.fromInit) {
|
|
@@ -30373,30 +30559,142 @@ program.command("logout <server-url>").description("Remove one sync target (othe
|
|
|
30373
30559
|
process.exit(1);
|
|
30374
30560
|
}
|
|
30375
30561
|
});
|
|
30376
|
-
program.command("delete
|
|
30562
|
+
program.command("delete [session-ids...]").description("Delete sessions from chat-recall everywhere: purges them on every logged-in server and tombstones them so they can't resurrect on the next sync. Does NOT touch the AI tool's own transcript files.").option("--project <id>", "Select every session in a project (e.g. git:github.com/me/repo)").option("--match <text>", "With --project: only sessions whose first prompt is EXACTLY this").option("--tool <name>", "With --project: only sessions from this tool (claude, codex, \u2026)").option("--stdin", "Read session ids from stdin, one per line").option("-n, --dry-run", "List what would be deleted and exit").option("-y, --yes", "Skip the confirmation prompt").action(async (sessionIds, opts) => {
|
|
30377
30563
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
30564
|
+
const { selectSessions: selectSessions2, bulkDelete: bulkDelete2, needsConfirmation: needsConfirmation2 } = await Promise.resolve().then(() => (init_bulk_delete(), bulk_delete_exports));
|
|
30378
30565
|
const targets = loadAllCredentials2();
|
|
30379
30566
|
if (targets.length === 0) {
|
|
30380
30567
|
console.error(chalk2.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
|
|
30381
30568
|
process.exit(1);
|
|
30382
30569
|
}
|
|
30383
|
-
|
|
30384
|
-
|
|
30570
|
+
if ((opts.match || opts.tool) && !opts.project) {
|
|
30571
|
+
console.error(chalk2.red("--match and --tool select WITHIN a project; pass --project too."));
|
|
30572
|
+
process.exit(1);
|
|
30573
|
+
}
|
|
30574
|
+
let ids = [...sessionIds];
|
|
30575
|
+
let preview = [];
|
|
30576
|
+
if (opts.stdin) {
|
|
30577
|
+
const stdin = await new Promise((resolve3) => {
|
|
30578
|
+
let buf = "";
|
|
30579
|
+
process.stdin.setEncoding("utf-8");
|
|
30580
|
+
process.stdin.on("data", (d) => {
|
|
30581
|
+
buf += d;
|
|
30582
|
+
});
|
|
30583
|
+
process.stdin.on("end", () => resolve3(buf));
|
|
30584
|
+
});
|
|
30585
|
+
ids.push(...stdin.split("\n").map((l) => l.trim()).filter(Boolean));
|
|
30586
|
+
}
|
|
30587
|
+
if (opts.project) {
|
|
30385
30588
|
try {
|
|
30386
|
-
|
|
30387
|
-
|
|
30388
|
-
|
|
30589
|
+
preview = await selectSessions2(targets[0], { project: opts.project, match: opts.match, tool: opts.tool });
|
|
30590
|
+
} catch (e) {
|
|
30591
|
+
console.error(chalk2.red(`Could not list sessions: ${e instanceof Error ? e.message : "failed"}`));
|
|
30592
|
+
process.exit(1);
|
|
30593
|
+
}
|
|
30594
|
+
ids.push(...preview.map((r) => r.sessionId));
|
|
30595
|
+
}
|
|
30596
|
+
ids = [...new Set(ids.filter(Boolean))];
|
|
30597
|
+
if (ids.length === 0) {
|
|
30598
|
+
console.log(chalk2.yellow("Nothing selected \u2014 no session ids given and no selector matched."));
|
|
30599
|
+
return;
|
|
30600
|
+
}
|
|
30601
|
+
const shown = preview.length > 0 ? preview.slice(0, 10) : ids.slice(0, 10).map((id) => ({ sessionId: id, firstPrompt: void 0 }));
|
|
30602
|
+
for (const r of shown) {
|
|
30603
|
+
const label = r.firstPrompt ? chalk2.dim(` \u2014 ${r.firstPrompt.replace(/\s+/g, " ").slice(0, 60)}`) : "";
|
|
30604
|
+
console.log(` ${r.sessionId}${label}`);
|
|
30605
|
+
}
|
|
30606
|
+
if (ids.length > shown.length) console.log(chalk2.dim(` \u2026 and ${ids.length - shown.length} more`));
|
|
30607
|
+
if (opts.dryRun) {
|
|
30608
|
+
console.log(chalk2.cyan(`
|
|
30609
|
+
Dry run \u2014 ${ids.length} session(s) would be deleted on ${targets.length} server(s). Nothing was changed.`));
|
|
30610
|
+
return;
|
|
30611
|
+
}
|
|
30612
|
+
if (!opts.yes && needsConfirmation2({ argvIds: sessionIds.length, project: opts.project, stdin: opts.stdin })) {
|
|
30613
|
+
if (!process.stdin.isTTY) {
|
|
30614
|
+
console.error(chalk2.red(`
|
|
30615
|
+
Refusing to delete ${ids.length} session(s) without confirmation \u2014 pass --yes (or -n to preview).`));
|
|
30616
|
+
process.exit(1);
|
|
30617
|
+
}
|
|
30618
|
+
const readline = await import("node:readline/promises");
|
|
30619
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
30620
|
+
const answer = await rl.question(chalk2.yellow(`
|
|
30621
|
+
Permanently delete ${ids.length} session(s) on ${targets.length} server(s)? This cannot be undone. [y/N] `));
|
|
30622
|
+
rl.close();
|
|
30623
|
+
if (answer.trim().toLowerCase() !== "y") {
|
|
30624
|
+
console.log("Aborted \u2014 nothing was deleted.");
|
|
30625
|
+
return;
|
|
30626
|
+
}
|
|
30627
|
+
}
|
|
30628
|
+
const res = await bulkDelete2(ids, { targets });
|
|
30629
|
+
for (const [server, r] of Object.entries(res.perTarget)) {
|
|
30630
|
+
if (r.error) console.error(chalk2.red(`\u2717 ${server}: ${r.deleted}/${ids.length} deleted, then failed \u2014 ${r.error}`));
|
|
30631
|
+
else console.log(chalk2.green(`\u2713 ${server}: ${r.deleted} deleted`));
|
|
30632
|
+
}
|
|
30633
|
+
if (res.deleted === 0) {
|
|
30634
|
+
console.error(chalk2.red("Nothing was deleted."));
|
|
30635
|
+
process.exit(1);
|
|
30636
|
+
}
|
|
30637
|
+
console.log(chalk2.dim(`Tombstoned \u2014 re-sync cannot resurrect them. Local transcript files were not touched.`));
|
|
30638
|
+
if (res.deleted < ids.length) {
|
|
30639
|
+
console.error(chalk2.yellow(`Note: ${ids.length - res.deleted} session(s) did not delete on any server.`));
|
|
30640
|
+
}
|
|
30641
|
+
});
|
|
30642
|
+
program.command("restore [session-ids...]").description("Undo a delete: lifts the tombstone so those sessions can be synced again. Restores no content by itself \u2014 re-run `chat-recall index --force` on a machine that still has the transcript. With no ids, lists what has been deleted.").option("--stdin", "Read session ids from stdin, one per line").option("--list", "Just show what has been deleted, newest first").option("--limit <n>", "How many deletions to list (default 50)").action(async (sessionIds, opts) => {
|
|
30643
|
+
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
30644
|
+
const { listTombstones: listTombstones2, restoreSessions: restoreSessions2 } = await Promise.resolve().then(() => (init_bulk_delete(), bulk_delete_exports));
|
|
30645
|
+
const targets = loadAllCredentials2();
|
|
30646
|
+
if (targets.length === 0) {
|
|
30647
|
+
console.error(chalk2.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
|
|
30648
|
+
process.exit(1);
|
|
30649
|
+
}
|
|
30650
|
+
const ids = [...sessionIds];
|
|
30651
|
+
if (opts.stdin) {
|
|
30652
|
+
const buf = await new Promise((resolve3) => {
|
|
30653
|
+
let b = "";
|
|
30654
|
+
process.stdin.setEncoding("utf-8");
|
|
30655
|
+
process.stdin.on("data", (d) => {
|
|
30656
|
+
b += d;
|
|
30389
30657
|
});
|
|
30390
|
-
|
|
30391
|
-
|
|
30392
|
-
|
|
30393
|
-
|
|
30658
|
+
process.stdin.on("end", () => resolve3(b));
|
|
30659
|
+
});
|
|
30660
|
+
ids.push(...buf.split("\n").map((l) => l.trim()).filter(Boolean));
|
|
30661
|
+
}
|
|
30662
|
+
if (opts.list || ids.length === 0) {
|
|
30663
|
+
const limit = Math.max(1, parseInt(opts.limit ?? "") || 50);
|
|
30664
|
+
try {
|
|
30665
|
+
const { total, tombstones } = await listTombstones2(targets[0], limit);
|
|
30666
|
+
if (total === 0) {
|
|
30667
|
+
console.log(chalk2.dim("Nothing has been deleted."));
|
|
30668
|
+
return;
|
|
30669
|
+
}
|
|
30670
|
+
console.log(chalk2.bold(`${total} deleted session(s) \u2014 newest first:
|
|
30671
|
+
`));
|
|
30672
|
+
for (const t of tombstones) {
|
|
30673
|
+
console.log(` ${t.session_id} ${chalk2.dim(new Date(t.deleted_at).toISOString().replace("T", " ").slice(0, 19))}`);
|
|
30674
|
+
}
|
|
30675
|
+
if (total > tombstones.length) console.log(chalk2.dim(`
|
|
30676
|
+
\u2026 and ${total - tombstones.length} more (--limit to see them)`));
|
|
30677
|
+
console.log(chalk2.dim("\nRestore with: chat-recall restore <id...>"));
|
|
30394
30678
|
} catch (e) {
|
|
30395
|
-
console.error(chalk2.red(
|
|
30679
|
+
console.error(chalk2.red(`Could not list deletions: ${e instanceof Error ? e.message : "failed"}`));
|
|
30680
|
+
process.exit(1);
|
|
30396
30681
|
}
|
|
30682
|
+
return;
|
|
30397
30683
|
}
|
|
30398
|
-
|
|
30399
|
-
|
|
30684
|
+
const res = await restoreSessions2(ids, { targets });
|
|
30685
|
+
for (const [server, r] of Object.entries(res.perTarget)) {
|
|
30686
|
+
if (r.error) console.error(chalk2.red(`\u2717 ${server}: ${r.error}`));
|
|
30687
|
+
else {
|
|
30688
|
+
console.log(chalk2.green(`\u2713 ${server}: ${r.restored} tombstone(s) lifted`));
|
|
30689
|
+
if (r.notDeleted > 0) console.log(chalk2.yellow(` ${r.notDeleted} id(s) were not deleted here \u2014 nothing to lift`));
|
|
30690
|
+
}
|
|
30691
|
+
}
|
|
30692
|
+
if (res.restored === 0) {
|
|
30693
|
+
console.error(chalk2.red("No tombstones were lifted."));
|
|
30694
|
+
process.exit(1);
|
|
30695
|
+
}
|
|
30696
|
+
console.log(chalk2.dim("\nThe content is still gone from the server. Re-upload it from a machine that"));
|
|
30697
|
+
console.log(chalk2.dim("still holds the transcript: chat-recall index --force"));
|
|
30400
30698
|
});
|
|
30401
30699
|
program.command("rename <session-id> <name>").description('Give a session a memorable name on every logged-in server (mirrors Claude Code\'s /rename \u2014 shows in `recall recent` and the web UI in place of the auto summary). Pass an empty name "" to clear it and revert to the auto title.').action(async (sessionId, name) => {
|
|
30402
30700
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
@@ -30486,16 +30784,16 @@ program.command("update").description("Update this CLI now from the server you s
|
|
|
30486
30784
|
}
|
|
30487
30785
|
let installFailed = false;
|
|
30488
30786
|
for (const cred of targets) {
|
|
30489
|
-
const
|
|
30787
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
30490
30788
|
const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
30491
|
-
const r = await runAutoUpdate2(
|
|
30789
|
+
const r = await runAutoUpdate2(base3, headers, cliVersion3());
|
|
30492
30790
|
if (r.updated) {
|
|
30493
|
-
console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${
|
|
30791
|
+
console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base3})`));
|
|
30494
30792
|
continue;
|
|
30495
30793
|
}
|
|
30496
30794
|
const benign = /already current|no CLI release|disabled/.test(r.reason);
|
|
30497
30795
|
if (/install failed|download failed|checksum/.test(r.reason)) installFailed = true;
|
|
30498
|
-
console.log((benign ? chalk2.dim("\u2022 ") : chalk2.red("\u2717 ")) + r.reason + chalk2.dim(` (${
|
|
30796
|
+
console.log((benign ? chalk2.dim("\u2022 ") : chalk2.red("\u2717 ")) + r.reason + chalk2.dim(` (${base3})`));
|
|
30499
30797
|
}
|
|
30500
30798
|
await refreshUpdateCheck2(true);
|
|
30501
30799
|
if (installFailed) {
|