chat-recall 0.5.31 → 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/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 +686 -435
- package/dist/cli.js.map +1 -1
- package/dist/mcp.js +191 -186
- package/dist/scan-worker.js +59 -20
- package/dist/watch.js +194 -189
- 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,7 +10109,7 @@ 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
10114
|
function agyTranscriptPath(logsDir) {
|
|
10090
10115
|
const full = join11(logsDir, "transcript_full.jsonl");
|
|
@@ -10253,7 +10278,7 @@ var init_agy = __esm({
|
|
|
10253
10278
|
for (const brainDir of agyBrainDirs()) {
|
|
10254
10279
|
let sessionDirs;
|
|
10255
10280
|
try {
|
|
10256
|
-
sessionDirs =
|
|
10281
|
+
sessionDirs = readdirSync8(brainDir);
|
|
10257
10282
|
} catch {
|
|
10258
10283
|
continue;
|
|
10259
10284
|
}
|
|
@@ -10528,7 +10553,7 @@ var init_agy = __esm({
|
|
|
10528
10553
|
const candidates2 = [];
|
|
10529
10554
|
let sessionDirs;
|
|
10530
10555
|
try {
|
|
10531
|
-
sessionDirs =
|
|
10556
|
+
sessionDirs = readdirSync8(brainDir);
|
|
10532
10557
|
} catch {
|
|
10533
10558
|
return [];
|
|
10534
10559
|
}
|
|
@@ -10604,7 +10629,7 @@ var init_agy = __esm({
|
|
|
10604
10629
|
});
|
|
10605
10630
|
|
|
10606
10631
|
// ../engine/dist/core/backends/cursor-store.js
|
|
10607
|
-
import { existsSync as existsSync10, readdirSync as
|
|
10632
|
+
import { existsSync as existsSync10, readdirSync as readdirSync9, readFileSync as readFileSync6, statSync as statSync9 } from "fs";
|
|
10608
10633
|
import { join as join12 } from "path";
|
|
10609
10634
|
function cursorProjectSlug(absPath) {
|
|
10610
10635
|
return absPath.replace(/[^a-zA-Z0-9]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -10613,7 +10638,7 @@ function listChatsIn(chatsRoot) {
|
|
|
10613
10638
|
const out = [];
|
|
10614
10639
|
let hashDirs;
|
|
10615
10640
|
try {
|
|
10616
|
-
hashDirs =
|
|
10641
|
+
hashDirs = readdirSync9(chatsRoot);
|
|
10617
10642
|
} catch {
|
|
10618
10643
|
return out;
|
|
10619
10644
|
}
|
|
@@ -10623,7 +10648,7 @@ function listChatsIn(chatsRoot) {
|
|
|
10623
10648
|
try {
|
|
10624
10649
|
if (!statSync9(hashPath3).isDirectory())
|
|
10625
10650
|
continue;
|
|
10626
|
-
chatIds =
|
|
10651
|
+
chatIds = readdirSync9(hashPath3);
|
|
10627
10652
|
} catch {
|
|
10628
10653
|
continue;
|
|
10629
10654
|
}
|
|
@@ -10668,7 +10693,7 @@ function findChat(chatsRoots, chatId) {
|
|
|
10668
10693
|
for (const root of chatsRoots) {
|
|
10669
10694
|
let hashDirs;
|
|
10670
10695
|
try {
|
|
10671
|
-
hashDirs =
|
|
10696
|
+
hashDirs = readdirSync9(root);
|
|
10672
10697
|
} catch {
|
|
10673
10698
|
continue;
|
|
10674
10699
|
}
|
|
@@ -10989,7 +11014,7 @@ var init_cursor_store = __esm({
|
|
|
10989
11014
|
});
|
|
10990
11015
|
|
|
10991
11016
|
// ../engine/dist/core/backends/cursor-ide.js
|
|
10992
|
-
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";
|
|
10993
11018
|
import { dirname as dirname11, join as join13 } from "path";
|
|
10994
11019
|
function jsonOf(value) {
|
|
10995
11020
|
if (value == null)
|
|
@@ -11052,7 +11077,7 @@ function workspaceIndex(workspaceRoots) {
|
|
|
11052
11077
|
for (const root of workspaceRoots) {
|
|
11053
11078
|
let entries;
|
|
11054
11079
|
try {
|
|
11055
|
-
entries =
|
|
11080
|
+
entries = readdirSync10(root);
|
|
11056
11081
|
} catch {
|
|
11057
11082
|
continue;
|
|
11058
11083
|
}
|
|
@@ -11139,7 +11164,7 @@ function listComposers(globalDbPath, workspaceRoots) {
|
|
|
11139
11164
|
for (const root of workspaceRoots) {
|
|
11140
11165
|
let entries;
|
|
11141
11166
|
try {
|
|
11142
|
-
entries =
|
|
11167
|
+
entries = readdirSync10(root);
|
|
11143
11168
|
} catch {
|
|
11144
11169
|
continue;
|
|
11145
11170
|
}
|
|
@@ -12039,28 +12064,8 @@ var init_shadow = __esm({
|
|
|
12039
12064
|
}
|
|
12040
12065
|
});
|
|
12041
12066
|
|
|
12042
|
-
// ../engine/dist/core/project-dir-name.js
|
|
12043
|
-
function looksWindowsEncoded(dirName) {
|
|
12044
|
-
return /^[A-Za-z]--/.test(dirName);
|
|
12045
|
-
}
|
|
12046
|
-
function decodeProjectDirName(dirName) {
|
|
12047
|
-
if (!dirName)
|
|
12048
|
-
return "";
|
|
12049
|
-
if (looksWindowsEncoded(dirName)) {
|
|
12050
|
-
const drive = dirName[0].toUpperCase();
|
|
12051
|
-
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
12052
|
-
return `${drive}:\\${rest}`;
|
|
12053
|
-
}
|
|
12054
|
-
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
12055
|
-
}
|
|
12056
|
-
var init_project_dir_name = __esm({
|
|
12057
|
-
"../engine/dist/core/project-dir-name.js"() {
|
|
12058
|
-
"use strict";
|
|
12059
|
-
}
|
|
12060
|
-
});
|
|
12061
|
-
|
|
12062
12067
|
// ../engine/dist/core/live-session-scan.js
|
|
12063
|
-
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";
|
|
12064
12069
|
import { join as join16, basename as basename10 } from "path";
|
|
12065
12070
|
import { createHash as createHash5 } from "crypto";
|
|
12066
12071
|
function lazyGeminiProjectsJson() {
|
|
@@ -12097,7 +12102,7 @@ function sessionFileIndex() {
|
|
|
12097
12102
|
seenRoots.add(root);
|
|
12098
12103
|
let entries;
|
|
12099
12104
|
try {
|
|
12100
|
-
entries =
|
|
12105
|
+
entries = readdirSync11(root, { withFileTypes: true });
|
|
12101
12106
|
} catch {
|
|
12102
12107
|
continue;
|
|
12103
12108
|
}
|
|
@@ -12107,7 +12112,7 @@ function sessionFileIndex() {
|
|
|
12107
12112
|
const dir = join16(root, entry.name);
|
|
12108
12113
|
let names;
|
|
12109
12114
|
try {
|
|
12110
|
-
names =
|
|
12115
|
+
names = readdirSync11(dir);
|
|
12111
12116
|
} catch {
|
|
12112
12117
|
continue;
|
|
12113
12118
|
}
|
|
@@ -12118,7 +12123,7 @@ function sessionFileIndex() {
|
|
|
12118
12123
|
const located = {
|
|
12119
12124
|
path: join16(dir, name),
|
|
12120
12125
|
projectDir: entry.name,
|
|
12121
|
-
projectPath:
|
|
12126
|
+
projectPath: resolveProjectDirName(entry.name)
|
|
12122
12127
|
};
|
|
12123
12128
|
const prior = byId.get(id);
|
|
12124
12129
|
if (prior)
|
|
@@ -12205,7 +12210,7 @@ function resolveSessionContentPaths(sessionFile) {
|
|
|
12205
12210
|
const subDir = join16(sessionFile.slice(0, -6), "subagents");
|
|
12206
12211
|
if (!existsSync14(subDir))
|
|
12207
12212
|
return [sessionFile];
|
|
12208
|
-
const subPaths =
|
|
12213
|
+
const subPaths = readdirSync11(subDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join16(subDir, f));
|
|
12209
12214
|
return [sessionFile, ...subPaths];
|
|
12210
12215
|
}
|
|
12211
12216
|
function loadGeminiProjectMap() {
|
|
@@ -12253,7 +12258,7 @@ function geminiIndex() {
|
|
|
12253
12258
|
continue;
|
|
12254
12259
|
let projs;
|
|
12255
12260
|
try {
|
|
12256
|
-
projs =
|
|
12261
|
+
projs = readdirSync11(tmpRoot, { withFileTypes: true });
|
|
12257
12262
|
} catch {
|
|
12258
12263
|
continue;
|
|
12259
12264
|
}
|
|
@@ -12265,14 +12270,14 @@ function geminiIndex() {
|
|
|
12265
12270
|
continue;
|
|
12266
12271
|
let files;
|
|
12267
12272
|
try {
|
|
12268
|
-
files =
|
|
12273
|
+
files = readdirSync11(chats);
|
|
12269
12274
|
} catch {
|
|
12270
12275
|
continue;
|
|
12271
12276
|
}
|
|
12272
12277
|
for (const f of files) {
|
|
12273
12278
|
if (!isGeminiChat(f))
|
|
12274
12279
|
continue;
|
|
12275
|
-
const
|
|
12280
|
+
const base3 = f.replace(/\.jsonl?$/, "");
|
|
12276
12281
|
const located = {
|
|
12277
12282
|
path: join16(chats, f),
|
|
12278
12283
|
projectDir: proj.name,
|
|
@@ -12280,9 +12285,9 @@ function geminiIndex() {
|
|
|
12280
12285
|
format: f.endsWith(".jsonl") ? "jsonl" : "json"
|
|
12281
12286
|
};
|
|
12282
12287
|
all.push(located);
|
|
12283
|
-
if (!byBase.has(
|
|
12284
|
-
byBase.set(
|
|
12285
|
-
const tail =
|
|
12288
|
+
if (!byBase.has(base3))
|
|
12289
|
+
byBase.set(base3, located);
|
|
12290
|
+
const tail = base3.split("-").pop() || "";
|
|
12286
12291
|
if (tail.length >= 4 && !byTail.has(tail))
|
|
12287
12292
|
byTail.set(tail, located);
|
|
12288
12293
|
}
|
|
@@ -12384,21 +12389,21 @@ function findCodexSessionFile(sessionId) {
|
|
|
12384
12389
|
function findCodexSessionFileIn(root, sessionId) {
|
|
12385
12390
|
if (!existsSync14(root))
|
|
12386
12391
|
return null;
|
|
12387
|
-
for (const year of
|
|
12392
|
+
for (const year of readdirSync11(root, { withFileTypes: true })) {
|
|
12388
12393
|
if (!year.isDirectory())
|
|
12389
12394
|
continue;
|
|
12390
12395
|
const yearPath = join16(root, year.name);
|
|
12391
|
-
for (const month of
|
|
12396
|
+
for (const month of readdirSync11(yearPath, { withFileTypes: true })) {
|
|
12392
12397
|
if (!month.isDirectory())
|
|
12393
12398
|
continue;
|
|
12394
12399
|
const monthPath = join16(yearPath, month.name);
|
|
12395
|
-
for (const day of
|
|
12400
|
+
for (const day of readdirSync11(monthPath, { withFileTypes: true })) {
|
|
12396
12401
|
if (!day.isDirectory())
|
|
12397
12402
|
continue;
|
|
12398
12403
|
const dayPath = join16(monthPath, day.name);
|
|
12399
12404
|
let files;
|
|
12400
12405
|
try {
|
|
12401
|
-
files =
|
|
12406
|
+
files = readdirSync11(dayPath);
|
|
12402
12407
|
} catch {
|
|
12403
12408
|
continue;
|
|
12404
12409
|
}
|
|
@@ -12413,7 +12418,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
12413
12418
|
}
|
|
12414
12419
|
}
|
|
12415
12420
|
function scanDir(dir) {
|
|
12416
|
-
for (const entry of
|
|
12421
|
+
for (const entry of readdirSync11(dir, { withFileTypes: true })) {
|
|
12417
12422
|
if (entry.isDirectory()) {
|
|
12418
12423
|
const found = scanDir(join16(dir, entry.name));
|
|
12419
12424
|
if (found)
|
|
@@ -12568,7 +12573,7 @@ var init_first_prompt = __esm({
|
|
|
12568
12573
|
});
|
|
12569
12574
|
|
|
12570
12575
|
// ../engine/dist/core/backends/claude.js
|
|
12571
|
-
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";
|
|
12572
12577
|
import { join as join17, basename as basename11 } from "path";
|
|
12573
12578
|
function stripReminders(text) {
|
|
12574
12579
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -12723,13 +12728,13 @@ var init_claude2 = __esm({
|
|
|
12723
12728
|
collectSessionsFromRoot(root, cutoff, filter, seen, out) {
|
|
12724
12729
|
if (!existsSync16(root))
|
|
12725
12730
|
return;
|
|
12726
|
-
for (const proj of
|
|
12731
|
+
for (const proj of readdirSync12(root, { withFileTypes: true })) {
|
|
12727
12732
|
if (!proj.isDirectory())
|
|
12728
12733
|
continue;
|
|
12729
12734
|
if (filter && !proj.name.toLowerCase().includes(filter))
|
|
12730
12735
|
continue;
|
|
12731
12736
|
const projPath = join17(root, proj.name);
|
|
12732
|
-
const projectPath =
|
|
12737
|
+
const projectPath = resolveProjectDirName(proj.name);
|
|
12733
12738
|
const indexPath = join17(projPath, "sessions-index.json");
|
|
12734
12739
|
if (existsSync16(indexPath)) {
|
|
12735
12740
|
try {
|
|
@@ -12760,7 +12765,7 @@ var init_claude2 = __esm({
|
|
|
12760
12765
|
}
|
|
12761
12766
|
let files;
|
|
12762
12767
|
try {
|
|
12763
|
-
files =
|
|
12768
|
+
files = readdirSync12(projPath);
|
|
12764
12769
|
} catch {
|
|
12765
12770
|
continue;
|
|
12766
12771
|
}
|
|
@@ -13029,7 +13034,7 @@ var init_claude2 = __esm({
|
|
|
13029
13034
|
for (const root of claudeProjectDirs()) {
|
|
13030
13035
|
if (!existsSync16(root))
|
|
13031
13036
|
continue;
|
|
13032
|
-
for (const projEntry of
|
|
13037
|
+
for (const projEntry of readdirSync12(root, { withFileTypes: true })) {
|
|
13033
13038
|
if (!projEntry.isDirectory())
|
|
13034
13039
|
continue;
|
|
13035
13040
|
if (opts.projectFilter && !projEntry.name.toLowerCase().includes(opts.projectFilter.toLowerCase()))
|
|
@@ -13037,7 +13042,7 @@ var init_claude2 = __esm({
|
|
|
13037
13042
|
const projPath = join17(root, projEntry.name);
|
|
13038
13043
|
let files;
|
|
13039
13044
|
try {
|
|
13040
|
-
files =
|
|
13045
|
+
files = readdirSync12(projPath);
|
|
13041
13046
|
} catch {
|
|
13042
13047
|
continue;
|
|
13043
13048
|
}
|
|
@@ -13050,7 +13055,7 @@ var init_claude2 = __esm({
|
|
|
13050
13055
|
let mtime = st.mtimeMs;
|
|
13051
13056
|
const subDir = join17(projPath, f.slice(0, -6), "subagents");
|
|
13052
13057
|
if (existsSync16(subDir)) {
|
|
13053
|
-
for (const sub of
|
|
13058
|
+
for (const sub of readdirSync12(subDir)) {
|
|
13054
13059
|
try {
|
|
13055
13060
|
const subSt = statSync14(join17(subDir, sub));
|
|
13056
13061
|
if (subSt.mtimeMs > mtime)
|
|
@@ -13167,7 +13172,7 @@ __export(project_resolver_exports, {
|
|
|
13167
13172
|
});
|
|
13168
13173
|
import { execSync } from "child_process";
|
|
13169
13174
|
import { createHash as createHash6 } from "crypto";
|
|
13170
|
-
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";
|
|
13171
13176
|
import { basename as basename12, dirname as dirname13, isAbsolute, join as join18, resolve, sep } from "path";
|
|
13172
13177
|
function getProjectsConfigPath() {
|
|
13173
13178
|
return join18(getDataDir(), "projects.json");
|
|
@@ -13440,7 +13445,7 @@ function countGitChildren(dir) {
|
|
|
13440
13445
|
let count = 0;
|
|
13441
13446
|
let entries;
|
|
13442
13447
|
try {
|
|
13443
|
-
entries =
|
|
13448
|
+
entries = readdirSync13(dir);
|
|
13444
13449
|
} catch {
|
|
13445
13450
|
return 0;
|
|
13446
13451
|
}
|
|
@@ -13555,7 +13560,7 @@ var init_credentials_env = __esm({
|
|
|
13555
13560
|
|
|
13556
13561
|
// ../engine/dist/core/source-discovery.js
|
|
13557
13562
|
import { createHash as createHash7 } from "crypto";
|
|
13558
|
-
import { existsSync as existsSync18, readdirSync as
|
|
13563
|
+
import { existsSync as existsSync18, readdirSync as readdirSync14, statSync as statSync16 } from "fs";
|
|
13559
13564
|
import { join as join19 } from "path";
|
|
13560
13565
|
function sourceId(path) {
|
|
13561
13566
|
return "src_" + createHash7("sha256").update(path).digest("hex").slice(0, 12);
|
|
@@ -13592,7 +13597,7 @@ function countTranscripts(root, tool) {
|
|
|
13592
13597
|
return;
|
|
13593
13598
|
let entries;
|
|
13594
13599
|
try {
|
|
13595
|
-
entries =
|
|
13600
|
+
entries = readdirSync14(dir, { withFileTypes: true });
|
|
13596
13601
|
} catch {
|
|
13597
13602
|
return;
|
|
13598
13603
|
}
|
|
@@ -13671,7 +13676,7 @@ __export(home_discovery_exports, {
|
|
|
13671
13676
|
sessionIdsInHome: () => sessionIdsInHome
|
|
13672
13677
|
});
|
|
13673
13678
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
13674
|
-
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";
|
|
13675
13680
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
13676
13681
|
import { join as join20 } from "path";
|
|
13677
13682
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
@@ -13715,7 +13720,7 @@ function dirHasTranscript(root, match, depth) {
|
|
|
13715
13720
|
return false;
|
|
13716
13721
|
let entries;
|
|
13717
13722
|
try {
|
|
13718
|
-
entries =
|
|
13723
|
+
entries = readdirSync15(root, { withFileTypes: true });
|
|
13719
13724
|
} catch {
|
|
13720
13725
|
return false;
|
|
13721
13726
|
}
|
|
@@ -13747,7 +13752,7 @@ function countSessions(dir, tool) {
|
|
|
13747
13752
|
return;
|
|
13748
13753
|
let entries;
|
|
13749
13754
|
try {
|
|
13750
|
-
entries =
|
|
13755
|
+
entries = readdirSync15(d, { withFileTypes: true });
|
|
13751
13756
|
} catch {
|
|
13752
13757
|
return;
|
|
13753
13758
|
}
|
|
@@ -13799,7 +13804,7 @@ function sessionIdsInHome(dir, tool) {
|
|
|
13799
13804
|
return [];
|
|
13800
13805
|
if (tool === "agy") {
|
|
13801
13806
|
try {
|
|
13802
|
-
for (const e of
|
|
13807
|
+
for (const e of readdirSync15(join20(dir, "brain"), { withFileTypes: true })) {
|
|
13803
13808
|
if (e.isDirectory())
|
|
13804
13809
|
out.add(`agy_${e.name}`);
|
|
13805
13810
|
}
|
|
@@ -13809,11 +13814,11 @@ function sessionIdsInHome(dir, tool) {
|
|
|
13809
13814
|
}
|
|
13810
13815
|
if (tool === "cursor") {
|
|
13811
13816
|
try {
|
|
13812
|
-
for (const hash of
|
|
13817
|
+
for (const hash of readdirSync15(join20(dir, "chats"), { withFileTypes: true })) {
|
|
13813
13818
|
if (!hash.isDirectory())
|
|
13814
13819
|
continue;
|
|
13815
13820
|
try {
|
|
13816
|
-
for (const chat of
|
|
13821
|
+
for (const chat of readdirSync15(join20(dir, "chats", hash.name), { withFileTypes: true })) {
|
|
13817
13822
|
if (chat.isDirectory())
|
|
13818
13823
|
out.add(`cursor_${chat.name}`);
|
|
13819
13824
|
}
|
|
@@ -13829,7 +13834,7 @@ function sessionIdsInHome(dir, tool) {
|
|
|
13829
13834
|
return;
|
|
13830
13835
|
let entries;
|
|
13831
13836
|
try {
|
|
13832
|
-
entries =
|
|
13837
|
+
entries = readdirSync15(d, { withFileTypes: true });
|
|
13833
13838
|
} catch {
|
|
13834
13839
|
return;
|
|
13835
13840
|
}
|
|
@@ -13901,7 +13906,7 @@ function runningToolHomes(plat = osPlatform()) {
|
|
|
13901
13906
|
if (plat === "linux") {
|
|
13902
13907
|
let pids;
|
|
13903
13908
|
try {
|
|
13904
|
-
pids =
|
|
13909
|
+
pids = readdirSync15("/proc").filter((p) => /^\d+$/.test(p));
|
|
13905
13910
|
} catch {
|
|
13906
13911
|
return out;
|
|
13907
13912
|
}
|
|
@@ -13981,7 +13986,7 @@ function walkForHomes(dir, depth, visit) {
|
|
|
13981
13986
|
return;
|
|
13982
13987
|
let entries;
|
|
13983
13988
|
try {
|
|
13984
|
-
entries =
|
|
13989
|
+
entries = readdirSync15(dir, { withFileTypes: true });
|
|
13985
13990
|
} catch {
|
|
13986
13991
|
return;
|
|
13987
13992
|
}
|
|
@@ -15657,7 +15662,7 @@ var init_session_source = __esm({
|
|
|
15657
15662
|
});
|
|
15658
15663
|
|
|
15659
15664
|
// ../engine/dist/core/utils.js
|
|
15660
|
-
import { existsSync as existsSync22, readdirSync as
|
|
15665
|
+
import { existsSync as existsSync22, readdirSync as readdirSync16 } from "fs";
|
|
15661
15666
|
import { homedir as homedir6 } from "os";
|
|
15662
15667
|
import { join as join23 } from "path";
|
|
15663
15668
|
function splitByHeaders(markdown) {
|
|
@@ -15708,7 +15713,7 @@ function getClaudeDirs() {
|
|
|
15708
15713
|
}
|
|
15709
15714
|
add(join23(home, ".claude"));
|
|
15710
15715
|
try {
|
|
15711
|
-
const entries =
|
|
15716
|
+
const entries = readdirSync16(home, { withFileTypes: true });
|
|
15712
15717
|
for (const entry of entries) {
|
|
15713
15718
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
15714
15719
|
const candidate = join23(home, entry.name);
|
|
@@ -15738,7 +15743,7 @@ var init_utils = __esm({
|
|
|
15738
15743
|
});
|
|
15739
15744
|
|
|
15740
15745
|
// ../engine/dist/parsers/plan-source.js
|
|
15741
|
-
import { existsSync as existsSync23, readdirSync as
|
|
15746
|
+
import { existsSync as existsSync23, readdirSync as readdirSync17, readFileSync as readFileSync16, statSync as statSync21 } from "fs";
|
|
15742
15747
|
import { homedir as homedir7 } from "os";
|
|
15743
15748
|
import { join as join24, basename as basename13 } from "path";
|
|
15744
15749
|
import { createHash as createHash9 } from "crypto";
|
|
@@ -15765,7 +15770,7 @@ function parseFrontmatter(content) {
|
|
|
15765
15770
|
}
|
|
15766
15771
|
function safeReaddir(dir) {
|
|
15767
15772
|
try {
|
|
15768
|
-
return
|
|
15773
|
+
return readdirSync17(dir);
|
|
15769
15774
|
} catch {
|
|
15770
15775
|
return [];
|
|
15771
15776
|
}
|
|
@@ -15801,11 +15806,11 @@ var init_plan_source = __esm({
|
|
|
15801
15806
|
if (!existsSync23(projectsDir))
|
|
15802
15807
|
return this._knownProjectDirs;
|
|
15803
15808
|
try {
|
|
15804
|
-
const entries =
|
|
15809
|
+
const entries = readdirSync17(projectsDir, { withFileTypes: true });
|
|
15805
15810
|
for (const entry of entries) {
|
|
15806
15811
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
15807
15812
|
continue;
|
|
15808
|
-
const projectPath =
|
|
15813
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
15809
15814
|
if (existsSync23(projectPath)) {
|
|
15810
15815
|
this._knownProjectDirs.push(projectPath);
|
|
15811
15816
|
}
|
|
@@ -15833,7 +15838,7 @@ var init_plan_source = __esm({
|
|
|
15833
15838
|
for (const plansDir of this.plansDirs) {
|
|
15834
15839
|
if (!existsSync23(plansDir))
|
|
15835
15840
|
continue;
|
|
15836
|
-
const files =
|
|
15841
|
+
const files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
|
|
15837
15842
|
for (const file of files) {
|
|
15838
15843
|
if (seenClaude.has(file))
|
|
15839
15844
|
continue;
|
|
@@ -15877,7 +15882,7 @@ var init_plan_source = __esm({
|
|
|
15877
15882
|
return;
|
|
15878
15883
|
let files;
|
|
15879
15884
|
try {
|
|
15880
|
-
files =
|
|
15885
|
+
files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
|
|
15881
15886
|
} catch {
|
|
15882
15887
|
return;
|
|
15883
15888
|
}
|
|
@@ -15924,7 +15929,7 @@ var init_plan_source = __esm({
|
|
|
15924
15929
|
}
|
|
15925
15930
|
let projDirs;
|
|
15926
15931
|
try {
|
|
15927
|
-
projDirs =
|
|
15932
|
+
projDirs = readdirSync17(tmpRoot);
|
|
15928
15933
|
} catch {
|
|
15929
15934
|
return;
|
|
15930
15935
|
}
|
|
@@ -15933,7 +15938,7 @@ var init_plan_source = __esm({
|
|
|
15933
15938
|
const projRoot = join24(tmpRoot, projDir);
|
|
15934
15939
|
let sessions;
|
|
15935
15940
|
try {
|
|
15936
|
-
sessions =
|
|
15941
|
+
sessions = readdirSync17(projRoot);
|
|
15937
15942
|
} catch {
|
|
15938
15943
|
continue;
|
|
15939
15944
|
}
|
|
@@ -15943,7 +15948,7 @@ var init_plan_source = __esm({
|
|
|
15943
15948
|
continue;
|
|
15944
15949
|
let files;
|
|
15945
15950
|
try {
|
|
15946
|
-
files =
|
|
15951
|
+
files = readdirSync17(plansDir).filter((f) => f.endsWith(".md"));
|
|
15947
15952
|
} catch {
|
|
15948
15953
|
continue;
|
|
15949
15954
|
}
|
|
@@ -16152,7 +16157,7 @@ var init_plan_source = __esm({
|
|
|
16152
16157
|
return;
|
|
16153
16158
|
let sessionDirs;
|
|
16154
16159
|
try {
|
|
16155
|
-
sessionDirs =
|
|
16160
|
+
sessionDirs = readdirSync17(brainDir);
|
|
16156
16161
|
} catch {
|
|
16157
16162
|
return;
|
|
16158
16163
|
}
|
|
@@ -16166,7 +16171,7 @@ var init_plan_source = __esm({
|
|
|
16166
16171
|
}
|
|
16167
16172
|
let files;
|
|
16168
16173
|
try {
|
|
16169
|
-
files =
|
|
16174
|
+
files = readdirSync17(sessionPath).filter((f) => f.endsWith(".md"));
|
|
16170
16175
|
} catch {
|
|
16171
16176
|
continue;
|
|
16172
16177
|
}
|
|
@@ -16203,7 +16208,7 @@ var init_plan_source = __esm({
|
|
|
16203
16208
|
});
|
|
16204
16209
|
|
|
16205
16210
|
// ../engine/dist/parsers/task-source.js
|
|
16206
|
-
import { existsSync as existsSync24, readdirSync as
|
|
16211
|
+
import { existsSync as existsSync24, readdirSync as readdirSync18, readFileSync as readFileSync17, statSync as statSync22 } from "fs";
|
|
16207
16212
|
import { join as join25 } from "path";
|
|
16208
16213
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
16209
16214
|
var init_task_source = __esm({
|
|
@@ -16237,7 +16242,7 @@ var init_task_source = __esm({
|
|
|
16237
16242
|
return;
|
|
16238
16243
|
let files;
|
|
16239
16244
|
try {
|
|
16240
|
-
files =
|
|
16245
|
+
files = readdirSync18(todosDir).filter((f) => f.endsWith(".json"));
|
|
16241
16246
|
} catch {
|
|
16242
16247
|
return;
|
|
16243
16248
|
}
|
|
@@ -16286,7 +16291,7 @@ var init_task_source = __esm({
|
|
|
16286
16291
|
async *discoverInDir(tasksDir) {
|
|
16287
16292
|
if (!existsSync24(tasksDir))
|
|
16288
16293
|
return;
|
|
16289
|
-
const entries =
|
|
16294
|
+
const entries = readdirSync18(tasksDir, { withFileTypes: true });
|
|
16290
16295
|
for (const entry of entries) {
|
|
16291
16296
|
if (!entry.isDirectory())
|
|
16292
16297
|
continue;
|
|
@@ -16294,7 +16299,7 @@ var init_task_source = __esm({
|
|
|
16294
16299
|
const taskDir = join25(tasksDir, sessionUuid);
|
|
16295
16300
|
try {
|
|
16296
16301
|
const stat3 = statSync22(taskDir);
|
|
16297
|
-
const taskFiles =
|
|
16302
|
+
const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
|
|
16298
16303
|
if (taskFiles.length === 0)
|
|
16299
16304
|
continue;
|
|
16300
16305
|
const tasks2 = this.readTasks(taskDir, taskFiles);
|
|
@@ -16328,7 +16333,7 @@ var init_task_source = __esm({
|
|
|
16328
16333
|
const taskDir = item.filePath;
|
|
16329
16334
|
if (!existsSync24(taskDir))
|
|
16330
16335
|
return [];
|
|
16331
|
-
const taskFiles =
|
|
16336
|
+
const taskFiles = readdirSync18(taskDir).filter((f) => f.endsWith(".json"));
|
|
16332
16337
|
const tasks2 = this.readTasks(taskDir, taskFiles);
|
|
16333
16338
|
if (tasks2.length === 0)
|
|
16334
16339
|
return [];
|
|
@@ -16439,7 +16444,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
16439
16444
|
});
|
|
16440
16445
|
|
|
16441
16446
|
// ../engine/dist/parsers/claude-md-source.js
|
|
16442
|
-
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";
|
|
16443
16448
|
import { homedir as homedir8 } from "os";
|
|
16444
16449
|
import { join as join26, basename as basename14, dirname as dirname14 } from "path";
|
|
16445
16450
|
import { createHash as createHash10 } from "crypto";
|
|
@@ -16456,11 +16461,11 @@ function discoverProjectDirs(claudeDir) {
|
|
|
16456
16461
|
if (!existsSync25(projectsDir))
|
|
16457
16462
|
return;
|
|
16458
16463
|
try {
|
|
16459
|
-
const entries =
|
|
16464
|
+
const entries = readdirSync19(projectsDir, { withFileTypes: true });
|
|
16460
16465
|
for (const entry of entries) {
|
|
16461
16466
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16462
16467
|
continue;
|
|
16463
|
-
const projectPath =
|
|
16468
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
16464
16469
|
addProject(projectPath);
|
|
16465
16470
|
}
|
|
16466
16471
|
} catch {
|
|
@@ -16473,7 +16478,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
16473
16478
|
const home = homedir8();
|
|
16474
16479
|
scanProjectsDir(claudeBackend.projectsDir());
|
|
16475
16480
|
try {
|
|
16476
|
-
for (const entry of
|
|
16481
|
+
for (const entry of readdirSync19(home, { withFileTypes: true })) {
|
|
16477
16482
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
16478
16483
|
scanProjectsDir(join26(home, entry.name, "projects"));
|
|
16479
16484
|
}
|
|
@@ -16575,7 +16580,7 @@ var init_claude_md_source = __esm({
|
|
|
16575
16580
|
}
|
|
16576
16581
|
}
|
|
16577
16582
|
try {
|
|
16578
|
-
const entries =
|
|
16583
|
+
const entries = readdirSync19(searchDir, { withFileTypes: true });
|
|
16579
16584
|
for (const entry of entries) {
|
|
16580
16585
|
if (!entry.isDirectory())
|
|
16581
16586
|
continue;
|
|
@@ -16665,7 +16670,7 @@ var init_claude_md_source = __esm({
|
|
|
16665
16670
|
});
|
|
16666
16671
|
|
|
16667
16672
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
16668
|
-
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";
|
|
16669
16674
|
import { homedir as homedir9 } from "os";
|
|
16670
16675
|
import { join as join27, basename as basename15 } from "path";
|
|
16671
16676
|
function parseFrontmatter2(content) {
|
|
@@ -16693,7 +16698,7 @@ function parseFrontmatter2(content) {
|
|
|
16693
16698
|
return { fm, body };
|
|
16694
16699
|
}
|
|
16695
16700
|
function projectHashToPath(hashDir) {
|
|
16696
|
-
return
|
|
16701
|
+
return resolveProjectDirName(hashDir);
|
|
16697
16702
|
}
|
|
16698
16703
|
function discoverMemoryDirs() {
|
|
16699
16704
|
const out = [];
|
|
@@ -16707,7 +16712,7 @@ function discoverMemoryDirs() {
|
|
|
16707
16712
|
const home = homedir9();
|
|
16708
16713
|
const claudeRoots = [claudeBackend.projectsDir()];
|
|
16709
16714
|
try {
|
|
16710
|
-
for (const entry of
|
|
16715
|
+
for (const entry of readdirSync20(home, { withFileTypes: true })) {
|
|
16711
16716
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
16712
16717
|
claudeRoots.push(join27(home, entry.name, "projects"));
|
|
16713
16718
|
}
|
|
@@ -16718,7 +16723,7 @@ function discoverMemoryDirs() {
|
|
|
16718
16723
|
if (!existsSync26(projectsDir))
|
|
16719
16724
|
continue;
|
|
16720
16725
|
try {
|
|
16721
|
-
for (const entry of
|
|
16726
|
+
for (const entry of readdirSync20(projectsDir, { withFileTypes: true })) {
|
|
16722
16727
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
16723
16728
|
continue;
|
|
16724
16729
|
add(join27(projectsDir, entry.name, "memory"), entry.name);
|
|
@@ -16747,7 +16752,7 @@ var init_agent_memory_source = __esm({
|
|
|
16747
16752
|
for (const { memoryDir, projectHash } of discoverMemoryDirs()) {
|
|
16748
16753
|
const projectPath = projectHashToPath(projectHash);
|
|
16749
16754
|
try {
|
|
16750
|
-
for (const entry of
|
|
16755
|
+
for (const entry of readdirSync20(memoryDir, { withFileTypes: true })) {
|
|
16751
16756
|
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
16752
16757
|
continue;
|
|
16753
16758
|
const filePath = join27(memoryDir, entry.name);
|
|
@@ -16850,7 +16855,7 @@ var init_agent_memory_source = __esm({
|
|
|
16850
16855
|
});
|
|
16851
16856
|
|
|
16852
16857
|
// ../engine/dist/parsers/history-source.js
|
|
16853
|
-
import { existsSync as existsSync27, readdirSync as
|
|
16858
|
+
import { existsSync as existsSync27, readdirSync as readdirSync21, statSync as statSync25 } from "fs";
|
|
16854
16859
|
import { createReadStream as createReadStream3 } from "fs";
|
|
16855
16860
|
import { createInterface as createInterface2 } from "readline";
|
|
16856
16861
|
import { homedir as homedir10 } from "os";
|
|
@@ -16877,7 +16882,7 @@ var init_history_source = __esm({
|
|
|
16877
16882
|
};
|
|
16878
16883
|
tryAdd(claudeBackend.historyFile());
|
|
16879
16884
|
try {
|
|
16880
|
-
for (const entry of
|
|
16885
|
+
for (const entry of readdirSync21(home, { withFileTypes: true })) {
|
|
16881
16886
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
16882
16887
|
tryAdd(join28(home, entry.name, "history.jsonl"));
|
|
16883
16888
|
}
|
|
@@ -17034,7 +17039,7 @@ var init_history_source = __esm({
|
|
|
17034
17039
|
});
|
|
17035
17040
|
|
|
17036
17041
|
// ../engine/dist/parsers/paste-source.js
|
|
17037
|
-
import { existsSync as existsSync28, readdirSync as
|
|
17042
|
+
import { existsSync as existsSync28, readdirSync as readdirSync22, readFileSync as readFileSync20, statSync as statSync26 } from "fs";
|
|
17038
17043
|
import { homedir as homedir11 } from "os";
|
|
17039
17044
|
import { join as join29, basename as basename16 } from "path";
|
|
17040
17045
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
@@ -17060,7 +17065,7 @@ var init_paste_source = __esm({
|
|
|
17060
17065
|
};
|
|
17061
17066
|
tryAdd(claudeBackend.pasteCacheDir());
|
|
17062
17067
|
try {
|
|
17063
|
-
for (const entry of
|
|
17068
|
+
for (const entry of readdirSync22(home, { withFileTypes: true })) {
|
|
17064
17069
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
17065
17070
|
tryAdd(join29(home, entry.name, "paste-cache"));
|
|
17066
17071
|
}
|
|
@@ -17077,7 +17082,7 @@ var init_paste_source = __esm({
|
|
|
17077
17082
|
for (const cacheDir of this.cacheDirs) {
|
|
17078
17083
|
if (!existsSync28(cacheDir))
|
|
17079
17084
|
continue;
|
|
17080
|
-
const files =
|
|
17085
|
+
const files = readdirSync22(cacheDir).filter((f) => f.endsWith(".txt"));
|
|
17081
17086
|
for (const file of files) {
|
|
17082
17087
|
if (seen.has(file))
|
|
17083
17088
|
continue;
|
|
@@ -17134,7 +17139,7 @@ var init_paste_source = __esm({
|
|
|
17134
17139
|
});
|
|
17135
17140
|
|
|
17136
17141
|
// ../engine/dist/parsers/gemini-source.js
|
|
17137
|
-
import { existsSync as existsSync29, readdirSync as
|
|
17142
|
+
import { existsSync as existsSync29, readdirSync as readdirSync23, readFileSync as readFileSync21, statSync as statSync27 } from "fs";
|
|
17138
17143
|
import { join as join30, basename as basename17 } from "path";
|
|
17139
17144
|
import { createHash as createHash11 } from "crypto";
|
|
17140
17145
|
function loadGeminiProjectMap2() {
|
|
@@ -17176,13 +17181,13 @@ var init_gemini_source = __esm({
|
|
|
17176
17181
|
return;
|
|
17177
17182
|
const seen = /* @__PURE__ */ new Set();
|
|
17178
17183
|
try {
|
|
17179
|
-
for (const projectDirEntry of
|
|
17184
|
+
for (const projectDirEntry of readdirSync23(tmpDir, { withFileTypes: true })) {
|
|
17180
17185
|
if (!projectDirEntry.isDirectory())
|
|
17181
17186
|
continue;
|
|
17182
17187
|
const chatsDir = join30(tmpDir, projectDirEntry.name, "chats");
|
|
17183
17188
|
if (!existsSync29(chatsDir))
|
|
17184
17189
|
continue;
|
|
17185
|
-
for (const file of
|
|
17190
|
+
for (const file of readdirSync23(chatsDir)) {
|
|
17186
17191
|
if (!file.endsWith(".json") || !file.startsWith("session-"))
|
|
17187
17192
|
continue;
|
|
17188
17193
|
const filePath = join30(chatsDir, file);
|
|
@@ -17317,7 +17322,7 @@ var init_gemini_source = __esm({
|
|
|
17317
17322
|
});
|
|
17318
17323
|
|
|
17319
17324
|
// ../engine/dist/parsers/gemini-brain-source.js
|
|
17320
|
-
import { existsSync as existsSync30, readdirSync as
|
|
17325
|
+
import { existsSync as existsSync30, readdirSync as readdirSync24, readFileSync as readFileSync22, statSync as statSync28 } from "fs";
|
|
17321
17326
|
import { join as join31 } from "path";
|
|
17322
17327
|
var MAX_CHUNK_CHARS8, GeminiBrainSource;
|
|
17323
17328
|
var init_gemini_brain_source = __esm({
|
|
@@ -17338,12 +17343,12 @@ var init_gemini_brain_source = __esm({
|
|
|
17338
17343
|
return;
|
|
17339
17344
|
if (!existsSync30(this.brainDir))
|
|
17340
17345
|
return;
|
|
17341
|
-
const sessions =
|
|
17346
|
+
const sessions = readdirSync24(this.brainDir, { withFileTypes: true });
|
|
17342
17347
|
for (const entry of sessions) {
|
|
17343
17348
|
if (!entry.isDirectory())
|
|
17344
17349
|
continue;
|
|
17345
17350
|
const sessionDir = join31(this.brainDir, entry.name);
|
|
17346
|
-
const files =
|
|
17351
|
+
const files = readdirSync24(sessionDir).filter((f) => f.endsWith(".md") && !f.includes(".resolved") && !f.includes(".metadata"));
|
|
17347
17352
|
if (files.length === 0)
|
|
17348
17353
|
continue;
|
|
17349
17354
|
for (const file of files) {
|
|
@@ -17731,7 +17736,7 @@ var init_opencode_todo_source = __esm({
|
|
|
17731
17736
|
});
|
|
17732
17737
|
|
|
17733
17738
|
// ../engine/dist/parsers/codex-session-source.js
|
|
17734
|
-
import { existsSync as existsSync33, readdirSync as
|
|
17739
|
+
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as readFileSync23, statSync as statSync29 } from "fs";
|
|
17735
17740
|
import { join as join32, basename as basename18 } from "path";
|
|
17736
17741
|
function getCodexSessionsDir() {
|
|
17737
17742
|
return codexBackend.sessionsDir();
|
|
@@ -17952,7 +17957,7 @@ var init_codex_session_source = __esm({
|
|
|
17952
17957
|
const results = [];
|
|
17953
17958
|
if (!existsSync33(dir))
|
|
17954
17959
|
return results;
|
|
17955
|
-
for (const entry of
|
|
17960
|
+
for (const entry of readdirSync25(dir, { withFileTypes: true })) {
|
|
17956
17961
|
const fullPath = join32(dir, entry.name);
|
|
17957
17962
|
if (entry.isDirectory()) {
|
|
17958
17963
|
results.push(...this.collectJsonlFiles(fullPath));
|
|
@@ -17967,7 +17972,7 @@ var init_codex_session_source = __esm({
|
|
|
17967
17972
|
});
|
|
17968
17973
|
|
|
17969
17974
|
// ../engine/dist/parsers/diary-source.js
|
|
17970
|
-
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";
|
|
17971
17976
|
import { join as join33, basename as basename19 } from "path";
|
|
17972
17977
|
var MAX_CHUNK_CHARS11, DiarySource;
|
|
17973
17978
|
var init_diary_source = __esm({
|
|
@@ -17985,10 +17990,10 @@ var init_diary_source = __esm({
|
|
|
17985
17990
|
async *discover() {
|
|
17986
17991
|
if (!existsSync34(this.diaryDir))
|
|
17987
17992
|
return;
|
|
17988
|
-
const agents =
|
|
17993
|
+
const agents = readdirSync26(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
17989
17994
|
for (const agentDir of agents) {
|
|
17990
17995
|
const agentPath2 = join33(this.diaryDir, agentDir.name);
|
|
17991
|
-
const files =
|
|
17996
|
+
const files = readdirSync26(agentPath2).filter((f) => f.endsWith(".json"));
|
|
17992
17997
|
for (const file of files) {
|
|
17993
17998
|
const filePath = join33(agentPath2, file);
|
|
17994
17999
|
try {
|
|
@@ -18079,7 +18084,7 @@ var init_diary_source = __esm({
|
|
|
18079
18084
|
const agentDir = join33(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
18080
18085
|
if (!existsSync34(agentDir))
|
|
18081
18086
|
return [];
|
|
18082
|
-
const files =
|
|
18087
|
+
const files = readdirSync26(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
|
|
18083
18088
|
const entries = [];
|
|
18084
18089
|
for (const file of files) {
|
|
18085
18090
|
try {
|
|
@@ -18128,7 +18133,7 @@ var init_redact_inline = __esm({
|
|
|
18128
18133
|
});
|
|
18129
18134
|
|
|
18130
18135
|
// ../engine/dist/parsers/skills-source.js
|
|
18131
|
-
import { existsSync as existsSync35, readdirSync as
|
|
18136
|
+
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as readFileSync25, statSync as statSync31 } from "fs";
|
|
18132
18137
|
import { homedir as homedir12 } from "os";
|
|
18133
18138
|
import { join as join34 } from "path";
|
|
18134
18139
|
function rebuildBody(content) {
|
|
@@ -18209,7 +18214,7 @@ var init_skills_source = __esm({
|
|
|
18209
18214
|
return;
|
|
18210
18215
|
const codexPluginsDir = codexBackend.pluginsDir();
|
|
18211
18216
|
if (existsSync35(codexPluginsDir)) {
|
|
18212
|
-
for (const pluginName of
|
|
18217
|
+
for (const pluginName of readdirSync27(codexPluginsDir)) {
|
|
18213
18218
|
const skillsDir = join34(codexPluginsDir, pluginName, "skills");
|
|
18214
18219
|
if (!existsSync35(skillsDir))
|
|
18215
18220
|
continue;
|
|
@@ -18220,7 +18225,7 @@ var init_skills_source = __esm({
|
|
|
18220
18225
|
async *fromSkillRoot(root, pluginName) {
|
|
18221
18226
|
let entries;
|
|
18222
18227
|
try {
|
|
18223
|
-
entries =
|
|
18228
|
+
entries = readdirSync27(root.path);
|
|
18224
18229
|
} catch {
|
|
18225
18230
|
return;
|
|
18226
18231
|
}
|
|
@@ -18254,14 +18259,14 @@ var init_skills_source = __esm({
|
|
|
18254
18259
|
}
|
|
18255
18260
|
const subdirs = {};
|
|
18256
18261
|
try {
|
|
18257
|
-
for (const sub of
|
|
18262
|
+
for (const sub of readdirSync27(skillDir)) {
|
|
18258
18263
|
const subPath = join34(skillDir, sub);
|
|
18259
18264
|
try {
|
|
18260
18265
|
const ss = statSync31(subPath);
|
|
18261
18266
|
if (ss.isDirectory()) {
|
|
18262
18267
|
let count = 0;
|
|
18263
18268
|
try {
|
|
18264
|
-
count =
|
|
18269
|
+
count = readdirSync27(subPath).length;
|
|
18265
18270
|
} catch {
|
|
18266
18271
|
}
|
|
18267
18272
|
subdirs[sub] = count;
|
|
@@ -18327,7 +18332,7 @@ var init_skills_source = __esm({
|
|
|
18327
18332
|
});
|
|
18328
18333
|
|
|
18329
18334
|
// ../engine/dist/parsers/mcps-source.js
|
|
18330
|
-
import { existsSync as existsSync36, readdirSync as
|
|
18335
|
+
import { existsSync as existsSync36, readdirSync as readdirSync28, readFileSync as readFileSync26, statSync as statSync32 } from "fs";
|
|
18331
18336
|
import { homedir as homedir13 } from "os";
|
|
18332
18337
|
import { join as join35 } from "path";
|
|
18333
18338
|
function readJson(path) {
|
|
@@ -18441,7 +18446,7 @@ var init_mcps_source = __esm({
|
|
|
18441
18446
|
yield* this.fromCodexToml(codexBackend.configToml());
|
|
18442
18447
|
const pluginsDir = codexBackend.pluginsDir();
|
|
18443
18448
|
if (existsSync36(pluginsDir)) {
|
|
18444
|
-
for (const plugin of
|
|
18449
|
+
for (const plugin of readdirSync28(pluginsDir)) {
|
|
18445
18450
|
const mcpPath = join35(pluginsDir, plugin, ".mcp.json");
|
|
18446
18451
|
yield* this.fromObject(readJson(mcpPath)?.mcpServers, {
|
|
18447
18452
|
tool: "codex",
|
|
@@ -18665,7 +18670,7 @@ var init_toolkit_format = __esm({
|
|
|
18665
18670
|
});
|
|
18666
18671
|
|
|
18667
18672
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
18668
|
-
import { existsSync as existsSync37, readdirSync as
|
|
18673
|
+
import { existsSync as existsSync37, readdirSync as readdirSync29, readFileSync as readFileSync27, statSync as statSync33 } from "fs";
|
|
18669
18674
|
import { join as join36, basename as basename20 } from "path";
|
|
18670
18675
|
function rebuildBody2(content) {
|
|
18671
18676
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -18720,10 +18725,10 @@ var init_slash_commands_source = __esm({
|
|
|
18720
18725
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18721
18726
|
if (existsSync37(projectsRoot)) {
|
|
18722
18727
|
try {
|
|
18723
|
-
for (const entry of
|
|
18728
|
+
for (const entry of readdirSync29(projectsRoot, { withFileTypes: true })) {
|
|
18724
18729
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18725
18730
|
continue;
|
|
18726
|
-
const projectPath =
|
|
18731
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
18727
18732
|
const cmdDir = join36(projectPath, ".claude", "commands");
|
|
18728
18733
|
if (existsSync37(cmdDir))
|
|
18729
18734
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -18751,7 +18756,7 @@ var init_slash_commands_source = __esm({
|
|
|
18751
18756
|
const ext = root.format === "toml" ? ".toml" : ".md";
|
|
18752
18757
|
let files;
|
|
18753
18758
|
try {
|
|
18754
|
-
files =
|
|
18759
|
+
files = readdirSync29(root.path).filter((f) => f.endsWith(ext));
|
|
18755
18760
|
} catch {
|
|
18756
18761
|
continue;
|
|
18757
18762
|
}
|
|
@@ -18811,7 +18816,7 @@ var init_slash_commands_source = __esm({
|
|
|
18811
18816
|
});
|
|
18812
18817
|
|
|
18813
18818
|
// ../engine/dist/parsers/subagents-source.js
|
|
18814
|
-
import { existsSync as existsSync38, readdirSync as
|
|
18819
|
+
import { existsSync as existsSync38, readdirSync as readdirSync30, readFileSync as readFileSync28, statSync as statSync34 } from "fs";
|
|
18815
18820
|
import { join as join37, basename as basename21 } from "path";
|
|
18816
18821
|
function rebuildBody3(content) {
|
|
18817
18822
|
const { text, redacted } = redactInlineSecrets(content);
|
|
@@ -18868,10 +18873,10 @@ var init_subagents_source = __esm({
|
|
|
18868
18873
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18869
18874
|
if (existsSync38(projectsRoot)) {
|
|
18870
18875
|
try {
|
|
18871
|
-
for (const entry of
|
|
18876
|
+
for (const entry of readdirSync30(projectsRoot, { withFileTypes: true })) {
|
|
18872
18877
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18873
18878
|
continue;
|
|
18874
|
-
const projectPath =
|
|
18879
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
18875
18880
|
const agentDir = join37(projectPath, ".claude", "agents");
|
|
18876
18881
|
if (existsSync38(agentDir))
|
|
18877
18882
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
@@ -18899,7 +18904,7 @@ var init_subagents_source = __esm({
|
|
|
18899
18904
|
const ext = root.format === "toml" ? ".toml" : ".md";
|
|
18900
18905
|
let files;
|
|
18901
18906
|
try {
|
|
18902
|
-
files =
|
|
18907
|
+
files = readdirSync30(root.path).filter((f) => f.endsWith(ext));
|
|
18903
18908
|
} catch {
|
|
18904
18909
|
continue;
|
|
18905
18910
|
}
|
|
@@ -18960,7 +18965,7 @@ var init_subagents_source = __esm({
|
|
|
18960
18965
|
});
|
|
18961
18966
|
|
|
18962
18967
|
// ../engine/dist/parsers/hooks-source.js
|
|
18963
|
-
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";
|
|
18964
18969
|
import { join as join38 } from "path";
|
|
18965
18970
|
function readJson2(path) {
|
|
18966
18971
|
if (!existsSync39(path))
|
|
@@ -18987,10 +18992,10 @@ var init_hooks_source = __esm({
|
|
|
18987
18992
|
const projectsRoot = claudeBackend.projectsDir();
|
|
18988
18993
|
if (existsSync39(projectsRoot)) {
|
|
18989
18994
|
try {
|
|
18990
|
-
for (const entry of
|
|
18995
|
+
for (const entry of readdirSync31(projectsRoot, { withFileTypes: true })) {
|
|
18991
18996
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
18992
18997
|
continue;
|
|
18993
|
-
const projectPath =
|
|
18998
|
+
const projectPath = resolveProjectDirName(entry.name);
|
|
18994
18999
|
const settingsPath2 = join38(projectPath, ".claude", "settings.json");
|
|
18995
19000
|
if (existsSync39(settingsPath2)) {
|
|
18996
19001
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
@@ -19083,7 +19088,7 @@ var init_hooks_source = __esm({
|
|
|
19083
19088
|
});
|
|
19084
19089
|
|
|
19085
19090
|
// ../engine/dist/parsers/plugins-source.js
|
|
19086
|
-
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";
|
|
19087
19092
|
import { homedir as homedir14 } from "os";
|
|
19088
19093
|
import { join as join39 } from "path";
|
|
19089
19094
|
function readJson3(path) {
|
|
@@ -19145,7 +19150,7 @@ var init_plugins_source = __esm({
|
|
|
19145
19150
|
if (isSourceEnabled("gemini", "extensions") && existsSync40(gemRoot)) {
|
|
19146
19151
|
let entries;
|
|
19147
19152
|
try {
|
|
19148
|
-
entries =
|
|
19153
|
+
entries = readdirSync32(gemRoot);
|
|
19149
19154
|
} catch {
|
|
19150
19155
|
entries = [];
|
|
19151
19156
|
}
|
|
@@ -19193,7 +19198,7 @@ var init_plugins_source = __esm({
|
|
|
19193
19198
|
if (isSourceEnabled("codex", "plugins") && existsSync40(codexPluginsRoot)) {
|
|
19194
19199
|
let entries;
|
|
19195
19200
|
try {
|
|
19196
|
-
entries =
|
|
19201
|
+
entries = readdirSync32(codexPluginsRoot);
|
|
19197
19202
|
} catch {
|
|
19198
19203
|
entries = [];
|
|
19199
19204
|
}
|
|
@@ -19489,13 +19494,13 @@ function markSynced(server, rows) {
|
|
|
19489
19494
|
const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
|
|
19490
19495
|
const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
|
|
19491
19496
|
const ev = extractorVersionForId(r.id);
|
|
19492
|
-
const
|
|
19497
|
+
const base3 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
|
|
19493
19498
|
if (o > 0 || s > 0) {
|
|
19494
|
-
|
|
19495
|
-
|
|
19499
|
+
base3.o = o;
|
|
19500
|
+
base3.s = s;
|
|
19496
19501
|
}
|
|
19497
|
-
if (r.hash !== void 0)
|
|
19498
|
-
forServer[r.id] =
|
|
19502
|
+
if (r.hash !== void 0) base3.h = r.hash;
|
|
19503
|
+
forServer[r.id] = base3;
|
|
19499
19504
|
}
|
|
19500
19505
|
persist(data);
|
|
19501
19506
|
}
|
|
@@ -19737,7 +19742,7 @@ var init_http = __esm({
|
|
|
19737
19742
|
CLI_VERSION = JSON.parse(readFileSync33(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19738
19743
|
} catch {
|
|
19739
19744
|
try {
|
|
19740
|
-
if (true) CLI_VERSION = "0.5.
|
|
19745
|
+
if (true) CLI_VERSION = "0.5.32";
|
|
19741
19746
|
} catch {
|
|
19742
19747
|
}
|
|
19743
19748
|
}
|
|
@@ -20257,7 +20262,7 @@ var init_telemetry = __esm({
|
|
|
20257
20262
|
init_sync_client();
|
|
20258
20263
|
cliVersion2 = () => {
|
|
20259
20264
|
try {
|
|
20260
|
-
return true ? "0.5.
|
|
20265
|
+
return true ? "0.5.32" : "dev";
|
|
20261
20266
|
} catch {
|
|
20262
20267
|
return "dev";
|
|
20263
20268
|
}
|
|
@@ -20394,11 +20399,11 @@ __export(server_probe_exports, {
|
|
|
20394
20399
|
function probeOk(r) {
|
|
20395
20400
|
return r.kind === "ok" && r.apiVersion >= 2;
|
|
20396
20401
|
}
|
|
20397
|
-
async function probeServer(
|
|
20402
|
+
async function probeServer(base3, opts = {}) {
|
|
20398
20403
|
const f = opts.fetchImpl || fetch;
|
|
20399
20404
|
let res;
|
|
20400
20405
|
try {
|
|
20401
|
-
res = await f(`${
|
|
20406
|
+
res = await f(`${base3.replace(/\/+$/, "")}/api/capabilities`, {
|
|
20402
20407
|
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
20403
20408
|
});
|
|
20404
20409
|
} catch (err) {
|
|
@@ -20435,34 +20440,34 @@ async function probeServer(base2, opts = {}) {
|
|
|
20435
20440
|
raw: parsed
|
|
20436
20441
|
};
|
|
20437
20442
|
}
|
|
20438
|
-
function probeAdvice(r,
|
|
20443
|
+
function probeAdvice(r, base3) {
|
|
20439
20444
|
switch (r.kind) {
|
|
20440
20445
|
case "ok":
|
|
20441
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`;
|
|
20442
20447
|
case "moved":
|
|
20443
|
-
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>\``;
|
|
20444
20449
|
case "unauthorized":
|
|
20445
|
-
return `HTTP ${r.status} \u2014 ${
|
|
20450
|
+
return `HTTP ${r.status} \u2014 ${base3} rejected the credential. Re-login: \`chat-recall login ` + base3 + "`";
|
|
20446
20451
|
case "server_error":
|
|
20447
|
-
return `HTTP ${r.status} \u2014 ${
|
|
20452
|
+
return `HTTP ${r.status} \u2014 ${base3} is up but failing. Nothing to fix locally; check the server.`;
|
|
20448
20453
|
case "not_api":
|
|
20449
|
-
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`;
|
|
20450
20455
|
case "unreachable":
|
|
20451
20456
|
switch (r.reason) {
|
|
20452
20457
|
case "dns":
|
|
20453
|
-
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`;
|
|
20454
20459
|
case "refused":
|
|
20455
|
-
return `${
|
|
20460
|
+
return `${base3} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
|
|
20456
20461
|
case "tls":
|
|
20457
|
-
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.`;
|
|
20458
20463
|
case "timeout":
|
|
20459
|
-
return `${
|
|
20464
|
+
return `${base3} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
|
|
20460
20465
|
case "reset":
|
|
20461
|
-
return `the connection to ${
|
|
20466
|
+
return `the connection to ${base3} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
|
|
20462
20467
|
case "bad_port":
|
|
20463
|
-
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`;
|
|
20464
20469
|
default:
|
|
20465
|
-
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`;
|
|
20466
20471
|
}
|
|
20467
20472
|
}
|
|
20468
20473
|
}
|
|
@@ -20495,8 +20500,8 @@ function describeCause(err) {
|
|
|
20495
20500
|
const code2 = e.code;
|
|
20496
20501
|
if (typeof code2 === "string" && code2 && !parts.includes(code2)) parts.push(code2);
|
|
20497
20502
|
}
|
|
20498
|
-
const
|
|
20499
|
-
return parts.length ? `${
|
|
20503
|
+
const base3 = err instanceof Error ? err.message : String(err);
|
|
20504
|
+
return parts.length ? `${base3}: ${parts.join(" \u2192 ")}` : base3;
|
|
20500
20505
|
}
|
|
20501
20506
|
function describeUnreachable(err) {
|
|
20502
20507
|
const reason = classifyUnreachable(err);
|
|
@@ -20600,7 +20605,7 @@ __export(auto_update_exports, {
|
|
|
20600
20605
|
import { execSync as execSync2 } from "node:child_process";
|
|
20601
20606
|
import { readFileSync as readFileSync36 } from "node:fs";
|
|
20602
20607
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20603
|
-
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";
|
|
20604
20609
|
import { join as join43, dirname as dirname18, sep as sep2 } from "node:path";
|
|
20605
20610
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
20606
20611
|
import { createHash as createHash12 } from "node:crypto";
|
|
@@ -20632,12 +20637,12 @@ function installedVersion() {
|
|
|
20632
20637
|
return null;
|
|
20633
20638
|
}
|
|
20634
20639
|
}
|
|
20635
|
-
function planAutoUpdate(
|
|
20640
|
+
function planAutoUpdate(base3, caps, ownVersion3, flag) {
|
|
20636
20641
|
const rel = caps.cli;
|
|
20637
20642
|
if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
|
|
20638
20643
|
if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
|
|
20639
20644
|
if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
|
|
20640
|
-
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 };
|
|
20641
20646
|
}
|
|
20642
20647
|
function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
20643
20648
|
const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
|
|
@@ -20645,7 +20650,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
|
20645
20650
|
let removed = 0;
|
|
20646
20651
|
let entries;
|
|
20647
20652
|
try {
|
|
20648
|
-
entries =
|
|
20653
|
+
entries = readdirSync33(root);
|
|
20649
20654
|
} catch {
|
|
20650
20655
|
return 0;
|
|
20651
20656
|
}
|
|
@@ -20655,7 +20660,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
|
20655
20660
|
try {
|
|
20656
20661
|
const st = statSync38(dir);
|
|
20657
20662
|
if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
|
|
20658
|
-
const inside =
|
|
20663
|
+
const inside = readdirSync33(dir);
|
|
20659
20664
|
if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
|
|
20660
20665
|
rmSync5(dir, { recursive: true, force: true });
|
|
20661
20666
|
removed++;
|
|
@@ -20733,20 +20738,20 @@ function realRestart(platform2) {
|
|
|
20733
20738
|
else if (platform2 === "darwin") execSync2("launchctl kickstart -k gui/$(id -u)/com.chat-recall.watch", { stdio: "ignore", shell: "/bin/bash" });
|
|
20734
20739
|
else if (platform2 === "win32") execSync2("schtasks /End /TN chat-recall-watch & schtasks /Run /TN chat-recall-watch", { stdio: "ignore" });
|
|
20735
20740
|
}
|
|
20736
|
-
async function runAutoUpdate(
|
|
20741
|
+
async function runAutoUpdate(base3, authHeaders, ownVersion3, deps) {
|
|
20737
20742
|
let caps;
|
|
20738
20743
|
try {
|
|
20739
|
-
const res = await fetchWithTimeout(`${
|
|
20744
|
+
const res = await fetchWithTimeout(`${base3.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
|
|
20740
20745
|
if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
|
|
20741
20746
|
caps = await res.json();
|
|
20742
20747
|
} catch (e) {
|
|
20743
20748
|
return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
|
|
20744
20749
|
}
|
|
20745
20750
|
const effectiveOwn = newerOf(ownVersion3, installedVersion());
|
|
20746
|
-
const plan = planAutoUpdate(
|
|
20751
|
+
const plan = planAutoUpdate(base3, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20747
20752
|
if (!plan.update) {
|
|
20748
|
-
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(
|
|
20749
|
-
reportedStandingSkip.add(
|
|
20753
|
+
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base3)) {
|
|
20754
|
+
reportedStandingSkip.add(base3);
|
|
20750
20755
|
try {
|
|
20751
20756
|
const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
|
|
20752
20757
|
reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
|
|
@@ -20775,7 +20780,7 @@ var init_auto_update = __esm({
|
|
|
20775
20780
|
"src/auto-update.ts"() {
|
|
20776
20781
|
"use strict";
|
|
20777
20782
|
init_http();
|
|
20778
|
-
tarballUrl = (
|
|
20783
|
+
tarballUrl = (base3) => `${base3.replace(/\/+$/, "")}/install/chat-recall.tgz`;
|
|
20779
20784
|
reportedStandingSkip = /* @__PURE__ */ new Set();
|
|
20780
20785
|
}
|
|
20781
20786
|
});
|
|
@@ -20810,7 +20815,7 @@ __export(sync_client_exports, {
|
|
|
20810
20815
|
syncSessions: () => syncSessions
|
|
20811
20816
|
});
|
|
20812
20817
|
import { join as join44, dirname as dirname19, basename as basename22 } from "node:path";
|
|
20813
|
-
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";
|
|
20814
20819
|
import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
|
|
20815
20820
|
import { createHash as createHash13 } from "node:crypto";
|
|
20816
20821
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -20873,15 +20878,15 @@ function loadAllCredentials() {
|
|
|
20873
20878
|
return [];
|
|
20874
20879
|
}
|
|
20875
20880
|
async function fetchTenantSecurityConfig(cred) {
|
|
20876
|
-
const
|
|
20877
|
-
const cached = _securityConfigCache.get(
|
|
20881
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
20882
|
+
const cached = _securityConfigCache.get(base3);
|
|
20878
20883
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20879
20884
|
const headers = { "content-type": "application/json" };
|
|
20880
20885
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
20881
20886
|
try {
|
|
20882
20887
|
const [rulesRes, settingsRes] = await Promise.all([
|
|
20883
|
-
fetchWithTimeout(`${
|
|
20884
|
-
fetchWithTimeout(`${
|
|
20888
|
+
fetchWithTimeout(`${base3}/api/secrets/rules`, { headers }),
|
|
20889
|
+
fetchWithTimeout(`${base3}/api/teams/security-config`, { headers }).catch(() => null)
|
|
20885
20890
|
]);
|
|
20886
20891
|
let tenantRules = [];
|
|
20887
20892
|
let rulePackVersion = null;
|
|
@@ -20906,18 +20911,18 @@ async function fetchTenantSecurityConfig(cred) {
|
|
|
20906
20911
|
const body = await settingsRes.json().catch(() => ({}));
|
|
20907
20912
|
if (typeof body.verifySecrets === "boolean") verifySecrets = body.verifySecrets;
|
|
20908
20913
|
if (typeof body.telemetry === "boolean") {
|
|
20909
|
-
setTelemetryEligible(
|
|
20914
|
+
setTelemetryEligible(base3, body.telemetry);
|
|
20910
20915
|
try {
|
|
20911
20916
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
20912
20917
|
updateCollectorHealth({
|
|
20913
|
-
telemetryEligible: { ...prior, [
|
|
20918
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body.telemetry, at: Date.now() } }
|
|
20914
20919
|
});
|
|
20915
20920
|
} catch {
|
|
20916
20921
|
}
|
|
20917
20922
|
}
|
|
20918
20923
|
}
|
|
20919
20924
|
const config2 = { tenantRules, verifySecrets, rulePackVersion };
|
|
20920
|
-
_securityConfigCache.set(
|
|
20925
|
+
_securityConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
|
|
20921
20926
|
return config2;
|
|
20922
20927
|
} catch {
|
|
20923
20928
|
return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
|
|
@@ -20936,18 +20941,18 @@ function readPersistedSyncConfigs() {
|
|
|
20936
20941
|
return {};
|
|
20937
20942
|
}
|
|
20938
20943
|
}
|
|
20939
|
-
function persistSyncConfig(
|
|
20944
|
+
function persistSyncConfig(base3, config2) {
|
|
20940
20945
|
try {
|
|
20941
20946
|
const all = readPersistedSyncConfigs();
|
|
20942
|
-
all[
|
|
20947
|
+
all[base3] = { fetchedAt: Date.now(), config: config2 };
|
|
20943
20948
|
mkdirSync9(dirname19(syncConfigCachePath()), { recursive: true });
|
|
20944
20949
|
writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
|
|
20945
20950
|
} catch {
|
|
20946
20951
|
}
|
|
20947
20952
|
}
|
|
20948
20953
|
async function fetchTenantSyncConfig(cred) {
|
|
20949
|
-
const
|
|
20950
|
-
const cached = _syncConfigCache.get(
|
|
20954
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
20955
|
+
const cached = _syncConfigCache.get(base3);
|
|
20951
20956
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
20952
20957
|
const headers = { "content-type": "application/json" };
|
|
20953
20958
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
@@ -20955,7 +20960,7 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20955
20960
|
try {
|
|
20956
20961
|
const sources3 = discoverSessionSources();
|
|
20957
20962
|
if (sources3.length > 0) {
|
|
20958
|
-
await fetchWithTimeout(`${
|
|
20963
|
+
await fetchWithTimeout(`${base3}/api/sync-config/sources`, {
|
|
20959
20964
|
method: "POST",
|
|
20960
20965
|
headers,
|
|
20961
20966
|
body: JSON.stringify({ device: deviceLabel(), sources: sources3 })
|
|
@@ -20963,12 +20968,12 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
20963
20968
|
}
|
|
20964
20969
|
} catch {
|
|
20965
20970
|
}
|
|
20966
|
-
const res = await fetchWithTimeout(`${
|
|
20971
|
+
const res = await fetchWithTimeout(`${base3}/api/sync-config`, { headers });
|
|
20967
20972
|
if (res.status === 404) {
|
|
20968
|
-
_syncConfigCache.set(
|
|
20973
|
+
_syncConfigCache.set(base3, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
|
|
20969
20974
|
return EMPTY_SYNC_CONFIG;
|
|
20970
20975
|
}
|
|
20971
|
-
if (!res.ok) return lastKnownSyncConfig(
|
|
20976
|
+
if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
|
|
20972
20977
|
const body = await res.json().catch(() => ({}));
|
|
20973
20978
|
const config2 = {
|
|
20974
20979
|
excludeTools: Array.isArray(body.excludeTools) ? body.excludeTools.filter((t) => typeof t === "string") : [],
|
|
@@ -21005,22 +21010,22 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
21005
21010
|
if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
|
|
21006
21011
|
} catch {
|
|
21007
21012
|
}
|
|
21008
|
-
_syncConfigCache.set(
|
|
21009
|
-
persistSyncConfig(
|
|
21013
|
+
_syncConfigCache.set(base3, { fetchedAt: Date.now(), config: config2 });
|
|
21014
|
+
persistSyncConfig(base3, config2);
|
|
21010
21015
|
return config2;
|
|
21011
21016
|
} catch (err) {
|
|
21012
21017
|
if (isSyncRulesRefusal(err)) throw err;
|
|
21013
|
-
return lastKnownSyncConfig(
|
|
21018
|
+
return lastKnownSyncConfig(base3, err instanceof Error ? err.message : "request failed");
|
|
21014
21019
|
}
|
|
21015
21020
|
}
|
|
21016
|
-
function lastKnownSyncConfig(
|
|
21017
|
-
const remembered = _syncConfigCache.get(
|
|
21021
|
+
function lastKnownSyncConfig(base3, reason) {
|
|
21022
|
+
const remembered = _syncConfigCache.get(base3) ?? readPersistedSyncConfigs()[base3];
|
|
21018
21023
|
if (remembered) {
|
|
21019
21024
|
console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
|
|
21020
21025
|
return remembered.config;
|
|
21021
21026
|
}
|
|
21022
21027
|
const refusal = new Error(
|
|
21023
|
-
`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.`
|
|
21024
21029
|
);
|
|
21025
21030
|
refusal[SYNC_RULES_REFUSAL] = true;
|
|
21026
21031
|
throw refusal;
|
|
@@ -21137,25 +21142,25 @@ async function syncSessions(opts = {}) {
|
|
|
21137
21142
|
${errors.join("\n ")}`);
|
|
21138
21143
|
return { ...agg, perTarget };
|
|
21139
21144
|
}
|
|
21140
|
-
async function postFieldBatch(
|
|
21145
|
+
async function postFieldBatch(base3, token, rows) {
|
|
21141
21146
|
const headers = { "content-type": "application/json" };
|
|
21142
21147
|
if (token) headers.authorization = `Bearer ${token}`;
|
|
21143
21148
|
const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
21144
21149
|
for (let attempt = 0; ; attempt++) {
|
|
21145
|
-
const res = await fetchWithTimeout(`${
|
|
21150
|
+
const res = await fetchWithTimeout(`${base3}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
|
|
21146
21151
|
if (res.ok) return;
|
|
21147
21152
|
const retryable = res.status === 429 || res.status >= 500;
|
|
21148
|
-
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(() => "")}`);
|
|
21149
21154
|
const ra = Number(res.headers.get("retry-after")) || 0;
|
|
21150
21155
|
await sleep2(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
|
|
21151
21156
|
}
|
|
21152
21157
|
}
|
|
21153
21158
|
async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
21154
|
-
const
|
|
21155
|
-
const ledger = getSyncedRows(
|
|
21159
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
21160
|
+
const ledger = getSyncedRows(base3);
|
|
21156
21161
|
let pushed = 0, absent = 0, scanned = 0;
|
|
21157
21162
|
for (const field of SYNC_FIELDS) {
|
|
21158
|
-
const needFull = !!opts.force || fieldNeedsFullPass(
|
|
21163
|
+
const needFull = !!opts.force || fieldNeedsFullPass(base3, field);
|
|
21159
21164
|
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
21160
21165
|
const send = [];
|
|
21161
21166
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
@@ -21171,15 +21176,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
21171
21176
|
}
|
|
21172
21177
|
for (let i = 0; i < send.length; i += 200) {
|
|
21173
21178
|
const chunk = send.slice(i, i + 200);
|
|
21174
|
-
await postFieldBatch(
|
|
21175
|
-
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 })));
|
|
21176
21181
|
pushed += chunk.length;
|
|
21177
21182
|
}
|
|
21178
21183
|
if (absentIds.length) {
|
|
21179
|
-
markFieldCoverage(
|
|
21184
|
+
markFieldCoverage(base3, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
|
|
21180
21185
|
absent += absentIds.length;
|
|
21181
21186
|
}
|
|
21182
|
-
if (needFull) markFieldFullPassDone(
|
|
21187
|
+
if (needFull) markFieldFullPassDone(base3, field);
|
|
21183
21188
|
}
|
|
21184
21189
|
return { pushed, absent, scanned };
|
|
21185
21190
|
}
|
|
@@ -21209,7 +21214,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
|
|
|
21209
21214
|
let reaped = 0;
|
|
21210
21215
|
let names;
|
|
21211
21216
|
try {
|
|
21212
|
-
names =
|
|
21217
|
+
names = readdirSync34(dir);
|
|
21213
21218
|
} catch {
|
|
21214
21219
|
return 0;
|
|
21215
21220
|
}
|
|
@@ -21296,25 +21301,25 @@ function serverIngestConcurrency(serverUrl) {
|
|
|
21296
21301
|
return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
|
|
21297
21302
|
}
|
|
21298
21303
|
async function verifyServerApi(serverUrl, minApi) {
|
|
21299
|
-
const
|
|
21300
|
-
const seen = capsOk.get(
|
|
21304
|
+
const base3 = serverUrl.replace(/\/$/, "");
|
|
21305
|
+
const seen = capsOk.get(base3);
|
|
21301
21306
|
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
21302
21307
|
const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
21303
|
-
const probe = await probeServer2(
|
|
21308
|
+
const probe = await probeServer2(base3, {
|
|
21304
21309
|
fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
|
|
21305
21310
|
});
|
|
21306
|
-
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe,
|
|
21311
|
+
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base3));
|
|
21307
21312
|
const caps = probe.raw;
|
|
21308
21313
|
if ((caps.apiVersion ?? 0) < minApi) {
|
|
21309
21314
|
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
21310
21315
|
}
|
|
21311
21316
|
const adv = caps.limits?.ingestConcurrencyPerTenant;
|
|
21312
21317
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
21313
|
-
advertisedIngestConc.set(
|
|
21318
|
+
advertisedIngestConc.set(base3, Math.floor(adv));
|
|
21314
21319
|
}
|
|
21315
|
-
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(
|
|
21316
|
-
else advertisedGzipBody.delete(
|
|
21317
|
-
capsOk.set(
|
|
21320
|
+
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base3);
|
|
21321
|
+
else advertisedGzipBody.delete(base3);
|
|
21322
|
+
capsOk.set(base3, Date.now());
|
|
21318
21323
|
return true;
|
|
21319
21324
|
}
|
|
21320
21325
|
async function syncToTarget(cred, opts = {}) {
|
|
@@ -21379,7 +21384,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21379
21384
|
const ac = new AbortController();
|
|
21380
21385
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21381
21386
|
try {
|
|
21382
|
-
const res = await fetch(`${
|
|
21387
|
+
const res = await fetch(`${base3}/api/sync`, {
|
|
21383
21388
|
method: "POST",
|
|
21384
21389
|
// No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
|
|
21385
21390
|
// accepts it as the single 'default' tenant.
|
|
@@ -21394,26 +21399,26 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21394
21399
|
if (res.ok) {
|
|
21395
21400
|
const body2 = await res.json().catch(() => ({}));
|
|
21396
21401
|
if (typeof body2.telemetry === "boolean") {
|
|
21397
|
-
setTelemetryEligible(
|
|
21402
|
+
setTelemetryEligible(base3, body2.telemetry);
|
|
21398
21403
|
try {
|
|
21399
21404
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
21400
21405
|
updateCollectorHealth({
|
|
21401
|
-
telemetryEligible: { ...prior, [
|
|
21406
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
|
|
21402
21407
|
});
|
|
21403
21408
|
} catch {
|
|
21404
21409
|
}
|
|
21405
21410
|
}
|
|
21406
21411
|
const adv = body2.limits?.ingestConcurrencyPerTenant;
|
|
21407
21412
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
21408
|
-
setServerIngestConcurrency(
|
|
21413
|
+
setServerIngestConcurrency(base3, Math.floor(adv));
|
|
21409
21414
|
}
|
|
21410
21415
|
if (body2.cli && body2.cli.version) {
|
|
21411
21416
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
21412
21417
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
21413
|
-
const plan = planAutoUpdate2(
|
|
21418
|
+
const plan = planAutoUpdate2(base3, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
21414
21419
|
sweepStaleStaging2();
|
|
21415
21420
|
if (plan.update) {
|
|
21416
|
-
void runAutoUpdate2(
|
|
21421
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
21417
21422
|
});
|
|
21418
21423
|
}
|
|
21419
21424
|
}
|
|
@@ -21422,7 +21427,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21422
21427
|
const retryable = res.status === 429 || res.status >= 500;
|
|
21423
21428
|
const text = await res.text().catch(() => "");
|
|
21424
21429
|
if (res.status === 401 || res.status === 403) {
|
|
21425
|
-
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${
|
|
21430
|
+
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base3}`);
|
|
21426
21431
|
}
|
|
21427
21432
|
if (res.status === 402) {
|
|
21428
21433
|
let detail = text;
|
|
@@ -21442,7 +21447,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21442
21447
|
if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
|
|
21443
21448
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
21444
21449
|
const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
|
|
21445
|
-
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})`);
|
|
21446
21451
|
await sleep2(waitMs);
|
|
21447
21452
|
continue;
|
|
21448
21453
|
} catch (err) {
|
|
@@ -21509,11 +21514,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21509
21514
|
}
|
|
21510
21515
|
};
|
|
21511
21516
|
};
|
|
21512
|
-
const
|
|
21513
|
-
const ledger = opts.useLedger ? getSyncedRows(
|
|
21517
|
+
const base3 = cred.serverUrl.replace(/\/$/, "");
|
|
21518
|
+
const ledger = opts.useLedger ? getSyncedRows(base3) : null;
|
|
21514
21519
|
const convBatch = makeBatcher("conversations", 25, false, (rows) => {
|
|
21515
21520
|
try {
|
|
21516
|
-
markSynced(
|
|
21521
|
+
markSynced(base3, rows.map((r) => {
|
|
21517
21522
|
const off = typeof r.from_offset === "number" ? r.from_offset : 0;
|
|
21518
21523
|
const hash = shippedHash.get(r.session_id);
|
|
21519
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 };
|
|
@@ -21528,7 +21533,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21528
21533
|
const ac = new AbortController();
|
|
21529
21534
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21530
21535
|
try {
|
|
21531
|
-
const res = await fetch(`${
|
|
21536
|
+
const res = await fetch(`${base3}/api/sync`, {
|
|
21532
21537
|
method: "POST",
|
|
21533
21538
|
headers,
|
|
21534
21539
|
body: JSON.stringify({ conversations: convs }),
|
|
@@ -21539,10 +21544,10 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21539
21544
|
if (body.cli && body.cli.version) {
|
|
21540
21545
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
21541
21546
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
21542
|
-
const plan = planAutoUpdate2(
|
|
21547
|
+
const plan = planAutoUpdate2(base3, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
21543
21548
|
sweepStaleStaging2();
|
|
21544
21549
|
if (plan.update) {
|
|
21545
|
-
void runAutoUpdate2(
|
|
21550
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
21546
21551
|
});
|
|
21547
21552
|
}
|
|
21548
21553
|
}
|
|
@@ -21550,7 +21555,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21550
21555
|
const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
|
|
21551
21556
|
if (acked.length > 0) {
|
|
21552
21557
|
try {
|
|
21553
|
-
markSynced(
|
|
21558
|
+
markSynced(base3, acked.map((c) => ({
|
|
21554
21559
|
id: c.session_id,
|
|
21555
21560
|
mtime: c.mtime,
|
|
21556
21561
|
offset: c.from_offset,
|
|
@@ -21620,7 +21625,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21620
21625
|
const m = process.memoryUsage();
|
|
21621
21626
|
console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
|
|
21622
21627
|
} : null;
|
|
21623
|
-
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${
|
|
21628
|
+
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base3}`);
|
|
21624
21629
|
if (upload.sessionMeta) {
|
|
21625
21630
|
try {
|
|
21626
21631
|
await reconcileFieldsForTarget(
|
|
@@ -21635,7 +21640,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21635
21640
|
{ convRefs: slice }
|
|
21636
21641
|
);
|
|
21637
21642
|
} catch (e) {
|
|
21638
|
-
console.error(`[sync] field reconcile (${
|
|
21643
|
+
console.error(`[sync] field reconcile (${base3}): ${e instanceof Error ? e.message : e}`);
|
|
21639
21644
|
}
|
|
21640
21645
|
}
|
|
21641
21646
|
trace?.("field reconcile done");
|
|
@@ -21710,7 +21715,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21710
21715
|
continue;
|
|
21711
21716
|
} else {
|
|
21712
21717
|
try {
|
|
21713
|
-
markSynced(
|
|
21718
|
+
markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21714
21719
|
} catch {
|
|
21715
21720
|
}
|
|
21716
21721
|
skipped++;
|
|
@@ -21733,7 +21738,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21733
21738
|
const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
|
|
21734
21739
|
const priorCursor = ackRow?.s ?? 0;
|
|
21735
21740
|
const safeToAck = off > 0 && off <= priorCursor;
|
|
21736
|
-
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 }]);
|
|
21737
21742
|
} catch {
|
|
21738
21743
|
}
|
|
21739
21744
|
}
|
|
@@ -21743,7 +21748,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21743
21748
|
if (!built) {
|
|
21744
21749
|
if (ledger) {
|
|
21745
21750
|
try {
|
|
21746
|
-
markSynced(
|
|
21751
|
+
markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
21747
21752
|
} catch {
|
|
21748
21753
|
}
|
|
21749
21754
|
}
|
|
@@ -21799,7 +21804,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21799
21804
|
walked++;
|
|
21800
21805
|
if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
|
|
21801
21806
|
}
|
|
21802
|
-
const itemVersions = loadItemVersions(
|
|
21807
|
+
const itemVersions = loadItemVersions(base3);
|
|
21803
21808
|
const seenTools = /* @__PURE__ */ new Set();
|
|
21804
21809
|
const seenItemKeys = /* @__PURE__ */ new Map();
|
|
21805
21810
|
const registry = buildSourceRegistry();
|
|
@@ -21885,7 +21890,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21885
21890
|
await appendFlush();
|
|
21886
21891
|
for (const id of appendResults.fullResyncNeeded) {
|
|
21887
21892
|
try {
|
|
21888
|
-
markFullResync(
|
|
21893
|
+
markFullResync(base3, id);
|
|
21889
21894
|
} catch {
|
|
21890
21895
|
}
|
|
21891
21896
|
}
|
|
@@ -21902,7 +21907,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21902
21907
|
const rec = {};
|
|
21903
21908
|
for (const t of seenTools) rec[t] = extractorVersionForTool(t);
|
|
21904
21909
|
for (const [k, v] of seenItemKeys) rec[k] = v;
|
|
21905
|
-
saveItemVersions(
|
|
21910
|
+
saveItemVersions(base3, rec);
|
|
21906
21911
|
} catch {
|
|
21907
21912
|
}
|
|
21908
21913
|
}
|
|
@@ -21915,9 +21920,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21915
21920
|
}
|
|
21916
21921
|
if (tombstones.length > 0) {
|
|
21917
21922
|
await post({ tombstones });
|
|
21918
|
-
const data = getLedgerData(
|
|
21923
|
+
const data = getLedgerData(base3);
|
|
21919
21924
|
for (const t of tombstones) delete data[t.session_id];
|
|
21920
|
-
persistLedgerData(
|
|
21925
|
+
persistLedgerData(base3, data);
|
|
21921
21926
|
}
|
|
21922
21927
|
}
|
|
21923
21928
|
if (opts.prune) await post({ prune_empty_sessions: true });
|
|
@@ -22347,7 +22352,7 @@ var init_sync_client = __esm({
|
|
|
22347
22352
|
ownVersion = JSON.parse(readFileSync37(join44(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
22348
22353
|
} catch {
|
|
22349
22354
|
try {
|
|
22350
|
-
if (true) ownVersion = "0.5.
|
|
22355
|
+
if (true) ownVersion = "0.5.32";
|
|
22351
22356
|
} catch {
|
|
22352
22357
|
}
|
|
22353
22358
|
}
|
|
@@ -22417,9 +22422,9 @@ async function refreshUpdateCheck(force = false) {
|
|
|
22417
22422
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
22418
22423
|
for (const cred of loadAllCredentials2()) {
|
|
22419
22424
|
if (!cred.serverUrl) continue;
|
|
22420
|
-
const
|
|
22425
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
22421
22426
|
try {
|
|
22422
|
-
const res = await fetchWithTimeout(`${
|
|
22427
|
+
const res = await fetchWithTimeout(`${base3}/api/capabilities`, {
|
|
22423
22428
|
headers: cred.token ? { authorization: `Bearer ${cred.token}` } : {}
|
|
22424
22429
|
}, 5e3);
|
|
22425
22430
|
if (!res.ok) continue;
|
|
@@ -23014,7 +23019,7 @@ __export(install_skills_exports, {
|
|
|
23014
23019
|
skillsSourceDir: () => skillsSourceDir,
|
|
23015
23020
|
uninstallSkills: () => uninstallSkills
|
|
23016
23021
|
});
|
|
23017
|
-
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";
|
|
23018
23023
|
import { createHash as createHash15 } from "crypto";
|
|
23019
23024
|
import { join as join49, basename as basename23 } from "path";
|
|
23020
23025
|
function skillsSourceDir() {
|
|
@@ -23040,7 +23045,7 @@ function skillsFingerprint() {
|
|
|
23040
23045
|
}
|
|
23041
23046
|
function filesUnder(dir, prefix = "") {
|
|
23042
23047
|
const out = [];
|
|
23043
|
-
for (const e of
|
|
23048
|
+
for (const e of readdirSync35(dir, { withFileTypes: true })) {
|
|
23044
23049
|
if (e.name === MARKER) continue;
|
|
23045
23050
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
23046
23051
|
if (e.isDirectory()) out.push(...filesUnder(join49(dir, e.name), rel));
|
|
@@ -23054,7 +23059,7 @@ function skillStamp() {
|
|
|
23054
23059
|
function bundledSkillNames() {
|
|
23055
23060
|
const src = skillsSourceDir();
|
|
23056
23061
|
if (!existsSync46(src)) return [];
|
|
23057
|
-
return
|
|
23062
|
+
return readdirSync35(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync46(join49(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
|
|
23058
23063
|
}
|
|
23059
23064
|
function realPathOrSelf(p) {
|
|
23060
23065
|
try {
|
|
@@ -23146,7 +23151,7 @@ function uninstallSkills() {
|
|
|
23146
23151
|
perTarget.push({ id: t.id, label: t.label, removed });
|
|
23147
23152
|
continue;
|
|
23148
23153
|
}
|
|
23149
|
-
for (const entry of
|
|
23154
|
+
for (const entry of readdirSync35(t.dir, { withFileTypes: true })) {
|
|
23150
23155
|
if (!entry.isDirectory()) continue;
|
|
23151
23156
|
const dir = join49(t.dir, entry.name);
|
|
23152
23157
|
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
@@ -23849,9 +23854,9 @@ function portableCommand(cmd) {
|
|
|
23849
23854
|
}
|
|
23850
23855
|
if (isExecutableFile(cmd))
|
|
23851
23856
|
return { command: cmd, rewritten: false };
|
|
23852
|
-
const
|
|
23853
|
-
if (onPath(
|
|
23854
|
-
return { command:
|
|
23857
|
+
const base3 = basename26(cmd);
|
|
23858
|
+
if (onPath(base3))
|
|
23859
|
+
return { command: base3, rewritten: true };
|
|
23855
23860
|
return { missing: cmd };
|
|
23856
23861
|
}
|
|
23857
23862
|
function entryFromSpec(spec) {
|
|
@@ -24917,17 +24922,17 @@ async function collectCode(opts) {
|
|
|
24917
24922
|
return r;
|
|
24918
24923
|
};
|
|
24919
24924
|
log6(`indexing ${ws} + analyses \u2026`);
|
|
24920
|
-
const
|
|
24925
|
+
const base3 = await runMcp(bin, ws, [
|
|
24921
24926
|
call(1, "index_workspace", { path: ws }),
|
|
24922
24927
|
call(2, "status"),
|
|
24923
24928
|
call(3, "get_tree"),
|
|
24924
24929
|
...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
|
|
24925
24930
|
]);
|
|
24926
|
-
const st = parseJson(
|
|
24927
|
-
const tree = parseJson(
|
|
24931
|
+
const st = parseJson(base3, 2, {});
|
|
24932
|
+
const tree = parseJson(base3, 3, []);
|
|
24928
24933
|
const A = {};
|
|
24929
24934
|
ANALYSES.forEach((a, i) => {
|
|
24930
|
-
A[a] = parseJson(
|
|
24935
|
+
A[a] = parseJson(base3, 10 + i, {});
|
|
24931
24936
|
});
|
|
24932
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;
|
|
24933
24938
|
if (tree.length === 0) {
|
|
@@ -25827,14 +25832,14 @@ function writeLedger(l) {
|
|
|
25827
25832
|
} catch {
|
|
25828
25833
|
}
|
|
25829
25834
|
}
|
|
25830
|
-
async function pushProjectTaskStatuses(
|
|
25835
|
+
async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
|
|
25831
25836
|
const out = { files: 0, pushedTasks: 0 };
|
|
25832
25837
|
const ledger = readLedger();
|
|
25833
25838
|
let ledgerDirty = false;
|
|
25834
25839
|
for (const fk of FILE_KINDS) {
|
|
25835
25840
|
let projects;
|
|
25836
25841
|
try {
|
|
25837
|
-
const res = await fetchWithTimeout(`${
|
|
25842
|
+
const res = await fetchWithTimeout(`${base3}${fk.trackedPath}`, { headers: authHeaders });
|
|
25838
25843
|
if (!res.ok) continue;
|
|
25839
25844
|
projects = (await res.json()).projects || [];
|
|
25840
25845
|
} catch {
|
|
@@ -25862,7 +25867,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
25862
25867
|
continue;
|
|
25863
25868
|
}
|
|
25864
25869
|
try {
|
|
25865
|
-
const res = await fetchWithTimeout(`${
|
|
25870
|
+
const res = await fetchWithTimeout(`${base3}${fk.statusPath}`, {
|
|
25866
25871
|
method: "POST",
|
|
25867
25872
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
25868
25873
|
body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
|
|
@@ -25968,16 +25973,16 @@ ${block}`);
|
|
|
25968
25973
|
return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
|
|
25969
25974
|
}
|
|
25970
25975
|
}
|
|
25971
|
-
async function runPull(
|
|
25976
|
+
async function runPull(base3, opts) {
|
|
25972
25977
|
const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
|
|
25973
25978
|
const { hostname: hostname3 } = await import("node:os");
|
|
25974
|
-
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") ===
|
|
25979
|
+
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base3.replace(/\/+$/, ""));
|
|
25975
25980
|
const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
|
|
25976
25981
|
const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
|
|
25977
25982
|
const rows = [];
|
|
25978
25983
|
for (const type of wanted) {
|
|
25979
25984
|
try {
|
|
25980
|
-
const res = await fetchWithTimeout(`${
|
|
25985
|
+
const res = await fetchWithTimeout(`${base3}/api/toolkit/browse/${type}?limit=1000`, { headers });
|
|
25981
25986
|
if (!res.ok) continue;
|
|
25982
25987
|
const body = await res.json();
|
|
25983
25988
|
for (const it of body.items || []) rows.push(it);
|
|
@@ -26046,20 +26051,20 @@ async function runIntent(intent, ctx) {
|
|
|
26046
26051
|
async function drainSyncIntents(opts = {}) {
|
|
26047
26052
|
const out = { processed: 0, done: 0, errored: 0 };
|
|
26048
26053
|
for (const cred of loadAllCredentials()) {
|
|
26049
|
-
const
|
|
26054
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
26050
26055
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
26051
26056
|
let pending;
|
|
26052
26057
|
try {
|
|
26053
|
-
const res = await fetchWithTimeout(`${
|
|
26058
|
+
const res = await fetchWithTimeout(`${base3}/api/sync-intents/pending`, { headers: authHeaders });
|
|
26054
26059
|
if (!res.ok) continue;
|
|
26055
26060
|
const data = await res.json();
|
|
26056
26061
|
pending = data.intents || [];
|
|
26057
26062
|
if (data.cli && data.cli.version) {
|
|
26058
26063
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
26059
|
-
const plan = planAutoUpdate2(
|
|
26064
|
+
const plan = planAutoUpdate2(base3, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
26060
26065
|
sweepStaleStaging2();
|
|
26061
26066
|
if (plan.update) {
|
|
26062
|
-
void runAutoUpdate2(
|
|
26067
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion2).catch(() => {
|
|
26063
26068
|
});
|
|
26064
26069
|
}
|
|
26065
26070
|
}
|
|
@@ -26067,7 +26072,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
26067
26072
|
continue;
|
|
26068
26073
|
}
|
|
26069
26074
|
for (const intent of pending) {
|
|
26070
|
-
const { status, result } = await runIntent(intent, { base:
|
|
26075
|
+
const { status, result } = await runIntent(intent, { base: base3 });
|
|
26071
26076
|
out.processed++;
|
|
26072
26077
|
if (status === "done") out.done++;
|
|
26073
26078
|
else out.errored++;
|
|
@@ -26076,7 +26081,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
26076
26081
|
console.error(`[sync-intent] ${label}: ${status}`);
|
|
26077
26082
|
}
|
|
26078
26083
|
try {
|
|
26079
|
-
await fetchWithTimeout(`${
|
|
26084
|
+
await fetchWithTimeout(`${base3}/api/sync-intents/${intent.id}/ack`, {
|
|
26080
26085
|
method: "POST",
|
|
26081
26086
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
26082
26087
|
body: JSON.stringify({ status, result })
|
|
@@ -26085,7 +26090,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
26085
26090
|
}
|
|
26086
26091
|
}
|
|
26087
26092
|
try {
|
|
26088
|
-
await pushProjectTaskStatuses(
|
|
26093
|
+
await pushProjectTaskStatuses(base3, authHeaders, { verbose: opts.verbose });
|
|
26089
26094
|
} catch {
|
|
26090
26095
|
}
|
|
26091
26096
|
}
|
|
@@ -26111,7 +26116,7 @@ var init_intent_drain = __esm({
|
|
|
26111
26116
|
ownVersion2 = JSON.parse(readFileSync46(join55(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
26112
26117
|
} catch {
|
|
26113
26118
|
try {
|
|
26114
|
-
if (true) ownVersion2 = "0.5.
|
|
26119
|
+
if (true) ownVersion2 = "0.5.32";
|
|
26115
26120
|
} catch {
|
|
26116
26121
|
}
|
|
26117
26122
|
}
|
|
@@ -26533,7 +26538,7 @@ var init_vault_crypto = __esm({
|
|
|
26533
26538
|
});
|
|
26534
26539
|
|
|
26535
26540
|
// ../engine/dist/core/vault-source.js
|
|
26536
|
-
import { existsSync as existsSync53, readdirSync as
|
|
26541
|
+
import { existsSync as existsSync53, readdirSync as readdirSync36, statSync as statSync46 } from "fs";
|
|
26537
26542
|
import { extname, join as join57 } from "path";
|
|
26538
26543
|
function* walkVaultSources() {
|
|
26539
26544
|
const t = loadSettings().team.vault;
|
|
@@ -26565,18 +26570,18 @@ function* walkClaude() {
|
|
|
26565
26570
|
return;
|
|
26566
26571
|
let projectDirs = [];
|
|
26567
26572
|
try {
|
|
26568
|
-
projectDirs =
|
|
26573
|
+
projectDirs = readdirSync36(root);
|
|
26569
26574
|
} catch {
|
|
26570
26575
|
return;
|
|
26571
26576
|
}
|
|
26572
26577
|
for (const proj of projectDirs) {
|
|
26573
26578
|
if (proj.startsWith("."))
|
|
26574
26579
|
continue;
|
|
26575
|
-
const projectPath =
|
|
26580
|
+
const projectPath = resolveProjectDirName(proj);
|
|
26576
26581
|
const projDir = join57(root, proj);
|
|
26577
26582
|
let entries = [];
|
|
26578
26583
|
try {
|
|
26579
|
-
entries =
|
|
26584
|
+
entries = readdirSync36(projDir);
|
|
26580
26585
|
} catch {
|
|
26581
26586
|
continue;
|
|
26582
26587
|
}
|
|
@@ -26598,7 +26603,7 @@ function* walkGemini() {
|
|
|
26598
26603
|
return;
|
|
26599
26604
|
let hashDirs = [];
|
|
26600
26605
|
try {
|
|
26601
|
-
hashDirs =
|
|
26606
|
+
hashDirs = readdirSync36(tmp);
|
|
26602
26607
|
} catch {
|
|
26603
26608
|
return;
|
|
26604
26609
|
}
|
|
@@ -26608,7 +26613,7 @@ function* walkGemini() {
|
|
|
26608
26613
|
continue;
|
|
26609
26614
|
let entries = [];
|
|
26610
26615
|
try {
|
|
26611
|
-
entries =
|
|
26616
|
+
entries = readdirSync36(chatsDir);
|
|
26612
26617
|
} catch {
|
|
26613
26618
|
continue;
|
|
26614
26619
|
}
|
|
@@ -26620,8 +26625,8 @@ function* walkGemini() {
|
|
|
26620
26625
|
const s = safeStat(path);
|
|
26621
26626
|
if (!s)
|
|
26622
26627
|
continue;
|
|
26623
|
-
const
|
|
26624
|
-
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 };
|
|
26625
26630
|
}
|
|
26626
26631
|
}
|
|
26627
26632
|
}
|
|
@@ -26654,7 +26659,7 @@ function* walkCodex() {
|
|
|
26654
26659
|
const dir = stack.pop();
|
|
26655
26660
|
let entries = [];
|
|
26656
26661
|
try {
|
|
26657
|
-
entries =
|
|
26662
|
+
entries = readdirSync36(dir, { withFileTypes: true });
|
|
26658
26663
|
} catch {
|
|
26659
26664
|
continue;
|
|
26660
26665
|
}
|
|
@@ -26669,8 +26674,8 @@ function* walkCodex() {
|
|
|
26669
26674
|
const s = safeStat(path);
|
|
26670
26675
|
if (!s)
|
|
26671
26676
|
continue;
|
|
26672
|
-
const
|
|
26673
|
-
yield { sessionId: `codex_${
|
|
26677
|
+
const base3 = e.name.replace(/\.jsonl$/, "");
|
|
26678
|
+
yield { sessionId: `codex_${base3}`, tool: "codex", path, mtimeMs: s.mtimeMs, sizeBytes: s.size };
|
|
26674
26679
|
}
|
|
26675
26680
|
}
|
|
26676
26681
|
}
|
|
@@ -26680,7 +26685,7 @@ function* walkAgy() {
|
|
|
26680
26685
|
return;
|
|
26681
26686
|
let sessionDirs = [];
|
|
26682
26687
|
try {
|
|
26683
|
-
sessionDirs =
|
|
26688
|
+
sessionDirs = readdirSync36(brainDir);
|
|
26684
26689
|
} catch {
|
|
26685
26690
|
return;
|
|
26686
26691
|
}
|
|
@@ -26813,11 +26818,11 @@ function vaultEnable(passphrase, opts = {}) {
|
|
|
26813
26818
|
}
|
|
26814
26819
|
async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
|
|
26815
26820
|
const doFetch = opts.fetchImpl ?? fetch;
|
|
26816
|
-
const
|
|
26821
|
+
const base3 = remote.baseUrl.replace(/\/+$/, "");
|
|
26817
26822
|
const headers = { authorization: `Bearer ${remote.token}`, "content-type": "application/json" };
|
|
26818
26823
|
let published = { saltHex: null, keyId: null };
|
|
26819
26824
|
try {
|
|
26820
|
-
const r = await doFetch(`${
|
|
26825
|
+
const r = await doFetch(`${base3}/api/vault/salt`, { headers });
|
|
26821
26826
|
if (r.ok)
|
|
26822
26827
|
published = await r.json();
|
|
26823
26828
|
} catch {
|
|
@@ -26831,7 +26836,7 @@ async function vaultEnableWithRemote(passphrase, remote, opts = {}) {
|
|
|
26831
26836
|
}
|
|
26832
26837
|
const result = vaultEnable(passphrase);
|
|
26833
26838
|
try {
|
|
26834
|
-
const r = await doFetch(`${
|
|
26839
|
+
const r = await doFetch(`${base3}/api/vault/salt`, {
|
|
26835
26840
|
method: "POST",
|
|
26836
26841
|
headers,
|
|
26837
26842
|
body: JSON.stringify({ saltHex: result.saltHex, keyId: result.keyId })
|
|
@@ -26924,8 +26929,8 @@ async function vaultSync(passphrase) {
|
|
|
26924
26929
|
return report;
|
|
26925
26930
|
}
|
|
26926
26931
|
function importedPathFor(tool, sessionId) {
|
|
26927
|
-
const
|
|
26928
|
-
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`);
|
|
26929
26934
|
}
|
|
26930
26935
|
async function vaultRestore(passphrase, opts = {}) {
|
|
26931
26936
|
const ctx = context2();
|
|
@@ -27468,8 +27473,8 @@ async function deviceLogin(opts, onPrompt) {
|
|
|
27468
27473
|
throw new Error("device-auth timed out \u2014 the code expired before approval.");
|
|
27469
27474
|
}
|
|
27470
27475
|
async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
27471
|
-
const
|
|
27472
|
-
const startRes = await fetch(`${
|
|
27476
|
+
const base3 = serverUrl.replace(/\/+$/, "");
|
|
27477
|
+
const startRes = await fetch(`${base3}/api/auth/device/code`, {
|
|
27473
27478
|
method: "POST",
|
|
27474
27479
|
headers: { "content-type": "application/json" },
|
|
27475
27480
|
body: JSON.stringify({ client_id: BETTER_AUTH_CLI_CLIENT_ID })
|
|
@@ -27477,7 +27482,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27477
27482
|
if (!startRes.ok) {
|
|
27478
27483
|
throw new Error(`device-auth init failed: HTTP ${startRes.status} ${await startRes.text().catch(() => "")}`);
|
|
27479
27484
|
}
|
|
27480
|
-
const start = await readDeviceCode(startRes,
|
|
27485
|
+
const start = await readDeviceCode(startRes, base3);
|
|
27481
27486
|
onPrompt({
|
|
27482
27487
|
url: start.verification_uri_complete || start.verification_uri,
|
|
27483
27488
|
userCode: start.user_code,
|
|
@@ -27487,7 +27492,7 @@ async function betterAuthDeviceLogin(serverUrl, onPrompt) {
|
|
|
27487
27492
|
let interval = (start.interval ?? 5) * 1e3;
|
|
27488
27493
|
while (Date.now() < deadline) {
|
|
27489
27494
|
await sleep(interval);
|
|
27490
|
-
const res = await fetch(`${
|
|
27495
|
+
const res = await fetch(`${base3}/api/auth/device/token`, {
|
|
27491
27496
|
method: "POST",
|
|
27492
27497
|
headers: { "content-type": "application/json" },
|
|
27493
27498
|
body: JSON.stringify({
|
|
@@ -27572,6 +27577,140 @@ var init_install_report = __esm({
|
|
|
27572
27577
|
}
|
|
27573
27578
|
});
|
|
27574
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
|
+
|
|
27575
27714
|
// ../engine/dist/core/resume-command.js
|
|
27576
27715
|
function toolOfSessionId(sessionId) {
|
|
27577
27716
|
if (sessionId.startsWith("codex_"))
|
|
@@ -27782,13 +27921,13 @@ function requireTarget() {
|
|
|
27782
27921
|
}
|
|
27783
27922
|
return t;
|
|
27784
27923
|
}
|
|
27785
|
-
async function readJsonBody(res,
|
|
27924
|
+
async function readJsonBody(res, base3, what) {
|
|
27786
27925
|
const text = await res.text().catch(() => "");
|
|
27787
27926
|
try {
|
|
27788
27927
|
return JSON.parse(text);
|
|
27789
27928
|
} catch {
|
|
27790
27929
|
throw new Error(
|
|
27791
|
-
`${
|
|
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`
|
|
27792
27931
|
);
|
|
27793
27932
|
}
|
|
27794
27933
|
}
|
|
@@ -28573,9 +28712,9 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
28573
28712
|
return;
|
|
28574
28713
|
}
|
|
28575
28714
|
const target = firstTarget();
|
|
28576
|
-
const
|
|
28715
|
+
const base3 = target?.base || (process.env.CHAT_RECALL_SERVER || "https://chatrecall.dev").replace(/\/+$/, "");
|
|
28577
28716
|
try {
|
|
28578
|
-
const res = await fetch(`${
|
|
28717
|
+
const res = await fetch(`${base3}/api/contact/feedback`, {
|
|
28579
28718
|
method: "POST",
|
|
28580
28719
|
headers: {
|
|
28581
28720
|
"content-type": "application/json",
|
|
@@ -28602,7 +28741,7 @@ program.command("feedback").argument("<message...>", "what you want to say \u201
|
|
|
28602
28741
|
console.log(chalk2.dim(" Add --email <address> next time if you want a reply."));
|
|
28603
28742
|
}
|
|
28604
28743
|
} catch (err) {
|
|
28605
|
-
console.error(chalk2.red(`Could not reach ${
|
|
28744
|
+
console.error(chalk2.red(`Could not reach ${base3}.`));
|
|
28606
28745
|
console.error(chalk2.dim(" Your message, so it is not lost:"));
|
|
28607
28746
|
console.error(chalk2.dim(` ${message}`));
|
|
28608
28747
|
process.exitCode = 1;
|
|
@@ -29170,13 +29309,13 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
|
|
|
29170
29309
|
}
|
|
29171
29310
|
const { fetchWithTimeout: fetchWithTimeout2 } = await Promise.resolve().then(() => (init_http(), http_exports));
|
|
29172
29311
|
for (const t of targets) {
|
|
29173
|
-
const
|
|
29312
|
+
const base3 = t.serverUrl.replace(/\/+$/, "");
|
|
29174
29313
|
const headers = {};
|
|
29175
29314
|
if (t.token) headers.authorization = `Bearer ${t.token}`;
|
|
29176
29315
|
let deleted = 0, missing = 0, failed = 0;
|
|
29177
29316
|
for (const id of ids) {
|
|
29178
29317
|
try {
|
|
29179
|
-
const res = await fetchWithTimeout2(`${
|
|
29318
|
+
const res = await fetchWithTimeout2(`${base3}/api/conversations/${encodeURIComponent(id)}`, { method: "DELETE", headers }, 3e4);
|
|
29180
29319
|
if (res.ok) deleted++;
|
|
29181
29320
|
else if (res.status === 404) missing++;
|
|
29182
29321
|
else failed++;
|
|
@@ -29184,7 +29323,7 @@ sources2.command("decline <path>").description("Keep a folder out of sync (e.g.
|
|
|
29184
29323
|
failed++;
|
|
29185
29324
|
}
|
|
29186
29325
|
}
|
|
29187
|
-
const line = ` ${
|
|
29326
|
+
const line = ` ${base3}: deleted ${deleted}` + (missing ? `, ${missing} were not there` : "") + (failed ? chalk2.red(`, ${failed} FAILED`) : "");
|
|
29188
29327
|
console.log(failed ? chalk2.yellow(line) : chalk2.green(line));
|
|
29189
29328
|
if (failed) process.exitCode = 1;
|
|
29190
29329
|
}
|
|
@@ -30032,10 +30171,10 @@ program.command("service <action>").description("Manage the per-user background
|
|
|
30032
30171
|
});
|
|
30033
30172
|
async function runLogin(serverUrl, opts) {
|
|
30034
30173
|
const { saveCredentials: saveCredentials2, loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
30035
|
-
const
|
|
30174
|
+
const base3 = serverUrl.replace(/\/+$/, "");
|
|
30036
30175
|
const verifyToken = async (token) => {
|
|
30037
30176
|
try {
|
|
30038
|
-
const res = await fetch(`${
|
|
30177
|
+
const res = await fetch(`${base3}/api/status`, {
|
|
30039
30178
|
headers: token ? { authorization: `Bearer ${token}` } : {},
|
|
30040
30179
|
signal: AbortSignal.timeout(1e4)
|
|
30041
30180
|
});
|
|
@@ -30051,36 +30190,36 @@ async function runLogin(serverUrl, opts) {
|
|
|
30051
30190
|
return failLogin(opts, 'the token contains non-ASCII characters \u2014 this looks like a masked/truncated copy (e.g. "ct_12345678\u2026")');
|
|
30052
30191
|
}
|
|
30053
30192
|
const { probeServer: identifyServer, probeOk: identified, probeAdvice: identifyAdvice } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30054
|
-
const who = await identifyServer(
|
|
30055
|
-
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));
|
|
30056
30195
|
const check = await verifyToken(token);
|
|
30057
30196
|
if (!check.ok) {
|
|
30058
30197
|
if (check.status === 401 || check.status === 403) {
|
|
30059
30198
|
console.error(chalk2.dim("Tokens are shown once \u2014 mint a fresh one (Account \u2192 Connect your machine) and copy the whole line."));
|
|
30060
|
-
return failLogin(opts, `${
|
|
30199
|
+
return failLogin(opts, `${base3} rejected the token (HTTP ${check.status})`);
|
|
30061
30200
|
}
|
|
30062
30201
|
if (check.status !== void 0 && check.status >= 500) {
|
|
30063
|
-
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.`);
|
|
30064
30203
|
}
|
|
30065
30204
|
if (check.status === 404 || check.status === 410) {
|
|
30066
|
-
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.`);
|
|
30067
30206
|
}
|
|
30068
|
-
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}`}`);
|
|
30069
30208
|
}
|
|
30070
30209
|
saveCredentials2({ serverUrl, token });
|
|
30071
30210
|
console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` server: ${serverUrl} (token verified)`));
|
|
30072
30211
|
return;
|
|
30073
30212
|
}
|
|
30074
|
-
const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") ===
|
|
30213
|
+
const existing = loadAllCredentials2().find((t) => t.serverUrl.replace(/\/+$/, "") === base3);
|
|
30075
30214
|
if (existing && (await verifyToken(existing.token)).ok) {
|
|
30076
30215
|
console.log(chalk2.green("\u2713 Already connected.") + chalk2.dim(` server: ${serverUrl} (existing token verified)`));
|
|
30077
30216
|
return;
|
|
30078
30217
|
}
|
|
30079
30218
|
try {
|
|
30080
30219
|
const { probeServer: probeServer2, probeOk: probeOk2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30081
|
-
const identified = await probeServer2(
|
|
30220
|
+
const identified = await probeServer2(base3, { timeoutMs: 8e3 });
|
|
30082
30221
|
if (probeOk2(identified)) {
|
|
30083
|
-
const probe = await fetch(`${
|
|
30222
|
+
const probe = await fetch(`${base3}/api/status`, { signal: AbortSignal.timeout(8e3) });
|
|
30084
30223
|
if (probe.status === 200) {
|
|
30085
30224
|
saveCredentials2({ serverUrl, token: "" });
|
|
30086
30225
|
console.log(chalk2.green("\u2713 Logged in.") + chalk2.dim(` ${serverUrl} (local server \u2014 no auth, no token needed)`));
|
|
@@ -30101,16 +30240,16 @@ async function runLogin(serverUrl, opts) {
|
|
|
30101
30240
|
if (!issuer) {
|
|
30102
30241
|
const { probeServer: probeServer2, probeOk: probeOk2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
30103
30242
|
for (let attempt = 1; attempt <= 3 && !authProvider; attempt++) {
|
|
30104
|
-
const probe = await probeServer2(
|
|
30243
|
+
const probe = await probeServer2(base3, { timeoutMs: 15e3 });
|
|
30105
30244
|
if (probeOk2(probe)) {
|
|
30106
30245
|
const caps = probe.raw;
|
|
30107
30246
|
authProvider = caps?.authProvider;
|
|
30108
30247
|
if (caps?.oidcIssuer) issuer = caps.oidcIssuer;
|
|
30109
30248
|
capsError = null;
|
|
30110
30249
|
} else if (probe.kind === "moved" || probe.kind === "not_api") {
|
|
30111
|
-
return failLogin(opts, probeAdvice2(probe,
|
|
30250
|
+
return failLogin(opts, probeAdvice2(probe, base3));
|
|
30112
30251
|
} else {
|
|
30113
|
-
capsError = probeAdvice2(probe,
|
|
30252
|
+
capsError = probeAdvice2(probe, base3);
|
|
30114
30253
|
}
|
|
30115
30254
|
if (!authProvider && attempt < 3) await new Promise((r) => setTimeout(r, attempt * 1e3));
|
|
30116
30255
|
}
|
|
@@ -30119,7 +30258,7 @@ async function runLogin(serverUrl, opts) {
|
|
|
30119
30258
|
authProvider = "better-auth";
|
|
30120
30259
|
if (capsError) {
|
|
30121
30260
|
console.log(` ${chalk2.yellow("Could not read the server's capabilities")} (${capsError}) \u2014 assuming the standard sign-in flow.`);
|
|
30122
|
-
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, {
|
|
30123
30262
|
step: "cli_login_probe",
|
|
30124
30263
|
reason: capsError?.slice(0, 40) ?? null,
|
|
30125
30264
|
message: capsError
|
|
@@ -30141,20 +30280,20 @@ async function runLogin(serverUrl, opts) {
|
|
|
30141
30280
|
console.log(chalk2.dim(` If the page asks for a code: ${chalk2.bold(p.userCode)}`));
|
|
30142
30281
|
console.log(chalk2.dim("Then come back here \u2014 this finishes on its own. Waiting\u2026"));
|
|
30143
30282
|
};
|
|
30144
|
-
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(
|
|
30283
|
+
const tokens = authProvider === "better-auth" ? await betterAuthDeviceLogin2(base3, onPrompt) : await deviceLogin2({ issuer, clientId: opts.clientId }, onPrompt);
|
|
30145
30284
|
const authHdr = { authorization: `Bearer ${tokens.accessToken}`, "content-type": "application/json" };
|
|
30146
|
-
const meRes = await fetch(`${
|
|
30147
|
-
if (!meRes.ok) throw new Error(`${
|
|
30148
|
-
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");
|
|
30149
30288
|
const teams = me.teams || [];
|
|
30150
30289
|
let slug = opts.team;
|
|
30151
30290
|
if (!slug) {
|
|
30152
30291
|
if (teams.length === 1) slug = teams[0].team_slug;
|
|
30153
30292
|
else if (teams.length === 0) {
|
|
30154
30293
|
const name = me.user?.email?.split("@")[0]?.replace(/[^a-z0-9]/gi, "") || "workspace";
|
|
30155
|
-
const created = await fetch(`${
|
|
30294
|
+
const created = await fetch(`${base3}/api/teams`, { method: "POST", headers: authHdr, body: JSON.stringify({ name }) });
|
|
30156
30295
|
if (!created.ok) throw new Error(`workspace create failed: HTTP ${created.status} ${await created.text().catch(() => "")}`);
|
|
30157
|
-
slug = (await readJsonBody(created,
|
|
30296
|
+
slug = (await readJsonBody(created, base3, "POST /api/teams")).slug;
|
|
30158
30297
|
console.log(chalk2.dim(`Created workspace "${name}" (${slug}) \u2014 you're its owner.`));
|
|
30159
30298
|
} else {
|
|
30160
30299
|
teams.forEach((t) => console.error(` ${t.team_slug} ${chalk2.dim(t.name)}`));
|
|
@@ -30162,13 +30301,13 @@ async function runLogin(serverUrl, opts) {
|
|
|
30162
30301
|
}
|
|
30163
30302
|
}
|
|
30164
30303
|
const deviceId = opts.deviceId || (await import("node:os")).hostname();
|
|
30165
|
-
const mint = await fetch(`${
|
|
30304
|
+
const mint = await fetch(`${base3}/api/teams/${encodeURIComponent(slug)}/tokens`, {
|
|
30166
30305
|
method: "POST",
|
|
30167
30306
|
headers: authHdr,
|
|
30168
30307
|
body: JSON.stringify({ device_id: deviceId })
|
|
30169
30308
|
});
|
|
30170
30309
|
if (!mint.ok) throw new Error(`token mint failed: HTTP ${mint.status} ${await mint.text().catch(() => "")}`);
|
|
30171
|
-
const { token } = await readJsonBody(mint,
|
|
30310
|
+
const { token } = await readJsonBody(mint, base3, "POST /api/teams/:slug/tokens");
|
|
30172
30311
|
saveCredentials2({ serverUrl, token });
|
|
30173
30312
|
console.log(chalk2.green(`\u2713 Logged in to ${chalk2.bold(slug)}`) + chalk2.dim(` (device: ${deviceId}) server: ${serverUrl}`));
|
|
30174
30313
|
if (!opts.fromInit) {
|
|
@@ -30420,30 +30559,142 @@ program.command("logout <server-url>").description("Remove one sync target (othe
|
|
|
30420
30559
|
process.exit(1);
|
|
30421
30560
|
}
|
|
30422
30561
|
});
|
|
30423
|
-
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) => {
|
|
30424
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));
|
|
30425
30565
|
const targets = loadAllCredentials2();
|
|
30426
30566
|
if (targets.length === 0) {
|
|
30427
30567
|
console.error(chalk2.red("Not logged in \u2014 run `chat-recall login <server-url>` first."));
|
|
30428
30568
|
process.exit(1);
|
|
30429
30569
|
}
|
|
30430
|
-
|
|
30431
|
-
|
|
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) {
|
|
30432
30588
|
try {
|
|
30433
|
-
|
|
30434
|
-
|
|
30435
|
-
|
|
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;
|
|
30436
30657
|
});
|
|
30437
|
-
|
|
30438
|
-
|
|
30439
|
-
|
|
30440
|
-
|
|
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...>"));
|
|
30441
30678
|
} catch (e) {
|
|
30442
|
-
console.error(chalk2.red(
|
|
30679
|
+
console.error(chalk2.red(`Could not list deletions: ${e instanceof Error ? e.message : "failed"}`));
|
|
30680
|
+
process.exit(1);
|
|
30681
|
+
}
|
|
30682
|
+
return;
|
|
30683
|
+
}
|
|
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`));
|
|
30443
30690
|
}
|
|
30444
30691
|
}
|
|
30445
|
-
if (
|
|
30446
|
-
|
|
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"));
|
|
30447
30698
|
});
|
|
30448
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) => {
|
|
30449
30700
|
const { loadAllCredentials: loadAllCredentials2 } = await Promise.resolve().then(() => (init_sync_client(), sync_client_exports));
|
|
@@ -30533,16 +30784,16 @@ program.command("update").description("Update this CLI now from the server you s
|
|
|
30533
30784
|
}
|
|
30534
30785
|
let installFailed = false;
|
|
30535
30786
|
for (const cred of targets) {
|
|
30536
|
-
const
|
|
30787
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
30537
30788
|
const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
30538
|
-
const r = await runAutoUpdate2(
|
|
30789
|
+
const r = await runAutoUpdate2(base3, headers, cliVersion3());
|
|
30539
30790
|
if (r.updated) {
|
|
30540
|
-
console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${
|
|
30791
|
+
console.log(chalk2.green(`\u2713 ${r.reason}`) + chalk2.dim(` (${base3})`));
|
|
30541
30792
|
continue;
|
|
30542
30793
|
}
|
|
30543
30794
|
const benign = /already current|no CLI release|disabled/.test(r.reason);
|
|
30544
30795
|
if (/install failed|download failed|checksum/.test(r.reason)) installFailed = true;
|
|
30545
|
-
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})`));
|
|
30546
30797
|
}
|
|
30547
30798
|
await refreshUpdateCheck2(true);
|
|
30548
30799
|
if (installFailed) {
|