chat-recall 0.7.14 → 0.7.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +424 -289
- package/dist/hostile-server.d.ts.map +1 -1
- package/dist/hostile-server.js +10 -1
- package/dist/hostile-server.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +331 -196
- package/dist/scan-worker.js +63 -3
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +17 -4
- package/dist/sync-client.js.map +1 -1
- package/dist/sync-ledger.d.ts +8 -1
- package/dist/sync-ledger.d.ts.map +1 -1
- package/dist/sync-ledger.js +121 -18
- package/dist/sync-ledger.js.map +1 -1
- package/dist/watch.js +373 -236
- package/package.json +1 -1
package/dist/watch.js
CHANGED
|
@@ -4458,7 +4458,7 @@ var require_pino = __commonJS({
|
|
|
4458
4458
|
messageKey,
|
|
4459
4459
|
errorKey,
|
|
4460
4460
|
nestedKey,
|
|
4461
|
-
base:
|
|
4461
|
+
base: base3,
|
|
4462
4462
|
name,
|
|
4463
4463
|
level: level2,
|
|
4464
4464
|
customLevels,
|
|
@@ -4497,11 +4497,11 @@ var require_pino = __commonJS({
|
|
|
4497
4497
|
[formattersSym]: allFormatters
|
|
4498
4498
|
});
|
|
4499
4499
|
let chindings = "";
|
|
4500
|
-
if (
|
|
4500
|
+
if (base3 !== null) {
|
|
4501
4501
|
if (name === void 0) {
|
|
4502
|
-
chindings = coreChindings(
|
|
4502
|
+
chindings = coreChindings(base3);
|
|
4503
4503
|
} else {
|
|
4504
|
-
chindings = coreChindings(Object.assign({},
|
|
4504
|
+
chindings = coreChindings(Object.assign({}, base3, { name }));
|
|
4505
4505
|
}
|
|
4506
4506
|
}
|
|
4507
4507
|
const time2 = timestamp instanceof Function ? timestamp : timestamp ? epochTime : nullTime;
|
|
@@ -4881,57 +4881,57 @@ function freshDefaults() {
|
|
|
4881
4881
|
team: defaultTeam()
|
|
4882
4882
|
};
|
|
4883
4883
|
}
|
|
4884
|
-
function mergeSources(
|
|
4884
|
+
function mergeSources(base3, partial) {
|
|
4885
4885
|
if (!partial)
|
|
4886
|
-
return
|
|
4886
|
+
return base3;
|
|
4887
4887
|
const legacyGemini = partial.enabled?.gemini;
|
|
4888
4888
|
const inherited = legacyGemini && typeof legacyGemini === "object" ? (({ sessions: _s, plans: _p, ...rest }) => rest)(legacyGemini) : {};
|
|
4889
4889
|
const enabled = {
|
|
4890
|
-
claude: { ...
|
|
4891
|
-
opencode: { ...
|
|
4892
|
-
codex: { ...
|
|
4893
|
-
agy: { ...
|
|
4894
|
-
cursor: { ...
|
|
4895
|
-
shared: { ...
|
|
4896
|
-
common: { ...
|
|
4890
|
+
claude: { ...base3.enabled.claude, ...partial.enabled?.claude ?? {} },
|
|
4891
|
+
opencode: { ...base3.enabled.opencode, ...partial.enabled?.opencode ?? {} },
|
|
4892
|
+
codex: { ...base3.enabled.codex, ...partial.enabled?.codex ?? {} },
|
|
4893
|
+
agy: { ...base3.enabled.agy, ...inherited, ...partial.enabled?.agy ?? {} },
|
|
4894
|
+
cursor: { ...base3.enabled.cursor, ...partial.enabled?.cursor ?? {} },
|
|
4895
|
+
shared: { ...base3.enabled.shared, ...partial.enabled?.shared ?? {} },
|
|
4896
|
+
common: { ...base3.enabled.common, ...partial.enabled?.common ?? {} }
|
|
4897
4897
|
};
|
|
4898
4898
|
return {
|
|
4899
|
-
claudeHome: partial.claudeHome ??
|
|
4900
|
-
geminiHome: partial.geminiHome ??
|
|
4901
|
-
codexHome: partial.codexHome ??
|
|
4902
|
-
opencodeDbPath: partial.opencodeDbPath ??
|
|
4903
|
-
agyHome: partial.agyHome ??
|
|
4904
|
-
cursorHome: partial.cursorHome ??
|
|
4905
|
-
cursorIdeHome: partial.cursorIdeHome ??
|
|
4906
|
-
extraClaudeHomes: partial.extraClaudeHomes ??
|
|
4907
|
-
approvedHomes: partial.approvedHomes ??
|
|
4908
|
-
declinedHomes: partial.declinedHomes ??
|
|
4909
|
-
homesGrandfathered: partial.homesGrandfathered ??
|
|
4899
|
+
claudeHome: partial.claudeHome ?? base3.claudeHome,
|
|
4900
|
+
geminiHome: partial.geminiHome ?? base3.geminiHome,
|
|
4901
|
+
codexHome: partial.codexHome ?? base3.codexHome,
|
|
4902
|
+
opencodeDbPath: partial.opencodeDbPath ?? base3.opencodeDbPath,
|
|
4903
|
+
agyHome: partial.agyHome ?? base3.agyHome,
|
|
4904
|
+
cursorHome: partial.cursorHome ?? base3.cursorHome,
|
|
4905
|
+
cursorIdeHome: partial.cursorIdeHome ?? base3.cursorIdeHome,
|
|
4906
|
+
extraClaudeHomes: partial.extraClaudeHomes ?? base3.extraClaudeHomes,
|
|
4907
|
+
approvedHomes: partial.approvedHomes ?? base3.approvedHomes,
|
|
4908
|
+
declinedHomes: partial.declinedHomes ?? base3.declinedHomes,
|
|
4909
|
+
homesGrandfathered: partial.homesGrandfathered ?? base3.homesGrandfathered,
|
|
4910
4910
|
enabled
|
|
4911
4911
|
};
|
|
4912
4912
|
}
|
|
4913
|
-
function mergePrivacy(
|
|
4913
|
+
function mergePrivacy(base3, partial) {
|
|
4914
4914
|
if (!partial)
|
|
4915
|
-
return
|
|
4916
|
-
return { ...
|
|
4915
|
+
return base3;
|
|
4916
|
+
return { ...base3, ...partial };
|
|
4917
4917
|
}
|
|
4918
|
-
function mergeSync(
|
|
4918
|
+
function mergeSync(base3, partial) {
|
|
4919
4919
|
if (!partial)
|
|
4920
|
-
return
|
|
4920
|
+
return base3;
|
|
4921
4921
|
return {
|
|
4922
|
-
...
|
|
4922
|
+
...base3,
|
|
4923
4923
|
...partial,
|
|
4924
|
-
upload: { ...
|
|
4924
|
+
upload: { ...base3.upload, ...partial.upload ?? {} }
|
|
4925
4925
|
};
|
|
4926
4926
|
}
|
|
4927
|
-
function mergeTeam(
|
|
4927
|
+
function mergeTeam(base3, partial) {
|
|
4928
4928
|
if (!partial)
|
|
4929
|
-
return
|
|
4929
|
+
return base3;
|
|
4930
4930
|
return {
|
|
4931
|
-
...
|
|
4931
|
+
...base3,
|
|
4932
4932
|
...partial,
|
|
4933
|
-
publishAllowed: { ...
|
|
4934
|
-
vault: { ...
|
|
4933
|
+
publishAllowed: { ...base3.publishAllowed, ...partial.publishAllowed ?? {} },
|
|
4934
|
+
vault: { ...base3.vault, ...partial.vault ?? {} }
|
|
4935
4935
|
};
|
|
4936
4936
|
}
|
|
4937
4937
|
function settingsFilePath() {
|
|
@@ -5040,15 +5040,15 @@ function loadSettings() {
|
|
|
5040
5040
|
}
|
|
5041
5041
|
try {
|
|
5042
5042
|
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
5043
|
-
const
|
|
5043
|
+
const base3 = freshDefaults();
|
|
5044
5044
|
const result = {
|
|
5045
5045
|
v: SCHEMA_VERSION,
|
|
5046
|
-
embedding: { ...
|
|
5047
|
-
summary: { ...
|
|
5048
|
-
sources: mergeSources(
|
|
5049
|
-
privacy: mergePrivacy(
|
|
5050
|
-
sync: mergeSync(
|
|
5051
|
-
team: mergeTeam(
|
|
5046
|
+
embedding: { ...base3.embedding, ...parsed.embedding ?? {} },
|
|
5047
|
+
summary: { ...base3.summary, ...parsed.summary ?? {} },
|
|
5048
|
+
sources: mergeSources(base3.sources, parsed.sources),
|
|
5049
|
+
privacy: mergePrivacy(base3.privacy, parsed.privacy),
|
|
5050
|
+
sync: mergeSync(base3.sync, parsed.sync),
|
|
5051
|
+
team: mergeTeam(base3.team, parsed.team)
|
|
5052
5052
|
};
|
|
5053
5053
|
if (mtimeMs >= 0)
|
|
5054
5054
|
_settingsCache = { mtimeMs, size, value: structuredClone(result) };
|
|
@@ -5154,10 +5154,10 @@ function legacyAutoSyncedHomes() {
|
|
|
5154
5154
|
{ base: join3(home, ".local", "share", "opencode"), marker: "opencode.db" },
|
|
5155
5155
|
{ base: join3(home, ".cursor"), marker: "chats" }
|
|
5156
5156
|
];
|
|
5157
|
-
for (const { base:
|
|
5158
|
-
add(
|
|
5159
|
-
const parent = dirname3(
|
|
5160
|
-
const leaf =
|
|
5157
|
+
for (const { base: base3, marker } of bases) {
|
|
5158
|
+
add(base3, marker);
|
|
5159
|
+
const parent = dirname3(base3);
|
|
5160
|
+
const leaf = base3.slice(parent.length + 1);
|
|
5161
5161
|
try {
|
|
5162
5162
|
for (const e of readdirSync2(parent, { withFileTypes: true })) {
|
|
5163
5163
|
if (!e.isDirectory())
|
|
@@ -5338,17 +5338,17 @@ function cursorHomeDir() {
|
|
|
5338
5338
|
function cursorIdeHomeDir() {
|
|
5339
5339
|
return process.env.CHAT_RECALL_CURSOR_IDE_HOME || sources().cursorIdeHome || (process.platform === "darwin" ? join4(homedir3(), "Library", "Application Support", "Cursor") : join4(homedir3(), ".config", "Cursor"));
|
|
5340
5340
|
}
|
|
5341
|
-
function siblingHomes(
|
|
5341
|
+
function siblingHomes(base3, overridden, suffix) {
|
|
5342
5342
|
const roots = [];
|
|
5343
5343
|
const add = (home) => {
|
|
5344
5344
|
const root = suffix ? join4(home, suffix) : home;
|
|
5345
5345
|
if (existsSync4(root) && !roots.includes(root))
|
|
5346
5346
|
roots.push(root);
|
|
5347
5347
|
};
|
|
5348
|
-
add(
|
|
5348
|
+
add(base3);
|
|
5349
5349
|
if (!overridden) {
|
|
5350
|
-
const parent = dirname4(
|
|
5351
|
-
const leaf = basename(
|
|
5350
|
+
const parent = dirname4(base3);
|
|
5351
|
+
const leaf = basename(base3);
|
|
5352
5352
|
try {
|
|
5353
5353
|
for (const entry of readdirSync3(parent, { withFileTypes: true })) {
|
|
5354
5354
|
if (!entry.isDirectory())
|
|
@@ -5844,9 +5844,9 @@ async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
|
5844
5844
|
content.metadata.durationMs += obj.durationMs;
|
|
5845
5845
|
}
|
|
5846
5846
|
if (msgType === "file-history-snapshot") {
|
|
5847
|
-
const
|
|
5848
|
-
if (
|
|
5849
|
-
const backups =
|
|
5847
|
+
const snapshot2 = obj.snapshot;
|
|
5848
|
+
if (snapshot2 && typeof snapshot2 === "object") {
|
|
5849
|
+
const backups = snapshot2.trackedFileBackups;
|
|
5850
5850
|
if (backups && typeof backups === "object") {
|
|
5851
5851
|
for (const filePath2 of Object.keys(backups)) {
|
|
5852
5852
|
filesModified.add(filePath2);
|
|
@@ -7973,7 +7973,64 @@ var init_first_prompt = __esm({
|
|
|
7973
7973
|
});
|
|
7974
7974
|
|
|
7975
7975
|
// ../engine/dist/core/backends/tail-read.js
|
|
7976
|
-
import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync6 } from "node:fs";
|
|
7976
|
+
import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync6, fstatSync } from "node:fs";
|
|
7977
|
+
function readAt(fd, pos, len) {
|
|
7978
|
+
const buf = Buffer.alloc(len);
|
|
7979
|
+
let got = 0;
|
|
7980
|
+
while (got < len) {
|
|
7981
|
+
const n = readSync5(fd, buf, got, len - got, pos + got);
|
|
7982
|
+
if (n <= 0)
|
|
7983
|
+
break;
|
|
7984
|
+
got += n;
|
|
7985
|
+
}
|
|
7986
|
+
return buf.subarray(0, got);
|
|
7987
|
+
}
|
|
7988
|
+
function linesBeforeOffset(path, offset) {
|
|
7989
|
+
if (offset <= 0)
|
|
7990
|
+
return 0;
|
|
7991
|
+
let fd = null;
|
|
7992
|
+
try {
|
|
7993
|
+
fd = openSync5(path, "r");
|
|
7994
|
+
const ino = fstatSync(fd).ino;
|
|
7995
|
+
const known = lineCounts.get(path);
|
|
7996
|
+
let pos = 0;
|
|
7997
|
+
let lines = 0;
|
|
7998
|
+
if (known && known.ino === ino && known.offset <= offset) {
|
|
7999
|
+
const edgeStart2 = Math.max(0, known.offset - EDGE_BYTES);
|
|
8000
|
+
if (readAt(fd, edgeStart2, known.offset - edgeStart2).equals(known.edge)) {
|
|
8001
|
+
pos = known.offset;
|
|
8002
|
+
lines = known.lines;
|
|
8003
|
+
}
|
|
8004
|
+
}
|
|
8005
|
+
const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
|
|
8006
|
+
while (pos < offset) {
|
|
8007
|
+
const n = readSync5(fd, block, 0, Math.min(SKIP_SCAN_BYTES, offset - pos), pos);
|
|
8008
|
+
if (n <= 0)
|
|
8009
|
+
return void 0;
|
|
8010
|
+
for (let i = block.indexOf(10, 0); i >= 0 && i < n; i = block.indexOf(10, i + 1))
|
|
8011
|
+
lines++;
|
|
8012
|
+
pos += n;
|
|
8013
|
+
}
|
|
8014
|
+
const edgeStart = Math.max(0, offset - EDGE_BYTES);
|
|
8015
|
+
const edge = readAt(fd, edgeStart, offset - edgeStart);
|
|
8016
|
+
if (lineCounts.size >= LINE_COUNT_CACHE_MAX && !lineCounts.has(path)) {
|
|
8017
|
+
const oldest = lineCounts.keys().next().value;
|
|
8018
|
+
if (oldest !== void 0)
|
|
8019
|
+
lineCounts.delete(oldest);
|
|
8020
|
+
}
|
|
8021
|
+
lineCounts.set(path, { offset, lines, ino, edge });
|
|
8022
|
+
return lines;
|
|
8023
|
+
} catch {
|
|
8024
|
+
return void 0;
|
|
8025
|
+
} finally {
|
|
8026
|
+
if (fd !== null) {
|
|
8027
|
+
try {
|
|
8028
|
+
closeSync5(fd);
|
|
8029
|
+
} catch {
|
|
8030
|
+
}
|
|
8031
|
+
}
|
|
8032
|
+
}
|
|
8033
|
+
}
|
|
7977
8034
|
function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
|
|
7978
8035
|
let size = 0;
|
|
7979
8036
|
try {
|
|
@@ -8001,7 +8058,7 @@ function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
|
|
|
8001
8058
|
const lastNl = slice.lastIndexOf(10);
|
|
8002
8059
|
if (lastNl >= 0) {
|
|
8003
8060
|
const text = slice.subarray(0, lastNl + 1).toString("utf-8");
|
|
8004
|
-
return { text, newOffset: offset + lastNl + 1 };
|
|
8061
|
+
return { text, newOffset: offset + lastNl + 1, baseLine: linesBeforeOffset(path, offset) };
|
|
8005
8062
|
}
|
|
8006
8063
|
if (offset + got >= size)
|
|
8007
8064
|
return { text: "", newOffset: offset };
|
|
@@ -8034,12 +8091,15 @@ function findNewline(fd, from, size) {
|
|
|
8034
8091
|
}
|
|
8035
8092
|
return -1;
|
|
8036
8093
|
}
|
|
8037
|
-
var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES;
|
|
8094
|
+
var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES, lineCounts, LINE_COUNT_CACHE_MAX, EDGE_BYTES;
|
|
8038
8095
|
var init_tail_read = __esm({
|
|
8039
8096
|
"../engine/dist/core/backends/tail-read.js"() {
|
|
8040
8097
|
"use strict";
|
|
8041
8098
|
TAIL_READ_MAX_BYTES = 16 * 1024 * 1024;
|
|
8042
8099
|
SKIP_SCAN_BYTES = 1024 * 1024;
|
|
8100
|
+
lineCounts = /* @__PURE__ */ new Map();
|
|
8101
|
+
LINE_COUNT_CACHE_MAX = 2048;
|
|
8102
|
+
EDGE_BYTES = 64;
|
|
8043
8103
|
}
|
|
8044
8104
|
});
|
|
8045
8105
|
|
|
@@ -12280,8 +12340,8 @@ function serverRulePackVersion() {
|
|
|
12280
12340
|
return serverPack ? serverPack.version || "unversioned" : null;
|
|
12281
12341
|
}
|
|
12282
12342
|
function activeRules() {
|
|
12283
|
-
const
|
|
12284
|
-
return serverPack && serverPack.rules.length > 0 ? [...
|
|
12343
|
+
const base3 = settingsView().rules;
|
|
12344
|
+
return serverPack && serverPack.rules.length > 0 ? [...base3, ...serverPack.rules] : base3;
|
|
12285
12345
|
}
|
|
12286
12346
|
function isRedactionEnabled() {
|
|
12287
12347
|
const env = isEnvRedactionRequested();
|
|
@@ -18064,7 +18124,7 @@ __export(sync_ledger_exports, {
|
|
|
18064
18124
|
syncMode: () => syncMode,
|
|
18065
18125
|
unackedCursorAttemptCount: () => unackedCursorAttemptCount
|
|
18066
18126
|
});
|
|
18067
|
-
import { readFileSync as readFileSync30, writeFileSync as writeFileSync6, renameSync as renameSync4, mkdirSync as mkdirSync7 } from "node:fs";
|
|
18127
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync6, renameSync as renameSync4, mkdirSync as mkdirSync7, statSync as statSync35 } from "node:fs";
|
|
18068
18128
|
import { join as join39, dirname as dirname16 } from "node:path";
|
|
18069
18129
|
function toRow(entry) {
|
|
18070
18130
|
if (entry === void 0) return void 0;
|
|
@@ -18073,32 +18133,94 @@ function toRow(entry) {
|
|
|
18073
18133
|
function ledgerFilePath() {
|
|
18074
18134
|
return ledgerPath();
|
|
18075
18135
|
}
|
|
18076
|
-
function
|
|
18077
|
-
|
|
18136
|
+
function stampOf(path) {
|
|
18137
|
+
try {
|
|
18138
|
+
const st = statSync35(path);
|
|
18139
|
+
return `${st.mtimeMs}:${st.size}`;
|
|
18140
|
+
} catch {
|
|
18141
|
+
return null;
|
|
18142
|
+
}
|
|
18143
|
+
}
|
|
18144
|
+
function readDisk(path) {
|
|
18078
18145
|
try {
|
|
18079
|
-
const parsed = JSON.parse(readFileSync30(
|
|
18080
|
-
|
|
18146
|
+
const parsed = JSON.parse(readFileSync30(path, "utf-8"));
|
|
18147
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
18081
18148
|
} catch {
|
|
18082
|
-
|
|
18149
|
+
return {};
|
|
18150
|
+
}
|
|
18151
|
+
}
|
|
18152
|
+
function snapshot(data) {
|
|
18153
|
+
const out = /* @__PURE__ */ new Map();
|
|
18154
|
+
for (const [server, rows] of Object.entries(data)) {
|
|
18155
|
+
for (const [id, entry] of Object.entries(rows)) out.set(rowKey(server, id), JSON.stringify(entry));
|
|
18156
|
+
}
|
|
18157
|
+
return out;
|
|
18158
|
+
}
|
|
18159
|
+
function mergeOnto(disk) {
|
|
18160
|
+
const out = {};
|
|
18161
|
+
const put = (server, id, entry) => {
|
|
18162
|
+
(out[server] ??= {})[id] = entry;
|
|
18163
|
+
};
|
|
18164
|
+
const mine = cache3 ?? {};
|
|
18165
|
+
for (const [server, rows] of Object.entries(disk)) {
|
|
18166
|
+
for (const [id, entry] of Object.entries(rows)) {
|
|
18167
|
+
const k = rowKey(server, id);
|
|
18168
|
+
const own = mine[server]?.[id];
|
|
18169
|
+
const was = base.get(k);
|
|
18170
|
+
if (own === void 0) {
|
|
18171
|
+
if (was === void 0) put(server, id, entry);
|
|
18172
|
+
} else {
|
|
18173
|
+
put(server, id, JSON.stringify(own) === was ? entry : own);
|
|
18174
|
+
}
|
|
18175
|
+
}
|
|
18176
|
+
}
|
|
18177
|
+
for (const [server, rows] of Object.entries(mine)) {
|
|
18178
|
+
for (const [id, entry] of Object.entries(rows)) {
|
|
18179
|
+
if (disk[server]?.[id] !== void 0) continue;
|
|
18180
|
+
if (JSON.stringify(entry) !== base.get(rowKey(server, id))) put(server, id, entry);
|
|
18181
|
+
}
|
|
18083
18182
|
}
|
|
18183
|
+
return out;
|
|
18184
|
+
}
|
|
18185
|
+
function load() {
|
|
18186
|
+
const path = ledgerPath();
|
|
18187
|
+
const stamp2 = stampOf(path);
|
|
18188
|
+
if (cache3 && stamp2 === diskStamp) return cache3;
|
|
18189
|
+
const disk = readDisk(path);
|
|
18190
|
+
const merged = cache3 ? mergeOnto(disk) : disk;
|
|
18191
|
+
if (cache3) {
|
|
18192
|
+
for (const server of Object.keys(cache3)) if (!(server in merged)) delete cache3[server];
|
|
18193
|
+
for (const [server, rows] of Object.entries(merged)) {
|
|
18194
|
+
const target = cache3[server] ?? (cache3[server] = {});
|
|
18195
|
+
for (const id of Object.keys(target)) if (!(id in rows)) delete target[id];
|
|
18196
|
+
Object.assign(target, rows);
|
|
18197
|
+
}
|
|
18198
|
+
} else {
|
|
18199
|
+
cache3 = merged;
|
|
18200
|
+
}
|
|
18201
|
+
base = snapshot(disk);
|
|
18202
|
+
diskStamp = stamp2;
|
|
18084
18203
|
return cache3;
|
|
18085
18204
|
}
|
|
18086
|
-
function persistNow(
|
|
18205
|
+
function persistNow() {
|
|
18087
18206
|
const path = ledgerPath();
|
|
18088
18207
|
mkdirSync7(dirname16(path), { recursive: true });
|
|
18089
|
-
|
|
18090
|
-
|
|
18208
|
+
load();
|
|
18209
|
+
const tmp = `${path}.tmp-${process.pid}`;
|
|
18210
|
+
writeFileSync6(tmp, JSON.stringify(cache3 ?? {}));
|
|
18091
18211
|
renameSync4(tmp, path);
|
|
18212
|
+
base = snapshot(cache3 ?? {});
|
|
18213
|
+
diskStamp = stampOf(path);
|
|
18092
18214
|
pendingWrite = false;
|
|
18093
18215
|
}
|
|
18094
|
-
function persist(
|
|
18216
|
+
function persist(_data) {
|
|
18095
18217
|
pendingWrite = true;
|
|
18096
18218
|
if (flushTimer) return;
|
|
18097
18219
|
flushTimer = setTimeout(() => {
|
|
18098
18220
|
flushTimer = null;
|
|
18099
18221
|
if (pendingWrite) {
|
|
18100
18222
|
try {
|
|
18101
|
-
persistNow(
|
|
18223
|
+
persistNow();
|
|
18102
18224
|
} catch {
|
|
18103
18225
|
}
|
|
18104
18226
|
}
|
|
@@ -18132,7 +18254,7 @@ function pruneLedgerTargets(configuredServers) {
|
|
|
18132
18254
|
}
|
|
18133
18255
|
const rows = names.reduce((n, s) => n + Object.keys(orphans[s]).length, 0);
|
|
18134
18256
|
console.error(`[sync] tidied local bookkeeping: ${rows} already-synced marker(s) for ${names.length} server(s) you no longer sync to (${names.join(", ")}) moved to ${side}. Nothing was uploaded there; the file is kept so logging back in re-ships nothing.`);
|
|
18135
|
-
persistNow(
|
|
18257
|
+
persistNow();
|
|
18136
18258
|
return names.length;
|
|
18137
18259
|
}
|
|
18138
18260
|
function flushLedger() {
|
|
@@ -18141,7 +18263,7 @@ function flushLedger() {
|
|
|
18141
18263
|
flushTimer = null;
|
|
18142
18264
|
}
|
|
18143
18265
|
if (!pendingWrite || !cache3) return;
|
|
18144
|
-
persistNow(
|
|
18266
|
+
persistNow();
|
|
18145
18267
|
}
|
|
18146
18268
|
function loadItemVersionsAll() {
|
|
18147
18269
|
if (itemVersionsCache) return itemVersionsCache;
|
|
@@ -18207,6 +18329,7 @@ function persistLedgerData(server, serverData) {
|
|
|
18207
18329
|
const data = load();
|
|
18208
18330
|
data[server] = serverData;
|
|
18209
18331
|
persist(data);
|
|
18332
|
+
flushLedger();
|
|
18210
18333
|
}
|
|
18211
18334
|
function unackedCursorAttemptCount() {
|
|
18212
18335
|
return unackedCursorAttempts;
|
|
@@ -18229,13 +18352,13 @@ function markSynced(server, rows) {
|
|
|
18229
18352
|
const o = (cursorFromCaller ? r.offset : void 0) ?? prevOS.o ?? 0;
|
|
18230
18353
|
const s = (cursorFromCaller ? r.size : void 0) ?? prevOS.s ?? 0;
|
|
18231
18354
|
const ev = extractorVersionForId(r.id);
|
|
18232
|
-
const
|
|
18355
|
+
const base3 = prevF ? { m: Math.floor(r.mtime), v: ev, f: prevF } : { m: Math.floor(r.mtime), v: ev };
|
|
18233
18356
|
if (o > 0 || s > 0) {
|
|
18234
|
-
|
|
18235
|
-
|
|
18357
|
+
base3.o = o;
|
|
18358
|
+
base3.s = s;
|
|
18236
18359
|
}
|
|
18237
|
-
if (r.hash !== void 0)
|
|
18238
|
-
forServer[r.id] =
|
|
18360
|
+
if (r.hash !== void 0) base3.h = r.hash;
|
|
18361
|
+
forServer[r.id] = base3;
|
|
18239
18362
|
}
|
|
18240
18363
|
persist(data);
|
|
18241
18364
|
}
|
|
@@ -18304,6 +18427,8 @@ function forceFieldRescan(fieldName, server) {
|
|
|
18304
18427
|
function _resetLedgerCacheForTests() {
|
|
18305
18428
|
flushLedger();
|
|
18306
18429
|
cache3 = null;
|
|
18430
|
+
base = /* @__PURE__ */ new Map();
|
|
18431
|
+
diskStamp = null;
|
|
18307
18432
|
reconcileCache = null;
|
|
18308
18433
|
}
|
|
18309
18434
|
function markFullResync(server, sessionId) {
|
|
@@ -18325,7 +18450,7 @@ function syncMode(row, mtime, fileSize, extractorVersion, isAppendOnly) {
|
|
|
18325
18450
|
if (row.m >= Math.floor(mtime)) return "skip";
|
|
18326
18451
|
return "full";
|
|
18327
18452
|
}
|
|
18328
|
-
var ledgerPath, cache3, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
18453
|
+
var ledgerPath, cache3, base, diskStamp, rowKey, LEDGER_FLUSH_MS, pendingWrite, flushTimer, itemVersionsPath, itemVersionsCache, inventoryPath, unackedCursorAttempts, reconcilePath, reconcileCache;
|
|
18329
18454
|
var init_sync_ledger = __esm({
|
|
18330
18455
|
"src/sync-ledger.ts"() {
|
|
18331
18456
|
"use strict";
|
|
@@ -18333,6 +18458,9 @@ var init_sync_ledger = __esm({
|
|
|
18333
18458
|
init_extractor_version();
|
|
18334
18459
|
ledgerPath = () => join39(getDataDir(), "sync-ledger.json");
|
|
18335
18460
|
cache3 = null;
|
|
18461
|
+
base = /* @__PURE__ */ new Map();
|
|
18462
|
+
diskStamp = null;
|
|
18463
|
+
rowKey = (server, id) => `${server}\0${id}`;
|
|
18336
18464
|
LEDGER_FLUSH_MS = 2e3;
|
|
18337
18465
|
pendingWrite = false;
|
|
18338
18466
|
flushTimer = null;
|
|
@@ -18371,7 +18499,7 @@ var init_sync_fields = __esm({
|
|
|
18371
18499
|
});
|
|
18372
18500
|
|
|
18373
18501
|
// ../engine/dist/core/index-lock.js
|
|
18374
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as
|
|
18502
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as statSync36, closeSync as closeSync8 } from "fs";
|
|
18375
18503
|
import { dirname as dirname17, join as join40 } from "path";
|
|
18376
18504
|
function acquireIndexLock(opts) {
|
|
18377
18505
|
const lockPath = lockFilePath(opts.file);
|
|
@@ -18421,7 +18549,7 @@ function lockFilePath(file = ".compact.lock") {
|
|
|
18421
18549
|
}
|
|
18422
18550
|
function stealStaleLock(lockPath, staleAfterMs) {
|
|
18423
18551
|
try {
|
|
18424
|
-
const s =
|
|
18552
|
+
const s = statSync36(lockPath);
|
|
18425
18553
|
const age = Date.now() - s.mtimeMs;
|
|
18426
18554
|
let payload;
|
|
18427
18555
|
try {
|
|
@@ -18484,7 +18612,7 @@ var init_http = __esm({
|
|
|
18484
18612
|
CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
18485
18613
|
} catch {
|
|
18486
18614
|
try {
|
|
18487
|
-
if (true) CLI_VERSION = "0.7.
|
|
18615
|
+
if (true) CLI_VERSION = "0.7.16";
|
|
18488
18616
|
} catch {
|
|
18489
18617
|
}
|
|
18490
18618
|
}
|
|
@@ -18978,7 +19106,7 @@ var init_telemetry = __esm({
|
|
|
18978
19106
|
init_sync_client();
|
|
18979
19107
|
cliVersion = () => {
|
|
18980
19108
|
try {
|
|
18981
|
-
return true ? "0.7.
|
|
19109
|
+
return true ? "0.7.16" : "dev";
|
|
18982
19110
|
} catch {
|
|
18983
19111
|
return "dev";
|
|
18984
19112
|
}
|
|
@@ -19001,11 +19129,11 @@ __export(server_probe_exports, {
|
|
|
19001
19129
|
function probeOk(r) {
|
|
19002
19130
|
return r.kind === "ok" && r.apiVersion >= 2;
|
|
19003
19131
|
}
|
|
19004
|
-
async function probeServer(
|
|
19132
|
+
async function probeServer(base3, opts = {}) {
|
|
19005
19133
|
const f = opts.fetchImpl || fetch;
|
|
19006
19134
|
let res;
|
|
19007
19135
|
try {
|
|
19008
|
-
res = await f(`${
|
|
19136
|
+
res = await f(`${base3.replace(/\/+$/, "")}/api/capabilities`, {
|
|
19009
19137
|
signal: AbortSignal.timeout(opts.timeoutMs ?? 1e4)
|
|
19010
19138
|
});
|
|
19011
19139
|
} catch (err) {
|
|
@@ -19042,34 +19170,34 @@ async function probeServer(base2, opts = {}) {
|
|
|
19042
19170
|
raw: parsed
|
|
19043
19171
|
};
|
|
19044
19172
|
}
|
|
19045
|
-
function probeAdvice(r,
|
|
19173
|
+
function probeAdvice(r, base3) {
|
|
19046
19174
|
switch (r.kind) {
|
|
19047
19175
|
case "ok":
|
|
19048
19176
|
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`;
|
|
19049
19177
|
case "moved":
|
|
19050
|
-
return `HTTP ${r.status} \u2014 nothing is served at ${
|
|
19178
|
+
return `HTTP ${r.status} \u2014 nothing is served at ${base3}. If the host moved, re-point it: \`chat-recall login <new-server-url>\``;
|
|
19051
19179
|
case "unauthorized":
|
|
19052
|
-
return `HTTP ${r.status} \u2014 ${
|
|
19180
|
+
return `HTTP ${r.status} \u2014 ${base3} rejected the credential. Re-login: \`chat-recall login ` + base3 + "`";
|
|
19053
19181
|
case "server_error":
|
|
19054
|
-
return `HTTP ${r.status} \u2014 ${
|
|
19182
|
+
return `HTTP ${r.status} \u2014 ${base3} is up but failing. Nothing to fix locally; check the server.`;
|
|
19055
19183
|
case "not_api":
|
|
19056
|
-
return `${
|
|
19184
|
+
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`;
|
|
19057
19185
|
case "unreachable":
|
|
19058
19186
|
switch (r.reason) {
|
|
19059
19187
|
case "dns":
|
|
19060
|
-
return `cannot resolve the host in ${
|
|
19188
|
+
return `cannot resolve the host in ${base3} (${r.error}) \u2014 check the URL for a typo, and your DNS or VPN`;
|
|
19061
19189
|
case "refused":
|
|
19062
|
-
return `${
|
|
19190
|
+
return `${base3} resolves but refused the connection (${r.error}) \u2014 the server is not running, or the port is wrong`;
|
|
19063
19191
|
case "tls":
|
|
19064
|
-
return `the TLS certificate at ${
|
|
19192
|
+
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.`;
|
|
19065
19193
|
case "timeout":
|
|
19066
|
-
return `${
|
|
19194
|
+
return `${base3} did not answer in time (${r.error}) \u2014 a firewall or proxy that drops traffic silently looks exactly like this`;
|
|
19067
19195
|
case "reset":
|
|
19068
|
-
return `the connection to ${
|
|
19196
|
+
return `the connection to ${base3} was cut (${r.error}) \u2014 often a proxy or a captive portal`;
|
|
19069
19197
|
case "bad_port":
|
|
19070
|
-
return `${
|
|
19198
|
+
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`;
|
|
19071
19199
|
default:
|
|
19072
|
-
return `no HTTP response from ${
|
|
19200
|
+
return `no HTTP response from ${base3} (${r.error}) \u2014 check the URL, DNS, or that the server is running`;
|
|
19073
19201
|
}
|
|
19074
19202
|
}
|
|
19075
19203
|
}
|
|
@@ -19102,8 +19230,8 @@ function describeCause(err) {
|
|
|
19102
19230
|
const code = e.code;
|
|
19103
19231
|
if (typeof code === "string" && code && !parts.includes(code)) parts.push(code);
|
|
19104
19232
|
}
|
|
19105
|
-
const
|
|
19106
|
-
return parts.length ? `${
|
|
19233
|
+
const base3 = err instanceof Error ? err.message : String(err);
|
|
19234
|
+
return parts.length ? `${base3}: ${parts.join(" \u2192 ")}` : base3;
|
|
19107
19235
|
}
|
|
19108
19236
|
function describeUnreachable(err) {
|
|
19109
19237
|
const reason = classifyUnreachable(err);
|
|
@@ -19216,7 +19344,7 @@ __export(auto_update_exports, {
|
|
|
19216
19344
|
import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
|
|
19217
19345
|
import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
|
|
19218
19346
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
19219
|
-
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as
|
|
19347
|
+
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync30, statSync as statSync37, mkdirSync as mkdirSync9 } from "node:fs";
|
|
19220
19348
|
import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
19221
19349
|
import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
|
|
19222
19350
|
import { createHash as createHash7 } from "node:crypto";
|
|
@@ -19248,12 +19376,12 @@ function installedVersion() {
|
|
|
19248
19376
|
return null;
|
|
19249
19377
|
}
|
|
19250
19378
|
}
|
|
19251
|
-
function planAutoUpdate(
|
|
19379
|
+
function planAutoUpdate(base3, caps, ownVersion3, flag) {
|
|
19252
19380
|
const rel = caps.cli;
|
|
19253
19381
|
if (!rel || !rel.version || !rel.sha256) return { update: false, reason: "server advertises no CLI release" };
|
|
19254
19382
|
if (!isAutoUpdateEnabled(caps.edition, flag)) return { update: false, reason: `auto-update disabled (edition ${caps.edition ?? "?"})` };
|
|
19255
19383
|
if (compareVersions(rel.version, ownVersion3) <= 0) return { update: false, reason: `already current (own ${ownVersion3} >= server ${rel.version})` };
|
|
19256
|
-
return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(
|
|
19384
|
+
return { update: true, reason: `server ${rel.version} > own ${ownVersion3}`, url: tarballUrl(base3, rel.version), fallbackUrl: tarballUrl(base3), sha256: rel.sha256, from: ownVersion3, to: rel.version };
|
|
19257
19385
|
}
|
|
19258
19386
|
function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
19259
19387
|
const MKDTEMP_SUFFIX = /^cr-update-.{6}$/s;
|
|
@@ -19269,7 +19397,7 @@ function sweepStaleStaging(root = tmpdir2(), now = Date.now()) {
|
|
|
19269
19397
|
if (!MKDTEMP_SUFFIX.test(name)) continue;
|
|
19270
19398
|
const dir = join41(root, name);
|
|
19271
19399
|
try {
|
|
19272
|
-
const st =
|
|
19400
|
+
const st = statSync37(dir);
|
|
19273
19401
|
if (!st.isDirectory() || now - st.mtimeMs < COLD_MS) continue;
|
|
19274
19402
|
const inside = readdirSync30(dir);
|
|
19275
19403
|
if (inside.length > 1 || inside.length === 1 && inside[0] !== "chat-recall.tgz") continue;
|
|
@@ -19433,20 +19561,20 @@ function clearUpdateFailures() {
|
|
|
19433
19561
|
function stopAutoUpdates() {
|
|
19434
19562
|
stopRequested = true;
|
|
19435
19563
|
}
|
|
19436
|
-
async function runAutoUpdate(
|
|
19564
|
+
async function runAutoUpdate(base3, authHeaders, ownVersion3, deps) {
|
|
19437
19565
|
let caps;
|
|
19438
19566
|
try {
|
|
19439
|
-
const res = await fetchWithTimeout(`${
|
|
19567
|
+
const res = await fetchWithTimeout(`${base3.replace(/\/+$/, "")}/api/capabilities`, { headers: authHeaders });
|
|
19440
19568
|
if (!res.ok) return { updated: false, reason: `capabilities HTTP ${res.status}` };
|
|
19441
19569
|
caps = await res.json();
|
|
19442
19570
|
} catch (e) {
|
|
19443
19571
|
return { updated: false, reason: `capabilities unreachable: ${e instanceof Error ? e.message : e}` };
|
|
19444
19572
|
}
|
|
19445
19573
|
const effectiveOwn = newerOf(ownVersion3, installedVersion());
|
|
19446
|
-
const plan = planAutoUpdate(
|
|
19574
|
+
const plan = planAutoUpdate(base3, caps, effectiveOwn, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
19447
19575
|
if (!plan.update) {
|
|
19448
|
-
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(
|
|
19449
|
-
reportedStandingSkip.add(
|
|
19576
|
+
if (/disabled|no CLI release/.test(plan.reason) && !reportedStandingSkip.has(base3)) {
|
|
19577
|
+
reportedStandingSkip.add(base3);
|
|
19450
19578
|
try {
|
|
19451
19579
|
const { reportClientEvent: reportClientEvent2 } = await Promise.resolve().then(() => (init_client_events(), client_events_exports));
|
|
19452
19580
|
reportClientEvent2("auto_update_skipped", { message: `${plan.reason} (server offers ${caps.cli?.version ?? "?"}, this device runs ${effectiveOwn})` });
|
|
@@ -19502,7 +19630,7 @@ var init_auto_update = __esm({
|
|
|
19502
19630
|
"use strict";
|
|
19503
19631
|
init_http();
|
|
19504
19632
|
init_index_lock();
|
|
19505
|
-
tarballUrl = (
|
|
19633
|
+
tarballUrl = (base3, version) => `${base3.replace(/\/+$/, "")}/install/${version ? `chat-recall-${version}.tgz` : "chat-recall.tgz"}`;
|
|
19506
19634
|
GIVE_UP_AFTER = 3;
|
|
19507
19635
|
reportedStandingSkip = /* @__PURE__ */ new Set();
|
|
19508
19636
|
STOPPING_REASON = "not installed: this process is shutting down";
|
|
@@ -19513,7 +19641,7 @@ var init_auto_update = __esm({
|
|
|
19513
19641
|
|
|
19514
19642
|
// src/sync-client.ts
|
|
19515
19643
|
import { join as join42, dirname as dirname19, basename as basename20 } from "node:path";
|
|
19516
|
-
import { readFileSync as readFileSync35, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as
|
|
19644
|
+
import { readFileSync as readFileSync35, writeFileSync as writeFileSync9, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync4, rmSync as rmSync6, chmodSync as chmodSync3, unlinkSync as unlinkSync2, readdirSync as readdirSync31, statSync as statSync38 } from "node:fs";
|
|
19517
19645
|
import { tmpdir as tmpdir3, hostname as hostname2 } from "node:os";
|
|
19518
19646
|
import { createHash as createHash8 } from "node:crypto";
|
|
19519
19647
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -19558,15 +19686,15 @@ function loadAllCredentials() {
|
|
|
19558
19686
|
return [];
|
|
19559
19687
|
}
|
|
19560
19688
|
async function fetchTenantSecurityConfig(cred) {
|
|
19561
|
-
const
|
|
19562
|
-
const cached = _securityConfigCache.get(
|
|
19689
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
19690
|
+
const cached = _securityConfigCache.get(base3);
|
|
19563
19691
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
19564
19692
|
const headers = { "content-type": "application/json" };
|
|
19565
19693
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
19566
19694
|
try {
|
|
19567
19695
|
const [rulesRes, settingsRes] = await Promise.all([
|
|
19568
|
-
fetchWithTimeout(`${
|
|
19569
|
-
fetchWithTimeout(`${
|
|
19696
|
+
fetchWithTimeout(`${base3}/api/secrets/rules`, { headers }),
|
|
19697
|
+
fetchWithTimeout(`${base3}/api/teams/security-config`, { headers }).catch(() => null)
|
|
19570
19698
|
]);
|
|
19571
19699
|
let tenantRules = [];
|
|
19572
19700
|
let rulePackVersion = null;
|
|
@@ -19591,18 +19719,18 @@ async function fetchTenantSecurityConfig(cred) {
|
|
|
19591
19719
|
const body = await settingsRes.json().catch(() => ({}));
|
|
19592
19720
|
if (typeof body.verifySecrets === "boolean") verifySecrets = body.verifySecrets;
|
|
19593
19721
|
if (typeof body.telemetry === "boolean") {
|
|
19594
|
-
setTelemetryEligible(
|
|
19722
|
+
setTelemetryEligible(base3, body.telemetry);
|
|
19595
19723
|
try {
|
|
19596
19724
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
19597
19725
|
updateCollectorHealth({
|
|
19598
|
-
telemetryEligible: { ...prior, [
|
|
19726
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body.telemetry, at: Date.now() } }
|
|
19599
19727
|
});
|
|
19600
19728
|
} catch {
|
|
19601
19729
|
}
|
|
19602
19730
|
}
|
|
19603
19731
|
}
|
|
19604
19732
|
const config = { tenantRules, verifySecrets, rulePackVersion };
|
|
19605
|
-
_securityConfigCache.set(
|
|
19733
|
+
_securityConfigCache.set(base3, { fetchedAt: Date.now(), config });
|
|
19606
19734
|
return config;
|
|
19607
19735
|
} catch {
|
|
19608
19736
|
return { tenantRules: [], verifySecrets: true, rulePackVersion: null };
|
|
@@ -19618,18 +19746,18 @@ function readPersistedSyncConfigs() {
|
|
|
19618
19746
|
return {};
|
|
19619
19747
|
}
|
|
19620
19748
|
}
|
|
19621
|
-
function persistSyncConfig(
|
|
19749
|
+
function persistSyncConfig(base3, config) {
|
|
19622
19750
|
try {
|
|
19623
19751
|
const all = readPersistedSyncConfigs();
|
|
19624
|
-
all[
|
|
19752
|
+
all[base3] = { fetchedAt: Date.now(), config };
|
|
19625
19753
|
mkdirSync10(dirname19(syncConfigCachePath()), { recursive: true });
|
|
19626
19754
|
writeFileSync9(syncConfigCachePath(), JSON.stringify(all, null, 2));
|
|
19627
19755
|
} catch {
|
|
19628
19756
|
}
|
|
19629
19757
|
}
|
|
19630
19758
|
async function fetchTenantSyncConfig(cred) {
|
|
19631
|
-
const
|
|
19632
|
-
const cached = _syncConfigCache.get(
|
|
19759
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
19760
|
+
const cached = _syncConfigCache.get(base3);
|
|
19633
19761
|
if (cached && Date.now() - cached.fetchedAt < SECURITY_CONFIG_TTL_MS) return cached.config;
|
|
19634
19762
|
const headers = { "content-type": "application/json" };
|
|
19635
19763
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
@@ -19637,7 +19765,7 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
19637
19765
|
try {
|
|
19638
19766
|
const sources2 = discoverSessionSources();
|
|
19639
19767
|
if (sources2.length > 0) {
|
|
19640
|
-
await fetchWithTimeout(`${
|
|
19768
|
+
await fetchWithTimeout(`${base3}/api/sync-config/sources`, {
|
|
19641
19769
|
method: "POST",
|
|
19642
19770
|
headers,
|
|
19643
19771
|
body: JSON.stringify({ device: deviceLabel(), sources: sources2 })
|
|
@@ -19645,12 +19773,12 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
19645
19773
|
}
|
|
19646
19774
|
} catch {
|
|
19647
19775
|
}
|
|
19648
|
-
const res = await fetchWithTimeout(`${
|
|
19776
|
+
const res = await fetchWithTimeout(`${base3}/api/sync-config`, { headers });
|
|
19649
19777
|
if (res.status === 404) {
|
|
19650
|
-
_syncConfigCache.set(
|
|
19778
|
+
_syncConfigCache.set(base3, { fetchedAt: Date.now(), config: EMPTY_SYNC_CONFIG });
|
|
19651
19779
|
return EMPTY_SYNC_CONFIG;
|
|
19652
19780
|
}
|
|
19653
|
-
if (!res.ok) return lastKnownSyncConfig(
|
|
19781
|
+
if (!res.ok) return lastKnownSyncConfig(base3, `HTTP ${res.status}`);
|
|
19654
19782
|
const body = await res.json().catch(() => ({}));
|
|
19655
19783
|
const config = {
|
|
19656
19784
|
excludeTools: Array.isArray(body.excludeTools) ? body.excludeTools.filter((t) => typeof t === "string") : [],
|
|
@@ -19687,22 +19815,22 @@ async function fetchTenantSyncConfig(cred) {
|
|
|
19687
19815
|
if (decided > 0) console.error(`[sync] applied ${decided} folder decision(s) from the dashboard`);
|
|
19688
19816
|
} catch {
|
|
19689
19817
|
}
|
|
19690
|
-
_syncConfigCache.set(
|
|
19691
|
-
persistSyncConfig(
|
|
19818
|
+
_syncConfigCache.set(base3, { fetchedAt: Date.now(), config });
|
|
19819
|
+
persistSyncConfig(base3, config);
|
|
19692
19820
|
return config;
|
|
19693
19821
|
} catch (err) {
|
|
19694
19822
|
if (isSyncRulesRefusal(err)) throw err;
|
|
19695
|
-
return lastKnownSyncConfig(
|
|
19823
|
+
return lastKnownSyncConfig(base3, err instanceof Error ? err.message : "request failed");
|
|
19696
19824
|
}
|
|
19697
19825
|
}
|
|
19698
|
-
function lastKnownSyncConfig(
|
|
19699
|
-
const remembered = _syncConfigCache.get(
|
|
19826
|
+
function lastKnownSyncConfig(base3, reason) {
|
|
19827
|
+
const remembered = _syncConfigCache.get(base3) ?? readPersistedSyncConfigs()[base3];
|
|
19700
19828
|
if (remembered) {
|
|
19701
19829
|
console.error(`[sync] could not read server-side sync rules (${reason}) \u2014 applying the last known set from ${new Date(remembered.fetchedAt).toISOString()}`);
|
|
19702
19830
|
return remembered.config;
|
|
19703
19831
|
}
|
|
19704
19832
|
const refusal = new Error(
|
|
19705
|
-
`Cannot read the server-side sync rules from ${
|
|
19833
|
+
`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.`
|
|
19706
19834
|
);
|
|
19707
19835
|
refusal[SYNC_RULES_REFUSAL] = true;
|
|
19708
19836
|
throw refusal;
|
|
@@ -19810,25 +19938,25 @@ async function syncSessions(opts = {}) {
|
|
|
19810
19938
|
${errors.join("\n ")}`);
|
|
19811
19939
|
return { ...agg, perTarget };
|
|
19812
19940
|
}
|
|
19813
|
-
async function postFieldBatch(
|
|
19941
|
+
async function postFieldBatch(base3, token, rows) {
|
|
19814
19942
|
const headers = { "content-type": "application/json" };
|
|
19815
19943
|
if (token) headers.authorization = `Bearer ${token}`;
|
|
19816
19944
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
19817
19945
|
for (let attempt = 0; ; attempt++) {
|
|
19818
|
-
const res = await fetchWithTimeout(`${
|
|
19946
|
+
const res = await fetchWithTimeout(`${base3}/api/sync`, { method: "POST", headers, body: JSON.stringify({ fields: rows }) }, 6e4);
|
|
19819
19947
|
if (res.ok) return;
|
|
19820
19948
|
const retryable = res.status === 429 || res.status >= 500;
|
|
19821
|
-
if (!retryable || attempt >= 5) throw new Error(`${
|
|
19949
|
+
if (!retryable || attempt >= 5) throw new Error(`${base3}: fields batch HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
19822
19950
|
const ra = Number(res.headers.get("retry-after")) || 0;
|
|
19823
19951
|
await sleep(ra > 0 ? ra * 1e3 : [500, 1500, 4e3, 8e3, 15e3][Math.min(attempt, 4)]);
|
|
19824
19952
|
}
|
|
19825
19953
|
}
|
|
19826
19954
|
async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
19827
|
-
const
|
|
19828
|
-
const ledger = getSyncedRows(
|
|
19955
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
19956
|
+
const ledger = getSyncedRows(base3);
|
|
19829
19957
|
let pushed = 0, absent = 0, scanned = 0;
|
|
19830
19958
|
for (const field of SYNC_FIELDS) {
|
|
19831
|
-
const needFull = !!opts.force || fieldNeedsFullPass(
|
|
19959
|
+
const needFull = !!opts.force || fieldNeedsFullPass(base3, field);
|
|
19832
19960
|
const candidates2 = needFull ? fullRefs() : opts.convRefs ?? fullRefs();
|
|
19833
19961
|
const send = [];
|
|
19834
19962
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
@@ -19844,15 +19972,15 @@ async function reconcileFieldsForTarget(cred, fullRefs, opts = {}) {
|
|
|
19844
19972
|
}
|
|
19845
19973
|
for (let i = 0; i < send.length; i += 200) {
|
|
19846
19974
|
const chunk = send.slice(i, i + 200);
|
|
19847
|
-
await postFieldBatch(
|
|
19848
|
-
markFieldCoverage(
|
|
19975
|
+
await postFieldBatch(base3, cred.token, chunk);
|
|
19976
|
+
markFieldCoverage(base3, field, chunk.map((r) => ({ id: r.session_id, present: true, mtime: mtimeById.get(r.session_id) ?? 0 })));
|
|
19849
19977
|
pushed += chunk.length;
|
|
19850
19978
|
}
|
|
19851
19979
|
if (absentIds.length) {
|
|
19852
|
-
markFieldCoverage(
|
|
19980
|
+
markFieldCoverage(base3, field, absentIds.map((id) => ({ id, present: false, mtime: mtimeById.get(id) ?? 0 })));
|
|
19853
19981
|
absent += absentIds.length;
|
|
19854
19982
|
}
|
|
19855
|
-
if (needFull) markFieldFullPassDone(
|
|
19983
|
+
if (needFull) markFieldFullPassDone(base3, field);
|
|
19856
19984
|
}
|
|
19857
19985
|
return { pushed, absent, scanned };
|
|
19858
19986
|
}
|
|
@@ -19868,7 +19996,7 @@ function reapStaleScanDirs(dir = tmpdir3(), maxAgeMs = 6 * 36e5, now = Date.now(
|
|
|
19868
19996
|
if (!name.startsWith("cr-batchscan-")) continue;
|
|
19869
19997
|
const p = join42(dir, name);
|
|
19870
19998
|
try {
|
|
19871
|
-
if (now -
|
|
19999
|
+
if (now - statSync38(p).mtimeMs < maxAgeMs) continue;
|
|
19872
20000
|
rmSync6(p, { recursive: true, force: true });
|
|
19873
20001
|
reaped++;
|
|
19874
20002
|
} catch {
|
|
@@ -19942,25 +20070,25 @@ function serverIngestConcurrency(serverUrl) {
|
|
|
19942
20070
|
return advertisedIngestConc.get(serverUrl.replace(/\/$/, "")) ?? null;
|
|
19943
20071
|
}
|
|
19944
20072
|
async function verifyServerApi(serverUrl, minApi) {
|
|
19945
|
-
const
|
|
19946
|
-
const seen = capsOk.get(
|
|
20073
|
+
const base3 = serverUrl.replace(/\/$/, "");
|
|
20074
|
+
const seen = capsOk.get(base3);
|
|
19947
20075
|
if (seen !== void 0 && Date.now() - seen < CAPS_TTL_MS) return true;
|
|
19948
20076
|
const { probeServer: probeServer2, probeAdvice: probeAdvice2 } = await Promise.resolve().then(() => (init_server_probe(), server_probe_exports));
|
|
19949
|
-
const probe = await probeServer2(
|
|
20077
|
+
const probe = await probeServer2(base3, {
|
|
19950
20078
|
fetchImpl: ((url, init) => fetchWithTimeout(String(url), init ?? {}))
|
|
19951
20079
|
});
|
|
19952
|
-
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe,
|
|
20080
|
+
if (probe.kind !== "ok") throw new Error(probeAdvice2(probe, base3));
|
|
19953
20081
|
const caps = probe.raw;
|
|
19954
20082
|
if ((caps.apiVersion ?? 0) < minApi) {
|
|
19955
20083
|
throw new Error(`server too old: apiVersion ${caps.apiVersion ?? "none"} < required ${minApi} \u2014 update the server image before syncing`);
|
|
19956
20084
|
}
|
|
19957
20085
|
const adv = caps.limits?.ingestConcurrencyPerTenant;
|
|
19958
20086
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
19959
|
-
advertisedIngestConc.set(
|
|
20087
|
+
advertisedIngestConc.set(base3, Math.floor(adv));
|
|
19960
20088
|
}
|
|
19961
|
-
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(
|
|
19962
|
-
else advertisedGzipBody.delete(
|
|
19963
|
-
capsOk.set(
|
|
20089
|
+
if (caps.limits?.acceptsGzipBody === true) advertisedGzipBody.add(base3);
|
|
20090
|
+
else advertisedGzipBody.delete(base3);
|
|
20091
|
+
capsOk.set(base3, Date.now());
|
|
19964
20092
|
return true;
|
|
19965
20093
|
}
|
|
19966
20094
|
async function syncToTarget(cred, opts = {}) {
|
|
@@ -20025,7 +20153,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20025
20153
|
const ac = new AbortController();
|
|
20026
20154
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
20027
20155
|
try {
|
|
20028
|
-
const res = await fetch(`${
|
|
20156
|
+
const res = await fetch(`${base3}/api/sync`, {
|
|
20029
20157
|
method: "POST",
|
|
20030
20158
|
// No token ⇒ no auth header: a no-auth local server (AUTH_PROVIDER=none)
|
|
20031
20159
|
// accepts it as the single 'default' tenant.
|
|
@@ -20041,26 +20169,26 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20041
20169
|
acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
|
|
20042
20170
|
const body2 = await res.json().catch(() => ({}));
|
|
20043
20171
|
if (typeof body2.telemetry === "boolean") {
|
|
20044
|
-
setTelemetryEligible(
|
|
20172
|
+
setTelemetryEligible(base3, body2.telemetry);
|
|
20045
20173
|
try {
|
|
20046
20174
|
const prior = readCollectorHealth()?.telemetryEligible ?? {};
|
|
20047
20175
|
updateCollectorHealth({
|
|
20048
|
-
telemetryEligible: { ...prior, [
|
|
20176
|
+
telemetryEligible: { ...prior, [base3]: { allowed: body2.telemetry, at: Date.now() } }
|
|
20049
20177
|
});
|
|
20050
20178
|
} catch {
|
|
20051
20179
|
}
|
|
20052
20180
|
}
|
|
20053
20181
|
const adv = body2.limits?.ingestConcurrencyPerTenant;
|
|
20054
20182
|
if (typeof adv === "number" && Number.isFinite(adv) && adv >= 1) {
|
|
20055
|
-
setServerIngestConcurrency(
|
|
20183
|
+
setServerIngestConcurrency(base3, Math.floor(adv));
|
|
20056
20184
|
}
|
|
20057
20185
|
if (body2.cli && body2.cli.version) {
|
|
20058
20186
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
20059
20187
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
20060
|
-
const plan = planAutoUpdate2(
|
|
20188
|
+
const plan = planAutoUpdate2(base3, { cli: body2.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20061
20189
|
sweepStaleStaging2();
|
|
20062
20190
|
if (plan.update) {
|
|
20063
|
-
void runAutoUpdate2(
|
|
20191
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
20064
20192
|
});
|
|
20065
20193
|
}
|
|
20066
20194
|
}
|
|
@@ -20069,7 +20197,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20069
20197
|
const retryable = res.status === 429 || res.status >= 500;
|
|
20070
20198
|
const text = await res.text().catch(() => "");
|
|
20071
20199
|
if (res.status === 401 || res.status === 403) {
|
|
20072
|
-
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${
|
|
20200
|
+
throw classedError("auth", `server rejected this machine's device token (HTTP ${res.status} \u2014 revoked?). Reconnect with: chat-recall login ${base3}`);
|
|
20073
20201
|
}
|
|
20074
20202
|
if (res.status === 402) {
|
|
20075
20203
|
let detail = text;
|
|
@@ -20090,7 +20218,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20090
20218
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
20091
20219
|
const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
|
|
20092
20220
|
const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
|
|
20093
|
-
console.error(`[sync] HTTP ${res.status} from ${
|
|
20221
|
+
console.error(`[sync] HTTP ${res.status} from ${base3}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
|
|
20094
20222
|
await sleep(waitMs);
|
|
20095
20223
|
continue;
|
|
20096
20224
|
} catch (err) {
|
|
@@ -20158,11 +20286,11 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20158
20286
|
}
|
|
20159
20287
|
};
|
|
20160
20288
|
};
|
|
20161
|
-
const
|
|
20162
|
-
const ledger = opts.useLedger ? getSyncedRows(
|
|
20289
|
+
const base3 = cred.serverUrl.replace(/\/$/, "");
|
|
20290
|
+
const ledger = opts.useLedger ? getSyncedRows(base3) : null;
|
|
20163
20291
|
const convBatch = makeBatcher("conversations", 25, false, (rows) => {
|
|
20164
20292
|
try {
|
|
20165
|
-
markSynced(
|
|
20293
|
+
markSynced(base3, rows.map((r) => {
|
|
20166
20294
|
const off = typeof r.from_offset === "number" ? r.from_offset : 0;
|
|
20167
20295
|
const hash = shippedHash.get(r.session_id);
|
|
20168
20296
|
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 };
|
|
@@ -20177,7 +20305,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20177
20305
|
const ac = new AbortController();
|
|
20178
20306
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
20179
20307
|
try {
|
|
20180
|
-
const res = await fetch(`${
|
|
20308
|
+
const res = await fetch(`${base3}/api/sync`, {
|
|
20181
20309
|
method: "POST",
|
|
20182
20310
|
headers,
|
|
20183
20311
|
body: JSON.stringify({ conversations: convs }),
|
|
@@ -20188,10 +20316,10 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20188
20316
|
if (body.cli && body.cli.version) {
|
|
20189
20317
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
20190
20318
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
20191
|
-
const plan = planAutoUpdate2(
|
|
20319
|
+
const plan = planAutoUpdate2(base3, { cli: body.cli }, ownVersion, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
20192
20320
|
sweepStaleStaging2();
|
|
20193
20321
|
if (plan.update) {
|
|
20194
|
-
void runAutoUpdate2(
|
|
20322
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion).catch(() => {
|
|
20195
20323
|
});
|
|
20196
20324
|
}
|
|
20197
20325
|
}
|
|
@@ -20199,7 +20327,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20199
20327
|
const acked = convs.filter((c) => !fullNeeded.has(c.session_id));
|
|
20200
20328
|
if (acked.length > 0) {
|
|
20201
20329
|
try {
|
|
20202
|
-
markSynced(
|
|
20330
|
+
markSynced(base3, acked.map((c) => ({
|
|
20203
20331
|
id: c.session_id,
|
|
20204
20332
|
mtime: c.mtime,
|
|
20205
20333
|
offset: c.from_offset,
|
|
@@ -20217,13 +20345,14 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20217
20345
|
clearTimeout(timer);
|
|
20218
20346
|
}
|
|
20219
20347
|
};
|
|
20220
|
-
const postChunkedHead = async (
|
|
20348
|
+
const postChunkedHead = async (head, fileSize) => {
|
|
20349
|
+
const conv = { ...head, chunk_head: true };
|
|
20221
20350
|
const headers = { "content-type": "application/json" };
|
|
20222
20351
|
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
20223
20352
|
const ac = new AbortController();
|
|
20224
20353
|
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
20225
20354
|
try {
|
|
20226
|
-
const res = await fetch(`${
|
|
20355
|
+
const res = await fetch(`${base3}/api/sync`, {
|
|
20227
20356
|
method: "POST",
|
|
20228
20357
|
headers,
|
|
20229
20358
|
body: JSON.stringify({ conversations: [conv] }),
|
|
@@ -20233,14 +20362,15 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20233
20362
|
const body = await res.json().catch(() => ({}));
|
|
20234
20363
|
const id = conv.session_id;
|
|
20235
20364
|
const guarded = (body.shrink_guarded ?? []).find((g) => g.session_id === id);
|
|
20365
|
+
const staged = (body.rebuild_staged ?? []).includes(id);
|
|
20236
20366
|
const mtime = conv.mtime;
|
|
20237
20367
|
try {
|
|
20238
|
-
if (!guarded) {
|
|
20239
|
-
markSynced(
|
|
20368
|
+
if (staged || !guarded) {
|
|
20369
|
+
markSynced(base3, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
|
|
20240
20370
|
} else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
|
|
20241
|
-
markSynced(
|
|
20371
|
+
markSynced(base3, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
|
|
20242
20372
|
} else {
|
|
20243
|
-
markSynced(
|
|
20373
|
+
markSynced(base3, [{ id, mtime }]);
|
|
20244
20374
|
}
|
|
20245
20375
|
} catch {
|
|
20246
20376
|
}
|
|
@@ -20306,7 +20436,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20306
20436
|
const m = process.memoryUsage();
|
|
20307
20437
|
console.error(`[sync-trace] ${msg} \xB7 heap=${(m.heapUsed / 1048576).toFixed(0)}MB rss=${(m.rss / 1048576).toFixed(0)}MB`);
|
|
20308
20438
|
} : null;
|
|
20309
|
-
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${
|
|
20439
|
+
trace?.(`walk start: ${slice.length} ref(s) \u2192 ${base3}`);
|
|
20310
20440
|
if (upload.sessionMeta) {
|
|
20311
20441
|
try {
|
|
20312
20442
|
await reconcileFieldsForTarget(
|
|
@@ -20321,7 +20451,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20321
20451
|
{ convRefs: slice }
|
|
20322
20452
|
);
|
|
20323
20453
|
} catch (e) {
|
|
20324
|
-
console.error(`[sync] field reconcile (${
|
|
20454
|
+
console.error(`[sync] field reconcile (${base3}): ${e instanceof Error ? e.message : e}`);
|
|
20325
20455
|
}
|
|
20326
20456
|
}
|
|
20327
20457
|
trace?.("field reconcile done");
|
|
@@ -20363,7 +20493,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20363
20493
|
}
|
|
20364
20494
|
trace?.("conversation walk start");
|
|
20365
20495
|
const walkStartedAt = Date.now();
|
|
20366
|
-
const firstWalk = (ledger ?? getSyncedRows(
|
|
20496
|
+
const firstWalk = (ledger ?? getSyncedRows(base3)).size === 0;
|
|
20367
20497
|
reportWalkProgress({ done: 0, total: slice.length, startedAt: walkStartedAt, complete: false, first: firstWalk });
|
|
20368
20498
|
walkProgressForUpload = { done: 0, total: slice.length, complete: false };
|
|
20369
20499
|
let traceN = 0;
|
|
@@ -20403,7 +20533,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20403
20533
|
continue;
|
|
20404
20534
|
} else {
|
|
20405
20535
|
try {
|
|
20406
|
-
markSynced(
|
|
20536
|
+
markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
20407
20537
|
} catch {
|
|
20408
20538
|
}
|
|
20409
20539
|
skipped++;
|
|
@@ -20426,7 +20556,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20426
20556
|
const off = getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId) ?? 0;
|
|
20427
20557
|
const priorCursor = ackRow?.s ?? 0;
|
|
20428
20558
|
const safeToAck = off > 0 && off <= priorCursor;
|
|
20429
|
-
markSynced(
|
|
20559
|
+
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 }]);
|
|
20430
20560
|
} catch {
|
|
20431
20561
|
}
|
|
20432
20562
|
}
|
|
@@ -20436,7 +20566,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20436
20566
|
if (!built) {
|
|
20437
20567
|
if (ledger) {
|
|
20438
20568
|
try {
|
|
20439
|
-
markSynced(
|
|
20569
|
+
markSynced(base3, [{ id: ref.prefixedId, mtime: ref.mtime }]);
|
|
20440
20570
|
} catch {
|
|
20441
20571
|
}
|
|
20442
20572
|
}
|
|
@@ -20493,7 +20623,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20493
20623
|
walked++;
|
|
20494
20624
|
if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
|
|
20495
20625
|
}
|
|
20496
|
-
const itemVersions = loadItemVersions(
|
|
20626
|
+
const itemVersions = loadItemVersions(base3);
|
|
20497
20627
|
const seenTools = /* @__PURE__ */ new Set();
|
|
20498
20628
|
const seenItemKeys = /* @__PURE__ */ new Map();
|
|
20499
20629
|
const registry = buildSourceRegistry();
|
|
@@ -20587,7 +20717,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20587
20717
|
await appendFlush();
|
|
20588
20718
|
for (const id of appendResults.fullResyncNeeded) {
|
|
20589
20719
|
try {
|
|
20590
|
-
markFullResync(
|
|
20720
|
+
markFullResync(base3, id);
|
|
20591
20721
|
} catch {
|
|
20592
20722
|
}
|
|
20593
20723
|
}
|
|
@@ -20600,7 +20730,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20600
20730
|
await findingsBatch.drain();
|
|
20601
20731
|
await drainInflight();
|
|
20602
20732
|
{
|
|
20603
|
-
const sentHashes = loadInventoryHashes(
|
|
20733
|
+
const sentHashes = loadInventoryHashes(base3);
|
|
20604
20734
|
const entries = [];
|
|
20605
20735
|
const hashes = {};
|
|
20606
20736
|
for (const [sourceType, ids] of inventory) {
|
|
@@ -20614,7 +20744,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20614
20744
|
if (entries.length > 0) {
|
|
20615
20745
|
try {
|
|
20616
20746
|
await post({ inventory: entries });
|
|
20617
|
-
saveInventoryHashes(
|
|
20747
|
+
saveInventoryHashes(base3, hashes);
|
|
20618
20748
|
} catch (err) {
|
|
20619
20749
|
console.error(`[sync] toolkit inventory not sent (it is retried next sync): ${err instanceof Error ? err.message : err}`);
|
|
20620
20750
|
}
|
|
@@ -20625,7 +20755,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20625
20755
|
const rec = {};
|
|
20626
20756
|
for (const t of seenTools) rec[t] = extractorVersionForTool(t);
|
|
20627
20757
|
for (const [k, v] of seenItemKeys) rec[k] = v;
|
|
20628
|
-
saveItemVersions(
|
|
20758
|
+
saveItemVersions(base3, rec);
|
|
20629
20759
|
} catch {
|
|
20630
20760
|
}
|
|
20631
20761
|
}
|
|
@@ -20638,9 +20768,9 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20638
20768
|
}
|
|
20639
20769
|
if (tombstones.length > 0) {
|
|
20640
20770
|
await post({ tombstones });
|
|
20641
|
-
const data = getLedgerData(
|
|
20771
|
+
const data = getLedgerData(base3);
|
|
20642
20772
|
for (const t of tombstones) delete data[t.session_id];
|
|
20643
|
-
persistLedgerData(
|
|
20773
|
+
persistLedgerData(base3, data);
|
|
20644
20774
|
}
|
|
20645
20775
|
}
|
|
20646
20776
|
if (opts.prune) await post({ prune_empty_sessions: true });
|
|
@@ -20968,8 +21098,13 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
|
|
|
20968
21098
|
const backend = getBackendForId(ref.prefixedId);
|
|
20969
21099
|
if (!backend?.readFromOffset) return null;
|
|
20970
21100
|
const mapPath = opts.mapPath ?? ((p) => p);
|
|
20971
|
-
const { text: tailText, newOffset, skippedBytes } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
|
|
21101
|
+
const { text: tailText, newOffset, skippedBytes, baseLine } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
|
|
20972
21102
|
if (newOffset <= fromOffset) return null;
|
|
21103
|
+
const fileSize = backend.fileSize?.(ref.prefixedId) ?? 0;
|
|
21104
|
+
const position = {
|
|
21105
|
+
...typeof baseLine === "number" ? { base_line: baseLine } : {},
|
|
21106
|
+
final: fileSize > 0 && newOffset >= fileSize
|
|
21107
|
+
};
|
|
20973
21108
|
const messages = skippedBytes ? [] : parseTailMessages(ref.toolId, tailText);
|
|
20974
21109
|
const textMessages = messages.filter((m) => m.role !== "summary" && m.content?.trim());
|
|
20975
21110
|
const hasContent = textMessages.length > 0 || messages.some((m) => m.toolCalls?.length);
|
|
@@ -20982,6 +21117,7 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
|
|
|
20982
21117
|
append: true,
|
|
20983
21118
|
base_offset: fromOffset,
|
|
20984
21119
|
from_offset: newOffset,
|
|
21120
|
+
...position,
|
|
20985
21121
|
redacted_text: "",
|
|
20986
21122
|
envelope: { v: TRANSCRIPT_VERSION, messages: [], subagents: [] },
|
|
20987
21123
|
mtime: Math.floor(ref.mtime) || 0
|
|
@@ -21028,6 +21164,7 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
|
|
|
21028
21164
|
// equals its stored synced-through offset.
|
|
21029
21165
|
from_offset: newOffset,
|
|
21030
21166
|
// where it ends → new synced-through offset.
|
|
21167
|
+
...position,
|
|
21031
21168
|
redacted_text: redactedText,
|
|
21032
21169
|
envelope,
|
|
21033
21170
|
mtime: Math.floor(ref.mtime) || 0
|
|
@@ -21111,7 +21248,7 @@ var init_sync_client = __esm({
|
|
|
21111
21248
|
ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21112
21249
|
} catch {
|
|
21113
21250
|
try {
|
|
21114
|
-
if (true) ownVersion = "0.7.
|
|
21251
|
+
if (true) ownVersion = "0.7.16";
|
|
21115
21252
|
} catch {
|
|
21116
21253
|
}
|
|
21117
21254
|
}
|
|
@@ -21170,10 +21307,10 @@ function parseAgentText(content, format, fallbackName) {
|
|
|
21170
21307
|
return { name: fm.name || fallbackName, description: fm.description || "", tools: fm.tools, body: body.trim() };
|
|
21171
21308
|
}
|
|
21172
21309
|
function readCommand(filePath, format) {
|
|
21173
|
-
return parseCommandText(readFileSync36(filePath, "utf-8"), format,
|
|
21310
|
+
return parseCommandText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
|
|
21174
21311
|
}
|
|
21175
21312
|
function readAgent(filePath, format) {
|
|
21176
|
-
return parseAgentText(readFileSync36(filePath, "utf-8"), format,
|
|
21313
|
+
return parseAgentText(readFileSync36(filePath, "utf-8"), format, base2(filePath));
|
|
21177
21314
|
}
|
|
21178
21315
|
function readInstructions(filePath, name) {
|
|
21179
21316
|
const content = readFileSync36(filePath, "utf-8");
|
|
@@ -21273,7 +21410,7 @@ function emit(type, art, toTool, projectPath) {
|
|
|
21273
21410
|
content: stringifyFrontmatter({ name: art.name, description: art.description, ...art.tools ? { tools: art.tools } : {} }, art.body)
|
|
21274
21411
|
};
|
|
21275
21412
|
}
|
|
21276
|
-
function
|
|
21413
|
+
function base2(filePath) {
|
|
21277
21414
|
return basename21(filePath).replace(/\.(md|toml)$/, "");
|
|
21278
21415
|
}
|
|
21279
21416
|
var init_artifact_codec = __esm({
|
|
@@ -21711,11 +21848,11 @@ var init_toolkit_sync = __esm({
|
|
|
21711
21848
|
});
|
|
21712
21849
|
|
|
21713
21850
|
// ../engine/dist/core/which.js
|
|
21714
|
-
import { existsSync as existsSync44, statSync as
|
|
21851
|
+
import { existsSync as existsSync44, statSync as statSync40, accessSync, constants } from "node:fs";
|
|
21715
21852
|
import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
|
|
21716
21853
|
function executable(p) {
|
|
21717
21854
|
try {
|
|
21718
|
-
if (!
|
|
21855
|
+
if (!statSync40(p).isFile())
|
|
21719
21856
|
return false;
|
|
21720
21857
|
} catch {
|
|
21721
21858
|
return false;
|
|
@@ -21778,11 +21915,11 @@ __export(toolkit_pull_exports, {
|
|
|
21778
21915
|
platformRefusal: () => platformRefusal,
|
|
21779
21916
|
portableCommand: () => portableCommand
|
|
21780
21917
|
});
|
|
21781
|
-
import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as
|
|
21918
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync41, writeFileSync as writeFileSync12 } from "node:fs";
|
|
21782
21919
|
import { dirname as dirname22, join as join47, basename as basename23, isAbsolute as isAbsolute3 } from "node:path";
|
|
21783
21920
|
function isExecutableFile(p) {
|
|
21784
21921
|
try {
|
|
21785
|
-
return
|
|
21922
|
+
return statSync41(p).isFile();
|
|
21786
21923
|
} catch {
|
|
21787
21924
|
return false;
|
|
21788
21925
|
}
|
|
@@ -21796,9 +21933,9 @@ function portableCommand(cmd) {
|
|
|
21796
21933
|
}
|
|
21797
21934
|
if (isExecutableFile(cmd))
|
|
21798
21935
|
return { command: cmd, rewritten: false };
|
|
21799
|
-
const
|
|
21800
|
-
if (onPath(
|
|
21801
|
-
return { command:
|
|
21936
|
+
const base3 = basename23(cmd);
|
|
21937
|
+
if (onPath(base3))
|
|
21938
|
+
return { command: base3, rewritten: true };
|
|
21802
21939
|
return { missing: cmd };
|
|
21803
21940
|
}
|
|
21804
21941
|
function entryFromSpec(spec) {
|
|
@@ -22315,7 +22452,7 @@ __export(shadow_prune_exports, {
|
|
|
22315
22452
|
DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
|
|
22316
22453
|
pruneShadow: () => pruneShadow
|
|
22317
22454
|
});
|
|
22318
|
-
import { readdirSync as readdirSync32, statSync as
|
|
22455
|
+
import { readdirSync as readdirSync32, statSync as statSync44, unlinkSync as unlinkSync3 } from "fs";
|
|
22319
22456
|
import { join as join50 } from "path";
|
|
22320
22457
|
function listShadows(isFullyAcked) {
|
|
22321
22458
|
const out = [];
|
|
@@ -22340,7 +22477,7 @@ function listShadows(isFullyAcked) {
|
|
|
22340
22477
|
const path = join50(dir, name);
|
|
22341
22478
|
let st;
|
|
22342
22479
|
try {
|
|
22343
|
-
st =
|
|
22480
|
+
st = statSync44(path);
|
|
22344
22481
|
} catch {
|
|
22345
22482
|
continue;
|
|
22346
22483
|
}
|
|
@@ -22455,7 +22592,7 @@ var init_code_intel = __esm({
|
|
|
22455
22592
|
});
|
|
22456
22593
|
|
|
22457
22594
|
// ../engine/dist/core/companions.js
|
|
22458
|
-
import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as
|
|
22595
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync45, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync42, writeFileSync as writeFileSync15 } from "node:fs";
|
|
22459
22596
|
import { homedir as homedir19 } from "node:os";
|
|
22460
22597
|
import { join as join51 } from "node:path";
|
|
22461
22598
|
import { execSync as execSync3 } from "node:child_process";
|
|
@@ -22506,7 +22643,7 @@ function checkCodeindexStatus() {
|
|
|
22506
22643
|
status.installed = true;
|
|
22507
22644
|
status.path = foundPath;
|
|
22508
22645
|
try {
|
|
22509
|
-
status.size =
|
|
22646
|
+
status.size = statSync45(foundPath).size;
|
|
22510
22647
|
} catch {
|
|
22511
22648
|
}
|
|
22512
22649
|
try {
|
|
@@ -22846,17 +22983,17 @@ async function collectCode(opts) {
|
|
|
22846
22983
|
return r;
|
|
22847
22984
|
};
|
|
22848
22985
|
log6(`indexing ${ws} + analyses \u2026`);
|
|
22849
|
-
const
|
|
22986
|
+
const base3 = await runMcp(bin, ws, [
|
|
22850
22987
|
call(1, "index_workspace", { path: ws }),
|
|
22851
22988
|
call(2, "status"),
|
|
22852
22989
|
call(3, "get_tree"),
|
|
22853
22990
|
...ANALYSES.map((a, i) => call(10 + i, "analyze", { analysis: a }))
|
|
22854
22991
|
]);
|
|
22855
|
-
const st = parseJson(
|
|
22856
|
-
const tree = parseJson(
|
|
22992
|
+
const st = parseJson(base3, 2, {});
|
|
22993
|
+
const tree = parseJson(base3, 3, []);
|
|
22857
22994
|
const A = {};
|
|
22858
22995
|
ANALYSES.forEach((a, i) => {
|
|
22859
|
-
A[a] = parseJson(
|
|
22996
|
+
A[a] = parseJson(base3, 10 + i, {});
|
|
22860
22997
|
});
|
|
22861
22998
|
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;
|
|
22862
22999
|
if (tree.length === 0) {
|
|
@@ -23949,7 +24086,7 @@ import { join as join48 } from "node:path";
|
|
|
23949
24086
|
|
|
23950
24087
|
// src/project-tasks.ts
|
|
23951
24088
|
init_http();
|
|
23952
|
-
import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as
|
|
24089
|
+
import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync39 } from "node:fs";
|
|
23953
24090
|
import { join as join45, dirname as dirname21 } from "node:path";
|
|
23954
24091
|
import { homedir as homedir18 } from "node:os";
|
|
23955
24092
|
|
|
@@ -24042,14 +24179,14 @@ var FILE_KINDS = [
|
|
|
24042
24179
|
{ kind: "secret", filename: "SECURITY_TASKS.md", trackedPath: "/api/secrets/tasks/tracked", statusPath: "/api/secrets/tasks/status" },
|
|
24043
24180
|
{ kind: "code", filename: "CODE_TASKS.md", trackedPath: "/api/code/tasks/tracked", statusPath: "/api/code/tasks/status" }
|
|
24044
24181
|
];
|
|
24045
|
-
async function pushProjectTaskStatuses(
|
|
24182
|
+
async function pushProjectTaskStatuses(base3, authHeaders, opts = {}) {
|
|
24046
24183
|
const out = { files: 0, pushedTasks: 0 };
|
|
24047
24184
|
const ledger = readLedger();
|
|
24048
24185
|
let ledgerDirty = false;
|
|
24049
24186
|
for (const fk of FILE_KINDS) {
|
|
24050
24187
|
let projects;
|
|
24051
24188
|
try {
|
|
24052
|
-
const res = await fetchWithTimeout(`${
|
|
24189
|
+
const res = await fetchWithTimeout(`${base3}${fk.trackedPath}`, { headers: authHeaders });
|
|
24053
24190
|
if (!res.ok) continue;
|
|
24054
24191
|
projects = (await res.json()).projects || [];
|
|
24055
24192
|
} catch {
|
|
@@ -24060,7 +24197,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
24060
24197
|
if (!existsSync43(file)) continue;
|
|
24061
24198
|
let mtime;
|
|
24062
24199
|
try {
|
|
24063
|
-
mtime =
|
|
24200
|
+
mtime = statSync39(file).mtimeMs;
|
|
24064
24201
|
} catch {
|
|
24065
24202
|
continue;
|
|
24066
24203
|
}
|
|
@@ -24077,7 +24214,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
24077
24214
|
continue;
|
|
24078
24215
|
}
|
|
24079
24216
|
try {
|
|
24080
|
-
const res = await fetchWithTimeout(`${
|
|
24217
|
+
const res = await fetchWithTimeout(`${base3}${fk.statusPath}`, {
|
|
24081
24218
|
method: "POST",
|
|
24082
24219
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
24083
24220
|
body: JSON.stringify({ project, items: changed.map((t) => ({ id: t.id, status: t.intent })) })
|
|
@@ -24167,16 +24304,16 @@ ${block}`);
|
|
|
24167
24304
|
return { status: "error", result: JSON.stringify({ error: e instanceof Error ? e.message : "failed" }) };
|
|
24168
24305
|
}
|
|
24169
24306
|
}
|
|
24170
|
-
async function runPull(
|
|
24307
|
+
async function runPull(base3, opts) {
|
|
24171
24308
|
const { executePull: executePull2 } = await Promise.resolve().then(() => (init_toolkit_pull(), toolkit_pull_exports));
|
|
24172
24309
|
const { hostname: hostname3 } = await import("node:os");
|
|
24173
|
-
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") ===
|
|
24310
|
+
const creds = loadAllCredentials().find((c) => c.serverUrl.replace(/\/+$/, "") === base3.replace(/\/+$/, ""));
|
|
24174
24311
|
const headers = creds?.token ? { authorization: `Bearer ${creds.token}` } : {};
|
|
24175
24312
|
const wanted = opts.types?.length ? opts.types : ["mcp", "skill", "command", "agent", "instructions"];
|
|
24176
24313
|
const rows = [];
|
|
24177
24314
|
for (const type of wanted) {
|
|
24178
24315
|
try {
|
|
24179
|
-
const res = await fetchWithTimeout(`${
|
|
24316
|
+
const res = await fetchWithTimeout(`${base3}/api/toolkit/browse/${type}?limit=1000`, { headers });
|
|
24180
24317
|
if (!res.ok) continue;
|
|
24181
24318
|
const body = await res.json();
|
|
24182
24319
|
for (const it of body.items || []) rows.push(it);
|
|
@@ -24248,27 +24385,27 @@ try {
|
|
|
24248
24385
|
ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
24249
24386
|
} catch {
|
|
24250
24387
|
try {
|
|
24251
|
-
if (true) ownVersion2 = "0.7.
|
|
24388
|
+
if (true) ownVersion2 = "0.7.16";
|
|
24252
24389
|
} catch {
|
|
24253
24390
|
}
|
|
24254
24391
|
}
|
|
24255
24392
|
async function drainSyncIntents(opts = {}) {
|
|
24256
24393
|
const out = { processed: 0, done: 0, errored: 0 };
|
|
24257
24394
|
for (const cred of loadAllCredentials()) {
|
|
24258
|
-
const
|
|
24395
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
24259
24396
|
const authHeaders = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
24260
24397
|
let pending;
|
|
24261
24398
|
try {
|
|
24262
|
-
const res = await fetchWithTimeout(`${
|
|
24399
|
+
const res = await fetchWithTimeout(`${base3}/api/sync-intents/pending`, { headers: authHeaders });
|
|
24263
24400
|
if (!res.ok) continue;
|
|
24264
24401
|
const data = await res.json();
|
|
24265
24402
|
pending = data.intents || [];
|
|
24266
24403
|
if (data.cli && data.cli.version) {
|
|
24267
24404
|
const { planAutoUpdate: planAutoUpdate2, runAutoUpdate: runAutoUpdate2, sweepStaleStaging: sweepStaleStaging2 } = await Promise.resolve().then(() => (init_auto_update(), auto_update_exports));
|
|
24268
|
-
const plan = planAutoUpdate2(
|
|
24405
|
+
const plan = planAutoUpdate2(base3, { cli: data.cli }, ownVersion2, process.env.CHAT_RECALL_AUTO_UPDATE);
|
|
24269
24406
|
sweepStaleStaging2();
|
|
24270
24407
|
if (plan.update) {
|
|
24271
|
-
void runAutoUpdate2(
|
|
24408
|
+
void runAutoUpdate2(base3, authHeaders, ownVersion2).catch(() => {
|
|
24272
24409
|
});
|
|
24273
24410
|
}
|
|
24274
24411
|
}
|
|
@@ -24276,7 +24413,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
24276
24413
|
continue;
|
|
24277
24414
|
}
|
|
24278
24415
|
for (const intent of pending) {
|
|
24279
|
-
const { status, result } = await runIntent(intent, { base:
|
|
24416
|
+
const { status, result } = await runIntent(intent, { base: base3 });
|
|
24280
24417
|
out.processed++;
|
|
24281
24418
|
if (status === "done") out.done++;
|
|
24282
24419
|
else out.errored++;
|
|
@@ -24285,7 +24422,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
24285
24422
|
console.error(`[sync-intent] ${label}: ${status}`);
|
|
24286
24423
|
}
|
|
24287
24424
|
try {
|
|
24288
|
-
await fetchWithTimeout(`${
|
|
24425
|
+
await fetchWithTimeout(`${base3}/api/sync-intents/${intent.id}/ack`, {
|
|
24289
24426
|
method: "POST",
|
|
24290
24427
|
headers: { "content-type": "application/json", ...authHeaders },
|
|
24291
24428
|
body: JSON.stringify({ status, result })
|
|
@@ -24294,7 +24431,7 @@ async function drainSyncIntents(opts = {}) {
|
|
|
24294
24431
|
}
|
|
24295
24432
|
}
|
|
24296
24433
|
try {
|
|
24297
|
-
await pushProjectTaskStatuses(
|
|
24434
|
+
await pushProjectTaskStatuses(base3, authHeaders, { verbose: opts.verbose });
|
|
24298
24435
|
} catch {
|
|
24299
24436
|
}
|
|
24300
24437
|
}
|
|
@@ -24313,7 +24450,7 @@ init_auto_update();
|
|
|
24313
24450
|
|
|
24314
24451
|
// src/code-index-cursor.ts
|
|
24315
24452
|
init_paths();
|
|
24316
|
-
import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as
|
|
24453
|
+
import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync42 } from "fs";
|
|
24317
24454
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
24318
24455
|
import { createHash as createHash10 } from "crypto";
|
|
24319
24456
|
import { join as join49, dirname as dirname24 } from "path";
|
|
@@ -24364,7 +24501,7 @@ function workspaceFingerprint(workspace, collectorVersion) {
|
|
|
24364
24501
|
const rel = entry.slice(3);
|
|
24365
24502
|
let stamp2 = "gone";
|
|
24366
24503
|
try {
|
|
24367
|
-
const s =
|
|
24504
|
+
const s = statSync42(join49(workspace, rel));
|
|
24368
24505
|
stamp2 = `${s.size}:${Math.floor(s.mtimeMs)}`;
|
|
24369
24506
|
} catch {
|
|
24370
24507
|
}
|
|
@@ -24573,11 +24710,11 @@ function checkSelfRestart(opts) {
|
|
|
24573
24710
|
}
|
|
24574
24711
|
|
|
24575
24712
|
// src/log-rotate.ts
|
|
24576
|
-
import { statSync as
|
|
24713
|
+
import { statSync as statSync43, copyFileSync as copyFileSync3, truncateSync } from "fs";
|
|
24577
24714
|
var LOG_MAX_BYTES = 32 * 1024 * 1024;
|
|
24578
24715
|
function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
|
|
24579
24716
|
try {
|
|
24580
|
-
const size =
|
|
24717
|
+
const size = statSync43(logPath).size;
|
|
24581
24718
|
if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
|
|
24582
24719
|
copyFileSync3(logPath, `${logPath}.1`);
|
|
24583
24720
|
truncateSync(logPath, 0);
|
|
@@ -24632,8 +24769,8 @@ async function runCollectorMigration(opts) {
|
|
|
24632
24769
|
// auto-indexer/indexer.ts
|
|
24633
24770
|
init_sync_ledger();
|
|
24634
24771
|
init_collector_health();
|
|
24635
|
-
import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as
|
|
24636
|
-
var CLI_VERSION3 = true ? "0.7.
|
|
24772
|
+
import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync46 } from "fs";
|
|
24773
|
+
var CLI_VERSION3 = true ? "0.7.16" : "0.0.0";
|
|
24637
24774
|
var DEBOUNCE_MS = 5e3;
|
|
24638
24775
|
var PLANS_DIR = claudeBackend.plansDir();
|
|
24639
24776
|
var TASKS_DIR = claudeBackend.tasksDir();
|
|
@@ -24738,7 +24875,7 @@ var CLAUDE_SESSION_ROOTS = claudeProjectDirs();
|
|
|
24738
24875
|
var sessionWatcher = watchWithFallback("sessions", CLAUDE_SESSION_ROOTS.map((root) => `${root}/**/*.jsonl`), {
|
|
24739
24876
|
ignored: (p, stats) => {
|
|
24740
24877
|
if (/agent-/.test(p) || /^\./.test(basename25(p))) return true;
|
|
24741
|
-
const st = stats ??
|
|
24878
|
+
const st = stats ?? statSync46(p, { throwIfNoEntry: false });
|
|
24742
24879
|
if (!st || st.isDirectory()) return false;
|
|
24743
24880
|
return st.mtimeMs < Date.now() - WATCH_WINDOW_MS;
|
|
24744
24881
|
},
|
|
@@ -25108,10 +25245,10 @@ async function codeIndexTick() {
|
|
|
25108
25245
|
continue;
|
|
25109
25246
|
}
|
|
25110
25247
|
for (const cred of creds) {
|
|
25111
|
-
const
|
|
25248
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
25112
25249
|
const headers = { "content-type": "application/json", ...cred.token ? { authorization: `Bearer ${cred.token}` } : {} };
|
|
25113
25250
|
try {
|
|
25114
|
-
await fetchWithTimeout(`${
|
|
25251
|
+
await fetchWithTimeout(`${base3}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
|
|
25115
25252
|
} catch {
|
|
25116
25253
|
}
|
|
25117
25254
|
}
|
|
@@ -25134,12 +25271,12 @@ if (CODE_INDEX_ON) {
|
|
|
25134
25271
|
}
|
|
25135
25272
|
async function autoUpdateTick() {
|
|
25136
25273
|
for (const cred of loadAllCredentials()) {
|
|
25137
|
-
const
|
|
25274
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
25138
25275
|
const headers = cred.token ? { authorization: `Bearer ${cred.token}` } : {};
|
|
25139
25276
|
try {
|
|
25140
|
-
const r = await runAutoUpdate(
|
|
25141
|
-
if (r.updated) daemonLog.info(`auto-update: ${r.reason} (${
|
|
25142
|
-
else if (!/already current|disabled|no CLI release/.test(r.reason)) daemonLog.info(`auto-update: ${r.reason} (${
|
|
25277
|
+
const r = await runAutoUpdate(base3, headers, CLI_VERSION3);
|
|
25278
|
+
if (r.updated) daemonLog.info(`auto-update: ${r.reason} (${base3}) \u2014 restarting service`);
|
|
25279
|
+
else if (!/already current|disabled|no CLI release/.test(r.reason)) daemonLog.info(`auto-update: ${r.reason} (${base3})`);
|
|
25143
25280
|
} catch {
|
|
25144
25281
|
}
|
|
25145
25282
|
}
|
|
@@ -25166,20 +25303,20 @@ async function collectorMigrationOnce() {
|
|
|
25166
25303
|
return;
|
|
25167
25304
|
}
|
|
25168
25305
|
for (const cred of creds) {
|
|
25169
|
-
const
|
|
25306
|
+
const base3 = cred.serverUrl.replace(/\/+$/, "");
|
|
25170
25307
|
const headers = { "content-type": "application/json", ...cred.token ? { authorization: `Bearer ${cred.token}` } : {} };
|
|
25171
25308
|
const reindex = async (rootPath) => {
|
|
25172
25309
|
try {
|
|
25173
25310
|
const result = await collectCode2({ workspace: rootPath, binPath: bin });
|
|
25174
|
-
const res = await fetchWithTimeout(`${
|
|
25311
|
+
const res = await fetchWithTimeout(`${base3}/api/code/index`, { method: "POST", headers, body: JSON.stringify(result) }, 6e4);
|
|
25175
25312
|
return res.ok;
|
|
25176
25313
|
} catch {
|
|
25177
25314
|
return false;
|
|
25178
25315
|
}
|
|
25179
25316
|
};
|
|
25180
25317
|
try {
|
|
25181
|
-
const r = await runCollectorMigration({ base:
|
|
25182
|
-
if (r.reindexed || r.failed || r.missing) daemonLog.info(`collector migration (${
|
|
25318
|
+
const r = await runCollectorMigration({ base: base3, authHeaders: headers, current: COLLECTOR_VERSION2, reindex, log: (m) => daemonLog.info(`${m}`) });
|
|
25319
|
+
if (r.reindexed || r.failed || r.missing) daemonLog.info(`collector migration (${base3}): re-derived ${r.reindexed}, failed ${r.failed}, skipped-missing ${r.missing}`);
|
|
25183
25320
|
} catch {
|
|
25184
25321
|
}
|
|
25185
25322
|
}
|