chat-recall 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-update.d.ts +34 -0
- package/dist/auto-update.d.ts.map +1 -1
- package/dist/auto-update.js +51 -8
- package/dist/auto-update.js.map +1 -1
- package/dist/cli.js +463 -244
- package/dist/cli.js.map +1 -1
- package/dist/code-index-cursor.d.ts +20 -3
- package/dist/code-index-cursor.d.ts.map +1 -1
- package/dist/code-index-cursor.js +53 -8
- package/dist/code-index-cursor.js.map +1 -1
- package/dist/mcp-relay.js +76 -13
- package/dist/mcp-relay.js.map +1 -1
- package/dist/mcp.js +777 -471
- package/dist/mcp.js.map +1 -1
- package/dist/relay-lifecycle.d.ts +69 -0
- package/dist/relay-lifecycle.d.ts.map +1 -0
- package/dist/relay-lifecycle.js +117 -0
- package/dist/relay-lifecycle.js.map +1 -0
- package/dist/repair.d.ts +2 -0
- package/dist/repair.d.ts.map +1 -1
- package/dist/repair.js +23 -3
- package/dist/repair.js.map +1 -1
- package/dist/scan-worker.js +122 -65
- package/dist/service-installer.d.ts.map +1 -1
- package/dist/service-installer.js +7 -2
- package/dist/service-installer.js.map +1 -1
- package/dist/sync-client.d.ts +38 -5
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +194 -61
- package/dist/sync-client.js.map +1 -1
- package/dist/sync-supervisor.d.ts +43 -0
- package/dist/sync-supervisor.d.ts.map +1 -0
- package/dist/sync-supervisor.js +84 -0
- package/dist/sync-supervisor.js.map +1 -0
- package/dist/watch.js +470 -213
- package/package.json +1 -1
package/dist/watch.js
CHANGED
|
@@ -6585,7 +6585,7 @@ var init_raw = __esm({
|
|
|
6585
6585
|
// ../engine/dist/transcript/shadow.js
|
|
6586
6586
|
import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
|
|
6587
6587
|
import { createHash as createHash2 } from "crypto";
|
|
6588
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync4 } from "fs";
|
|
6588
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync4, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
|
|
6589
6589
|
import { dirname as dirname7, join as join8 } from "path";
|
|
6590
6590
|
function shadowRoot() {
|
|
6591
6591
|
return join8(getDataDir(), "shadow");
|
|
@@ -6809,6 +6809,29 @@ function seedShadow(sessionId, container) {
|
|
|
6809
6809
|
}
|
|
6810
6810
|
return fullest;
|
|
6811
6811
|
}
|
|
6812
|
+
function shadowUncompressedBytes(tool, rawId) {
|
|
6813
|
+
const path = shadowFileFor(tool, rawId);
|
|
6814
|
+
let fd = null;
|
|
6815
|
+
try {
|
|
6816
|
+
const size = statSync4(path).size;
|
|
6817
|
+
if (size < 18)
|
|
6818
|
+
return 0;
|
|
6819
|
+
fd = openSync2(path, "r");
|
|
6820
|
+
const tail = Buffer.alloc(4);
|
|
6821
|
+
if (readSync2(fd, tail, 0, 4, size - 4) !== 4)
|
|
6822
|
+
return 0;
|
|
6823
|
+
return tail.readUInt32LE(0);
|
|
6824
|
+
} catch {
|
|
6825
|
+
return 0;
|
|
6826
|
+
} finally {
|
|
6827
|
+
if (fd !== null) {
|
|
6828
|
+
try {
|
|
6829
|
+
closeSync2(fd);
|
|
6830
|
+
} catch {
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6812
6835
|
function shadowSizeOnDisk(tool, rawId) {
|
|
6813
6836
|
try {
|
|
6814
6837
|
return statSync4(shadowFileFor(tool, rawId)).size;
|
|
@@ -6829,7 +6852,7 @@ var init_shadow = __esm({
|
|
|
6829
6852
|
});
|
|
6830
6853
|
|
|
6831
6854
|
// ../engine/dist/core/live-session-scan.js
|
|
6832
|
-
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync4, statSync as statSync5, openSync as
|
|
6855
|
+
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync4, statSync as statSync5, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
|
|
6833
6856
|
import { join as join9, basename as basename5 } from "path";
|
|
6834
6857
|
function detectTool(sessionId) {
|
|
6835
6858
|
return getBackendForId(sessionId)?.id ?? "claude";
|
|
@@ -6856,6 +6879,15 @@ function sessionFileIndex() {
|
|
|
6856
6879
|
return indexCache;
|
|
6857
6880
|
const byId = /* @__PURE__ */ new Map();
|
|
6858
6881
|
const seenRoots = /* @__PURE__ */ new Set();
|
|
6882
|
+
const projectPaths = /* @__PURE__ */ new Map();
|
|
6883
|
+
const projectPathOf = (dirName) => {
|
|
6884
|
+
let p = projectPaths.get(dirName);
|
|
6885
|
+
if (p === void 0) {
|
|
6886
|
+
p = resolveProjectDirName(dirName);
|
|
6887
|
+
projectPaths.set(dirName, p);
|
|
6888
|
+
}
|
|
6889
|
+
return p;
|
|
6890
|
+
};
|
|
6859
6891
|
for (const root of claudeProjectDirs()) {
|
|
6860
6892
|
if (seenRoots.has(root) || !existsSync7(root))
|
|
6861
6893
|
continue;
|
|
@@ -6883,7 +6915,7 @@ function sessionFileIndex() {
|
|
|
6883
6915
|
const located = {
|
|
6884
6916
|
path: join9(dir, name),
|
|
6885
6917
|
projectDir: entry.name,
|
|
6886
|
-
projectPath:
|
|
6918
|
+
projectPath: projectPathOf(entry.name)
|
|
6887
6919
|
};
|
|
6888
6920
|
const prior = byId.get(id);
|
|
6889
6921
|
if (prior)
|
|
@@ -7565,7 +7597,7 @@ var init_flat_string = __esm({
|
|
|
7565
7597
|
});
|
|
7566
7598
|
|
|
7567
7599
|
// ../engine/dist/core/first-prompt.js
|
|
7568
|
-
import { createReadStream as createReadStream2, existsSync as existsSync9, openSync as
|
|
7600
|
+
import { createReadStream as createReadStream2, existsSync as existsSync9, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
|
|
7569
7601
|
import { StringDecoder } from "string_decoder";
|
|
7570
7602
|
function stripBanners2(s) {
|
|
7571
7603
|
let out = s;
|
|
@@ -7619,7 +7651,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
|
|
|
7619
7651
|
const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
|
|
7620
7652
|
let fd;
|
|
7621
7653
|
try {
|
|
7622
|
-
fd =
|
|
7654
|
+
fd = openSync4(filePath, "r");
|
|
7623
7655
|
} catch {
|
|
7624
7656
|
return "";
|
|
7625
7657
|
}
|
|
@@ -7631,7 +7663,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
|
|
|
7631
7663
|
let pos = 0;
|
|
7632
7664
|
let lineNo = 0;
|
|
7633
7665
|
for (; ; ) {
|
|
7634
|
-
const n =
|
|
7666
|
+
const n = readSync4(fd, buf, 0, CHUNK, pos);
|
|
7635
7667
|
if (n <= 0)
|
|
7636
7668
|
break;
|
|
7637
7669
|
pos += n;
|
|
@@ -7657,7 +7689,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
|
|
|
7657
7689
|
return "";
|
|
7658
7690
|
} finally {
|
|
7659
7691
|
try {
|
|
7660
|
-
|
|
7692
|
+
closeSync4(fd);
|
|
7661
7693
|
} catch {
|
|
7662
7694
|
}
|
|
7663
7695
|
}
|
|
@@ -7676,8 +7708,8 @@ var init_first_prompt = __esm({
|
|
|
7676
7708
|
});
|
|
7677
7709
|
|
|
7678
7710
|
// ../engine/dist/core/backends/tail-read.js
|
|
7679
|
-
import { openSync as
|
|
7680
|
-
function readTailFromOffset(path, offset) {
|
|
7711
|
+
import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync6 } from "node:fs";
|
|
7712
|
+
function readTailFromOffset(path, offset, maxBytes = TAIL_READ_MAX_BYTES) {
|
|
7681
7713
|
let size = 0;
|
|
7682
7714
|
try {
|
|
7683
7715
|
size = statSync6(path).size;
|
|
@@ -7686,14 +7718,14 @@ function readTailFromOffset(path, offset) {
|
|
|
7686
7718
|
}
|
|
7687
7719
|
if (size <= offset)
|
|
7688
7720
|
return { text: "", newOffset: offset };
|
|
7689
|
-
const len = Math.min(size - offset,
|
|
7721
|
+
const len = Math.min(size - offset, Math.max(1, maxBytes));
|
|
7690
7722
|
const buf = Buffer.allocUnsafe(len);
|
|
7691
7723
|
let fd = null;
|
|
7692
7724
|
try {
|
|
7693
|
-
fd =
|
|
7725
|
+
fd = openSync5(path, "r");
|
|
7694
7726
|
let got = 0;
|
|
7695
7727
|
while (got < len) {
|
|
7696
|
-
const n =
|
|
7728
|
+
const n = readSync5(fd, buf, got, len - got, offset + got);
|
|
7697
7729
|
if (n <= 0)
|
|
7698
7730
|
break;
|
|
7699
7731
|
got += n;
|
|
@@ -7702,25 +7734,47 @@ function readTailFromOffset(path, offset) {
|
|
|
7702
7734
|
return { text: "", newOffset: offset };
|
|
7703
7735
|
const slice = got < len ? buf.subarray(0, got) : buf;
|
|
7704
7736
|
const lastNl = slice.lastIndexOf(10);
|
|
7705
|
-
if (lastNl
|
|
7706
|
-
|
|
7737
|
+
if (lastNl >= 0) {
|
|
7738
|
+
const text = slice.subarray(0, lastNl + 1).toString("utf-8");
|
|
7739
|
+
return { text, newOffset: offset + lastNl + 1 };
|
|
7707
7740
|
}
|
|
7708
|
-
|
|
7709
|
-
|
|
7741
|
+
if (offset + got >= size)
|
|
7742
|
+
return { text: "", newOffset: offset };
|
|
7743
|
+
const end = findNewline(fd, offset + got, size);
|
|
7744
|
+
if (end < 0)
|
|
7745
|
+
return { text: "", newOffset: offset };
|
|
7746
|
+
return { text: "", newOffset: end + 1, skippedBytes: end + 1 - offset };
|
|
7710
7747
|
} catch {
|
|
7711
7748
|
return { text: "", newOffset: offset };
|
|
7712
7749
|
} finally {
|
|
7713
7750
|
if (fd !== null) {
|
|
7714
7751
|
try {
|
|
7715
|
-
|
|
7752
|
+
closeSync5(fd);
|
|
7716
7753
|
} catch {
|
|
7717
7754
|
}
|
|
7718
7755
|
}
|
|
7719
7756
|
}
|
|
7720
7757
|
}
|
|
7758
|
+
function findNewline(fd, from, size) {
|
|
7759
|
+
const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
|
|
7760
|
+
let pos = from;
|
|
7761
|
+
while (pos < size) {
|
|
7762
|
+
const n = readSync5(fd, block, 0, Math.min(SKIP_SCAN_BYTES, size - pos), pos);
|
|
7763
|
+
if (n <= 0)
|
|
7764
|
+
return -1;
|
|
7765
|
+
const i = block.subarray(0, n).indexOf(10);
|
|
7766
|
+
if (i >= 0)
|
|
7767
|
+
return pos + i;
|
|
7768
|
+
pos += n;
|
|
7769
|
+
}
|
|
7770
|
+
return -1;
|
|
7771
|
+
}
|
|
7772
|
+
var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES;
|
|
7721
7773
|
var init_tail_read = __esm({
|
|
7722
7774
|
"../engine/dist/core/backends/tail-read.js"() {
|
|
7723
7775
|
"use strict";
|
|
7776
|
+
TAIL_READ_MAX_BYTES = 16 * 1024 * 1024;
|
|
7777
|
+
SKIP_SCAN_BYTES = 1024 * 1024;
|
|
7724
7778
|
}
|
|
7725
7779
|
});
|
|
7726
7780
|
|
|
@@ -7997,7 +8051,7 @@ var init_generic_engine = __esm({
|
|
|
7997
8051
|
});
|
|
7998
8052
|
|
|
7999
8053
|
// ../engine/dist/core/backends/claude.js
|
|
8000
|
-
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync5, statSync as statSync7, openSync as
|
|
8054
|
+
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync5, statSync as statSync7, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
8001
8055
|
import { join as join10, basename as basename8 } from "path";
|
|
8002
8056
|
function stripReminders(text) {
|
|
8003
8057
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -8094,13 +8148,13 @@ var init_claude2 = __esm({
|
|
|
8094
8148
|
return null;
|
|
8095
8149
|
let head;
|
|
8096
8150
|
try {
|
|
8097
|
-
const fd =
|
|
8151
|
+
const fd = openSync6(located.path, "r");
|
|
8098
8152
|
try {
|
|
8099
8153
|
const buf = Buffer.alloc(65536);
|
|
8100
|
-
const n =
|
|
8154
|
+
const n = readSync6(fd, buf, 0, buf.length, 0);
|
|
8101
8155
|
head = buf.toString("utf-8", 0, n);
|
|
8102
8156
|
} finally {
|
|
8103
|
-
|
|
8157
|
+
closeSync6(fd);
|
|
8104
8158
|
}
|
|
8105
8159
|
} catch {
|
|
8106
8160
|
return null;
|
|
@@ -8145,12 +8199,12 @@ var init_claude2 = __esm({
|
|
|
8145
8199
|
const seen = /* @__PURE__ */ new Set();
|
|
8146
8200
|
const out = [];
|
|
8147
8201
|
for (const root of claudeProjectDirs()) {
|
|
8148
|
-
this.collectSessionsFromRoot(root, cutoff, filter, seen, out);
|
|
8202
|
+
this.collectSessionsFromRoot(root, cutoff, filter, seen, out, opts.previews !== false);
|
|
8149
8203
|
}
|
|
8150
8204
|
out.sort((a, b) => b.mtime - a.mtime);
|
|
8151
8205
|
return opts.limit ? out.slice(0, opts.limit) : out;
|
|
8152
8206
|
}
|
|
8153
|
-
collectSessionsFromRoot(root, cutoff, filter, seen, out) {
|
|
8207
|
+
collectSessionsFromRoot(root, cutoff, filter, seen, out, previews) {
|
|
8154
8208
|
if (!existsSync10(root))
|
|
8155
8209
|
return;
|
|
8156
8210
|
for (const proj of readdirSync7(root, { withFileTypes: true })) {
|
|
@@ -8209,7 +8263,7 @@ var init_claude2 = __esm({
|
|
|
8209
8263
|
}
|
|
8210
8264
|
if (stat3.mtimeMs < cutoff)
|
|
8211
8265
|
continue;
|
|
8212
|
-
const firstPrompt = extractFirstUserPromptSync(fullPath, { maxLength: 200 });
|
|
8266
|
+
const firstPrompt = previews ? extractFirstUserPromptSync(fullPath, { maxLength: 200 }) : "";
|
|
8213
8267
|
out.push({
|
|
8214
8268
|
toolId: "claude",
|
|
8215
8269
|
rawId: sessionId,
|
|
@@ -8572,14 +8626,14 @@ var init_claude2 = __esm({
|
|
|
8572
8626
|
spansMultipleSources(prefixedId) {
|
|
8573
8627
|
return findSessionFiles(this.toRawId(prefixedId)).length > 1;
|
|
8574
8628
|
}
|
|
8575
|
-
async readFromOffset(prefixedId, offset) {
|
|
8629
|
+
async readFromOffset(prefixedId, offset, maxBytes) {
|
|
8576
8630
|
const rawId = this.toRawId(prefixedId);
|
|
8577
8631
|
const copies = findSessionFiles(rawId);
|
|
8578
8632
|
if (copies.length === 0)
|
|
8579
8633
|
return { text: "", newOffset: offset };
|
|
8580
8634
|
if (copies.length > 1)
|
|
8581
8635
|
return { text: "", newOffset: offset };
|
|
8582
|
-
return readTailFromOffset(copies[0].path, offset);
|
|
8636
|
+
return readTailFromOffset(copies[0].path, offset, maxBytes);
|
|
8583
8637
|
}
|
|
8584
8638
|
};
|
|
8585
8639
|
claudeBackend = new ClaudeBackend();
|
|
@@ -8807,23 +8861,8 @@ var init_opencode = __esm({
|
|
|
8807
8861
|
const projectPath = row.project_path || row.directory || "";
|
|
8808
8862
|
if (filter && !projectPath.toLowerCase().includes(filter))
|
|
8809
8863
|
continue;
|
|
8810
|
-
const
|
|
8811
|
-
|
|
8812
|
-
FROM part p JOIN message m ON m.id = p.message_id
|
|
8813
|
-
WHERE p.session_id = ?
|
|
8814
|
-
AND p.data LIKE '%"type":"text"%'
|
|
8815
|
-
AND m.data LIKE '%"role":"user"%'
|
|
8816
|
-
ORDER BY p.time_created ASC LIMIT 1
|
|
8817
|
-
`).get(row.id);
|
|
8818
|
-
let firstPrompt = "";
|
|
8819
|
-
if (firstUser) {
|
|
8820
|
-
try {
|
|
8821
|
-
const parsed = JSON.parse(firstUser.data);
|
|
8822
|
-
firstPrompt = flatString(String(parsed?.text || "").slice(0, 200));
|
|
8823
|
-
} catch {
|
|
8824
|
-
}
|
|
8825
|
-
}
|
|
8826
|
-
const messageCount = db.prepare("SELECT COUNT(*) as c FROM message WHERE session_id = ?").get(row.id)?.c ?? 0;
|
|
8864
|
+
const firstPrompt = opts.previews === false ? "" : this.firstUserPrompt(db, row.id);
|
|
8865
|
+
const messageCount = opts.previews === false ? 0 : db.prepare("SELECT COUNT(*) as c FROM message WHERE session_id = ?").get(row.id)?.c ?? 0;
|
|
8827
8866
|
const created = new Date(row.time_created || row.time_updated).toISOString();
|
|
8828
8867
|
const modified = new Date(row.time_updated).toISOString();
|
|
8829
8868
|
out.push({
|
|
@@ -8847,6 +8886,45 @@ var init_opencode = __esm({
|
|
|
8847
8886
|
db.close();
|
|
8848
8887
|
}
|
|
8849
8888
|
}
|
|
8889
|
+
/**
|
|
8890
|
+
* The first user text part of a session.
|
|
8891
|
+
*
|
|
8892
|
+
* Walks the session's user messages oldest first through the
|
|
8893
|
+
* (session_id, time_created, id) index and stops at the first one with a
|
|
8894
|
+
* text part. The role and the text are read by SQLite: a first message can
|
|
8895
|
+
* carry whole diffs in `summary` (107 MB on one row), and parsing that in JS
|
|
8896
|
+
* to read one field took the process to 510 MB. The earlier query filtered
|
|
8897
|
+
* every part and message with LIKE and then sorted, so it read all of a
|
|
8898
|
+
* session's data: 423 MB for a 236-session listing.
|
|
8899
|
+
*/
|
|
8900
|
+
firstUserPrompt(db, sessionId) {
|
|
8901
|
+
try {
|
|
8902
|
+
const has = (table, col) => !!db.prepare(`SELECT 1 FROM pragma_table_info(?) WHERE name = ?`).get(table, col);
|
|
8903
|
+
const msgOrder = has("message", "time_created") ? "time_created, id" : "rowid";
|
|
8904
|
+
const partOrder = has("part", "time_created") ? "time_created, id" : "rowid";
|
|
8905
|
+
const nextUser = db.prepare(`SELECT id, ${msgOrder === "rowid" ? "rowid AS k1, 0 AS k2" : "time_created AS k1, id AS k2"} FROM message
|
|
8906
|
+
WHERE session_id = ? AND (${msgOrder === "rowid" ? "rowid, 0" : "time_created, id"}) > (?, ?)
|
|
8907
|
+
AND json_extract(data, '$.role') = 'user'
|
|
8908
|
+
ORDER BY ${msgOrder} LIMIT 1`);
|
|
8909
|
+
const firstText = db.prepare(`SELECT substr(json_extract(data, '$.text'), 1, 400) AS text FROM part
|
|
8910
|
+
WHERE message_id = ? AND json_extract(data, '$.type') = 'text'
|
|
8911
|
+
AND length(trim(json_extract(data, '$.text'))) > 0
|
|
8912
|
+
ORDER BY ${partOrder} LIMIT 1`);
|
|
8913
|
+
let k1 = Number.MIN_SAFE_INTEGER, k2 = msgOrder === "rowid" ? 0 : "";
|
|
8914
|
+
for (; ; ) {
|
|
8915
|
+
const m = nextUser.get(sessionId, k1, k2);
|
|
8916
|
+
if (!m)
|
|
8917
|
+
return "";
|
|
8918
|
+
k1 = m.k1;
|
|
8919
|
+
k2 = m.k2;
|
|
8920
|
+
const t = firstText.get(m.id);
|
|
8921
|
+
if (t?.text)
|
|
8922
|
+
return flatString(t.text.slice(0, 200));
|
|
8923
|
+
}
|
|
8924
|
+
} catch {
|
|
8925
|
+
return "";
|
|
8926
|
+
}
|
|
8927
|
+
}
|
|
8850
8928
|
/** OpenCode auto-generates a session title (model-written, distinct from the
|
|
8851
8929
|
* first prompt — e.g. "Replacing Claude with Gemini CLI"). It's a plain
|
|
8852
8930
|
* column on the session row. */
|
|
@@ -9163,7 +9241,7 @@ var init_opencode = __esm({
|
|
|
9163
9241
|
});
|
|
9164
9242
|
|
|
9165
9243
|
// ../engine/dist/core/backends/codex.js
|
|
9166
|
-
import { readdirSync as readdirSync8, readFileSync as readFileSync6, statSync as statSync8, openSync as
|
|
9244
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync6, statSync as statSync8, openSync as openSync7, readSync as readSync7, closeSync as closeSync7 } from "fs";
|
|
9167
9245
|
import { basename as basename9, dirname as dirname10, join as join12 } from "path";
|
|
9168
9246
|
function parseShellWrites(cmd) {
|
|
9169
9247
|
const out = [];
|
|
@@ -9409,28 +9487,29 @@ var init_codex2 = __esm({
|
|
|
9409
9487
|
continue;
|
|
9410
9488
|
let firstPrompt = "";
|
|
9411
9489
|
let messageCount = 0;
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
|
|
9417
|
-
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9421
|
-
|
|
9422
|
-
|
|
9423
|
-
|
|
9424
|
-
|
|
9425
|
-
|
|
9426
|
-
firstPrompt
|
|
9490
|
+
if (opts.previews !== false)
|
|
9491
|
+
try {
|
|
9492
|
+
const lines = readFileSync6(filePath, "utf-8").split("\n");
|
|
9493
|
+
for (const line of lines) {
|
|
9494
|
+
if (!line.trim())
|
|
9495
|
+
continue;
|
|
9496
|
+
let ev;
|
|
9497
|
+
try {
|
|
9498
|
+
ev = JSON.parse(line);
|
|
9499
|
+
} catch {
|
|
9500
|
+
continue;
|
|
9501
|
+
}
|
|
9502
|
+
if (ev.type === "event_msg" && ev.payload?.type === "user_message") {
|
|
9503
|
+
messageCount++;
|
|
9504
|
+
if (!firstPrompt && ev.payload.message) {
|
|
9505
|
+
firstPrompt = flatString(String(ev.payload.message).slice(0, 200));
|
|
9506
|
+
}
|
|
9507
|
+
} else if (ev.type === "response_item" && ev.payload?.type === "message") {
|
|
9508
|
+
messageCount++;
|
|
9427
9509
|
}
|
|
9428
|
-
} else if (ev.type === "response_item" && ev.payload?.type === "message") {
|
|
9429
|
-
messageCount++;
|
|
9430
9510
|
}
|
|
9511
|
+
} catch {
|
|
9431
9512
|
}
|
|
9432
|
-
} catch {
|
|
9433
|
-
}
|
|
9434
9513
|
const prior = seen.get(rawId);
|
|
9435
9514
|
if (prior) {
|
|
9436
9515
|
if (stat3.mtimeMs > prior.mtime) {
|
|
@@ -9837,10 +9916,10 @@ var init_codex2 = __esm({
|
|
|
9837
9916
|
if (p === loc.path)
|
|
9838
9917
|
continue;
|
|
9839
9918
|
try {
|
|
9840
|
-
const fd =
|
|
9919
|
+
const fd = openSync7(p, "r");
|
|
9841
9920
|
const buf = Buffer.alloc(4096);
|
|
9842
|
-
const n =
|
|
9843
|
-
|
|
9921
|
+
const n = readSync7(fd, buf, 0, 4096, 0);
|
|
9922
|
+
closeSync7(fd);
|
|
9844
9923
|
const head = buf.toString("utf-8", 0, n);
|
|
9845
9924
|
if (head.includes(parentId) && head.includes("parent_thread_id"))
|
|
9846
9925
|
push(p, `subagents/${f}`);
|
|
@@ -9865,11 +9944,11 @@ var init_codex2 = __esm({
|
|
|
9865
9944
|
return 0;
|
|
9866
9945
|
}
|
|
9867
9946
|
}
|
|
9868
|
-
async readFromOffset(prefixedId, offset) {
|
|
9947
|
+
async readFromOffset(prefixedId, offset, maxBytes) {
|
|
9869
9948
|
const loc = this.findSession(prefixedId);
|
|
9870
9949
|
if (!loc)
|
|
9871
9950
|
return { text: "", newOffset: offset };
|
|
9872
|
-
return readTailFromOffset(loc.path, offset);
|
|
9951
|
+
return readTailFromOffset(loc.path, offset, maxBytes);
|
|
9873
9952
|
}
|
|
9874
9953
|
};
|
|
9875
9954
|
codexBackend = new CodexBackend();
|
|
@@ -10120,21 +10199,22 @@ var init_agy = __esm({
|
|
|
10120
10199
|
const projectDir = projectPath ? basename10(projectPath) : "";
|
|
10121
10200
|
let firstPrompt = "";
|
|
10122
10201
|
let messageCount = 0;
|
|
10123
|
-
|
|
10124
|
-
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
const
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
|
|
10132
|
-
|
|
10133
|
-
|
|
10202
|
+
if (opts.previews !== false)
|
|
10203
|
+
try {
|
|
10204
|
+
const lines = readFileSync7(filePath, "utf-8").split("\n").filter(Boolean);
|
|
10205
|
+
messageCount = lines.length;
|
|
10206
|
+
for (const line of lines) {
|
|
10207
|
+
const obj = JSON.parse(line);
|
|
10208
|
+
if (obj.source === "USER_EXPLICIT" && obj.type === "USER_INPUT" && typeof obj.content === "string") {
|
|
10209
|
+
const content = obj.content;
|
|
10210
|
+
const match = content.match(/<USER_REQUEST>([\s\S]*?)<\/USER_REQUEST>/);
|
|
10211
|
+
const rawText = match ? match[1].trim() : content.trim();
|
|
10212
|
+
firstPrompt = flatString(rawText.slice(0, 200));
|
|
10213
|
+
break;
|
|
10214
|
+
}
|
|
10134
10215
|
}
|
|
10216
|
+
} catch {
|
|
10135
10217
|
}
|
|
10136
|
-
} catch {
|
|
10137
|
-
}
|
|
10138
10218
|
if (seenIds.has(rawId))
|
|
10139
10219
|
continue;
|
|
10140
10220
|
seenIds.add(rawId);
|
|
@@ -10430,11 +10510,11 @@ var init_agy = __esm({
|
|
|
10430
10510
|
return 0;
|
|
10431
10511
|
}
|
|
10432
10512
|
}
|
|
10433
|
-
async readFromOffset(prefixedId, offset) {
|
|
10513
|
+
async readFromOffset(prefixedId, offset, maxBytes) {
|
|
10434
10514
|
const loc = this.findSession(prefixedId);
|
|
10435
10515
|
if (!loc)
|
|
10436
10516
|
return { text: "", newOffset: offset };
|
|
10437
|
-
return readTailFromOffset(loc.path, offset);
|
|
10517
|
+
return readTailFromOffset(loc.path, offset, maxBytes);
|
|
10438
10518
|
}
|
|
10439
10519
|
};
|
|
10440
10520
|
agyBackend = new AgyBackend();
|
|
@@ -12895,10 +12975,10 @@ var init_types = __esm({
|
|
|
12895
12975
|
|
|
12896
12976
|
// ../engine/dist/transcript/opencode.js
|
|
12897
12977
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
12898
|
-
const { existsSync:
|
|
12978
|
+
const { existsSync: existsSync51 } = await import("fs");
|
|
12899
12979
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12900
12980
|
const dbPath = opencodeBackend2.dbPath();
|
|
12901
|
-
if (!
|
|
12981
|
+
if (!existsSync51(dbPath))
|
|
12902
12982
|
return [];
|
|
12903
12983
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
12904
12984
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -12939,10 +13019,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
12939
13019
|
}
|
|
12940
13020
|
}
|
|
12941
13021
|
async function parseOpenCodeTranscript(sessionId) {
|
|
12942
|
-
const { existsSync:
|
|
13022
|
+
const { existsSync: existsSync51 } = await import("fs");
|
|
12943
13023
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
12944
13024
|
const dbPath = opencodeBackend2.dbPath();
|
|
12945
|
-
if (!
|
|
13025
|
+
if (!existsSync51(dbPath))
|
|
12946
13026
|
return [];
|
|
12947
13027
|
const realId = sessionId.replace("opencode_", "");
|
|
12948
13028
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -13019,6 +13099,7 @@ __export(transcript_exports, {
|
|
|
13019
13099
|
shadowFileFor: () => shadowFileFor,
|
|
13020
13100
|
shadowRoot: () => shadowRoot,
|
|
13021
13101
|
shadowSizeOnDisk: () => shadowSizeOnDisk,
|
|
13102
|
+
shadowUncompressedBytes: () => shadowUncompressedBytes,
|
|
13022
13103
|
snapshotShadow: () => snapshotShadow,
|
|
13023
13104
|
trimTranscriptForSync: () => trimTranscriptForSync,
|
|
13024
13105
|
updateShadow: () => updateShadow,
|
|
@@ -13201,12 +13282,13 @@ function resolveProjectId(inputPath) {
|
|
|
13201
13282
|
if (!isAbsolute(inputPath)) {
|
|
13202
13283
|
return { id: `path:${inputPath}`, displayName: inputPath, source: "path" };
|
|
13203
13284
|
}
|
|
13285
|
+
const known = inputCache.get(inputPath);
|
|
13286
|
+
if (known)
|
|
13287
|
+
return known;
|
|
13204
13288
|
const realPath = safeRealpath(inputPath);
|
|
13205
|
-
const
|
|
13206
|
-
if (cached)
|
|
13207
|
-
return cached;
|
|
13208
|
-
const result = doResolve(realPath);
|
|
13289
|
+
const result = resolveCache.get(realPath) ?? doResolve(realPath);
|
|
13209
13290
|
resolveCache.set(realPath, result);
|
|
13291
|
+
inputCache.set(inputPath, result);
|
|
13210
13292
|
return result;
|
|
13211
13293
|
}
|
|
13212
13294
|
function doResolve(realPath) {
|
|
@@ -13485,7 +13567,7 @@ function globToRegex(glob) {
|
|
|
13485
13567
|
function escapeRe(s) {
|
|
13486
13568
|
return s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
13487
13569
|
}
|
|
13488
|
-
var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
|
|
13570
|
+
var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, inputCache, gitCache, workspaceCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
|
|
13489
13571
|
var init_project_resolver = __esm({
|
|
13490
13572
|
"../engine/dist/core/project-resolver.js"() {
|
|
13491
13573
|
"use strict";
|
|
@@ -13493,6 +13575,7 @@ var init_project_resolver = __esm({
|
|
|
13493
13575
|
DEFAULT_AUTO_WORKSPACE_MIN_REPOS = 3;
|
|
13494
13576
|
BOT_WORKTREE_MARKERS = [".claude-pr-bot"];
|
|
13495
13577
|
resolveCache = /* @__PURE__ */ new Map();
|
|
13578
|
+
inputCache = /* @__PURE__ */ new Map();
|
|
13496
13579
|
gitCache = /* @__PURE__ */ new Map();
|
|
13497
13580
|
workspaceCache = /* @__PURE__ */ new Map();
|
|
13498
13581
|
cachedConfig = null;
|
|
@@ -17875,7 +17958,7 @@ var init_sync_fields = __esm({
|
|
|
17875
17958
|
});
|
|
17876
17959
|
|
|
17877
17960
|
// ../engine/dist/core/index-lock.js
|
|
17878
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as
|
|
17961
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync8, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as statSync35, closeSync as closeSync8 } from "fs";
|
|
17879
17962
|
import { dirname as dirname17, join as join40 } from "path";
|
|
17880
17963
|
function acquireIndexLock(opts) {
|
|
17881
17964
|
const lockPath = lockFilePath();
|
|
@@ -17887,7 +17970,7 @@ function acquireIndexLock(opts) {
|
|
|
17887
17970
|
}
|
|
17888
17971
|
let fd;
|
|
17889
17972
|
try {
|
|
17890
|
-
fd =
|
|
17973
|
+
fd = openSync8(lockPath, "wx", 384);
|
|
17891
17974
|
} catch (err) {
|
|
17892
17975
|
if (err.code === "EEXIST")
|
|
17893
17976
|
return null;
|
|
@@ -17897,7 +17980,7 @@ function acquireIndexLock(opts) {
|
|
|
17897
17980
|
try {
|
|
17898
17981
|
writeFileSync7(fd, JSON.stringify(holder));
|
|
17899
17982
|
} finally {
|
|
17900
|
-
|
|
17983
|
+
closeSync8(fd);
|
|
17901
17984
|
}
|
|
17902
17985
|
let released = false;
|
|
17903
17986
|
return {
|
|
@@ -17988,7 +18071,7 @@ var init_http = __esm({
|
|
|
17988
18071
|
CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
17989
18072
|
} catch {
|
|
17990
18073
|
try {
|
|
17991
|
-
if (true) CLI_VERSION = "0.7.
|
|
18074
|
+
if (true) CLI_VERSION = "0.7.2";
|
|
17992
18075
|
} catch {
|
|
17993
18076
|
}
|
|
17994
18077
|
}
|
|
@@ -18460,16 +18543,16 @@ async function flush() {
|
|
|
18460
18543
|
}
|
|
18461
18544
|
function stableMark(value) {
|
|
18462
18545
|
try {
|
|
18463
|
-
const { createHash:
|
|
18464
|
-
return
|
|
18546
|
+
const { createHash: createHash14 } = __require("node:crypto");
|
|
18547
|
+
return createHash14("sha256").update(value).digest("hex").slice(0, 12);
|
|
18465
18548
|
} catch {
|
|
18466
18549
|
return "";
|
|
18467
18550
|
}
|
|
18468
18551
|
}
|
|
18469
18552
|
function hashHost() {
|
|
18470
18553
|
try {
|
|
18471
|
-
const { createHash:
|
|
18472
|
-
return
|
|
18554
|
+
const { createHash: createHash14 } = __require("node:crypto");
|
|
18555
|
+
return createHash14("sha256").update(hostname()).digest("hex").slice(0, 12);
|
|
18473
18556
|
} catch {
|
|
18474
18557
|
return "";
|
|
18475
18558
|
}
|
|
@@ -18483,7 +18566,7 @@ var init_telemetry = __esm({
|
|
|
18483
18566
|
init_sync_client();
|
|
18484
18567
|
cliVersion = () => {
|
|
18485
18568
|
try {
|
|
18486
|
-
return true ? "0.7.
|
|
18569
|
+
return true ? "0.7.2" : "dev";
|
|
18487
18570
|
} catch {
|
|
18488
18571
|
return "dev";
|
|
18489
18572
|
}
|
|
@@ -18708,16 +18791,17 @@ __export(auto_update_exports, {
|
|
|
18708
18791
|
noteUpdateFailure: () => noteUpdateFailure,
|
|
18709
18792
|
planAutoUpdate: () => planAutoUpdate,
|
|
18710
18793
|
readUpdateState: () => readUpdateState,
|
|
18794
|
+
resolveNpm: () => resolveNpm,
|
|
18711
18795
|
runAutoUpdate: () => runAutoUpdate,
|
|
18712
18796
|
runningPrefix: () => runningPrefix,
|
|
18713
18797
|
sweepStaleStaging: () => sweepStaleStaging,
|
|
18714
18798
|
tarballUrl: () => tarballUrl
|
|
18715
18799
|
});
|
|
18716
|
-
import { execSync as execSync2 } from "node:child_process";
|
|
18717
|
-
import { readFileSync as readFileSync34 } from "node:fs";
|
|
18800
|
+
import { execSync as execSync2, execFileSync as execFileSync3 } from "node:child_process";
|
|
18801
|
+
import { readFileSync as readFileSync34, existsSync as existsSync41 } from "node:fs";
|
|
18718
18802
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
18719
18803
|
import { writeFileSync as writeFileSync8, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync31, statSync as statSync36, mkdirSync as mkdirSync9 } from "node:fs";
|
|
18720
|
-
import { join as join41, dirname as dirname18, sep as sep2 } from "node:path";
|
|
18804
|
+
import { join as join41, dirname as dirname18, sep as sep2, posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
18721
18805
|
import { tmpdir as tmpdir2, homedir as homedir15 } from "node:os";
|
|
18722
18806
|
import { createHash as createHash7 } from "node:crypto";
|
|
18723
18807
|
function compareVersions(a, b) {
|
|
@@ -18832,25 +18916,46 @@ function runningPrefix(moduleUrl = import.meta.url) {
|
|
|
18832
18916
|
const beforeNodeModules = here.slice(0, at);
|
|
18833
18917
|
return beforeNodeModules.endsWith(`${sep2}lib`) ? beforeNodeModules.slice(0, -4) : beforeNodeModules;
|
|
18834
18918
|
}
|
|
18835
|
-
function npmInstall(
|
|
18919
|
+
function npmInstall(npm, args) {
|
|
18836
18920
|
try {
|
|
18837
|
-
|
|
18921
|
+
const opts = { stdio: ["ignore", "ignore", "pipe"], env: npm.env };
|
|
18922
|
+
if (npm.shell) execSync2([npm.file, ...npm.args, ...args].map((a) => `"${a}"`).join(" "), opts);
|
|
18923
|
+
else execFileSync3(npm.file, [...npm.args, ...args], opts);
|
|
18838
18924
|
} catch (e) {
|
|
18839
18925
|
const err = e;
|
|
18840
18926
|
const detail = String(err.stderr ?? "").trim().split("\n").filter((l) => l.trim() && !/^npm (notice|warn)\b/i.test(l)).slice(-4).join(" | ").slice(0, 400);
|
|
18841
18927
|
throw new Error(detail ? `${err.message ?? "install failed"} \u2014 ${detail}` : err.message ?? "install failed");
|
|
18842
18928
|
}
|
|
18843
18929
|
}
|
|
18930
|
+
function resolveNpm(loc) {
|
|
18931
|
+
const win = loc.platform === "win32";
|
|
18932
|
+
const p = win ? pathWin32 : pathPosix;
|
|
18933
|
+
const nodeDir = p.dirname(loc.execPath);
|
|
18934
|
+
const cliUnder = (root) => win ? p.join(root, "node_modules", "npm", "bin", "npm-cli.js") : p.join(root, "lib", "node_modules", "npm", "bin", "npm-cli.js");
|
|
18935
|
+
const candidates2 = [
|
|
18936
|
+
cliUnder(win ? nodeDir : p.join(nodeDir, "..")),
|
|
18937
|
+
...loc.prefix ? [cliUnder(loc.prefix)] : []
|
|
18938
|
+
];
|
|
18939
|
+
const pathKey = Object.keys(loc.env).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
|
|
18940
|
+
const binDirs = [nodeDir, ...loc.prefix ? [win ? loc.prefix : p.join(loc.prefix, "bin")] : []];
|
|
18941
|
+
const delimiter3 = win ? ";" : ":";
|
|
18942
|
+
const current = loc.env[pathKey] ?? "";
|
|
18943
|
+
const env = { ...loc.env, [pathKey]: [...binDirs, ...current ? [current] : []].join(delimiter3) };
|
|
18944
|
+
const cli = candidates2.find((c) => loc.exists(c));
|
|
18945
|
+
if (cli) return { file: loc.execPath, args: [cli], env, shell: false };
|
|
18946
|
+
return { file: "npm", args: [], env, shell: true };
|
|
18947
|
+
}
|
|
18844
18948
|
function realInstall(tgz) {
|
|
18845
18949
|
const prefix = runningPrefix();
|
|
18950
|
+
const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync41 });
|
|
18846
18951
|
if (prefix) {
|
|
18847
|
-
npmInstall(
|
|
18952
|
+
npmInstall(npm, ["install", "-g", "--prefix", prefix, tgz]);
|
|
18848
18953
|
return;
|
|
18849
18954
|
}
|
|
18850
18955
|
try {
|
|
18851
|
-
npmInstall(
|
|
18956
|
+
npmInstall(npm, ["install", "-g", tgz]);
|
|
18852
18957
|
} catch {
|
|
18853
|
-
npmInstall(
|
|
18958
|
+
npmInstall(npm, ["install", "-g", "--prefix", join41(homedir15(), ".local"), tgz]);
|
|
18854
18959
|
}
|
|
18855
18960
|
}
|
|
18856
18961
|
function realRestart(platform2) {
|
|
@@ -19434,7 +19539,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19434
19539
|
const listSinceMs = changedWalk ? Math.max(0, (opts.sinceMs ?? 0) - CHANGED_WALK_OVERLAP_MS) : opts.useLedger ? void 0 : opts.sinceMs;
|
|
19435
19540
|
const refs = listAvailableBackends().flatMap((b) => {
|
|
19436
19541
|
try {
|
|
19437
|
-
return b.listSessions({ sinceMs: listSinceMs });
|
|
19542
|
+
return b.listSessions({ sinceMs: listSinceMs, previews: false });
|
|
19438
19543
|
} catch {
|
|
19439
19544
|
return [];
|
|
19440
19545
|
}
|
|
@@ -19653,16 +19758,53 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19653
19758
|
clearTimeout(timer);
|
|
19654
19759
|
}
|
|
19655
19760
|
};
|
|
19761
|
+
const postChunkedHead = async (conv, fileSize) => {
|
|
19762
|
+
const headers = { "content-type": "application/json" };
|
|
19763
|
+
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
19764
|
+
const ac = new AbortController();
|
|
19765
|
+
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
19766
|
+
try {
|
|
19767
|
+
const res = await fetch(`${base2}/api/sync`, {
|
|
19768
|
+
method: "POST",
|
|
19769
|
+
headers,
|
|
19770
|
+
body: JSON.stringify({ conversations: [conv] }),
|
|
19771
|
+
signal: ac.signal
|
|
19772
|
+
});
|
|
19773
|
+
if (!res.ok) throw new Error(`chunked head sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
19774
|
+
const body = await res.json().catch(() => ({}));
|
|
19775
|
+
const id = conv.session_id;
|
|
19776
|
+
const guarded = (body.shrink_guarded ?? []).find((g) => g.session_id === id);
|
|
19777
|
+
const mtime = conv.mtime;
|
|
19778
|
+
try {
|
|
19779
|
+
if (!guarded) {
|
|
19780
|
+
markSynced(base2, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
|
|
19781
|
+
} else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
|
|
19782
|
+
markSynced(base2, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
|
|
19783
|
+
} else {
|
|
19784
|
+
markSynced(base2, [{ id, mtime }]);
|
|
19785
|
+
}
|
|
19786
|
+
} catch {
|
|
19787
|
+
}
|
|
19788
|
+
appendResults.uploaded++;
|
|
19789
|
+
} finally {
|
|
19790
|
+
clearTimeout(timer);
|
|
19791
|
+
}
|
|
19792
|
+
};
|
|
19656
19793
|
let appendBatch = [];
|
|
19794
|
+
let appendBatchBytes = 0;
|
|
19657
19795
|
const APPEND_BATCH_SIZE = 50;
|
|
19796
|
+
const APPEND_BATCH_MAX_BYTES = SYNC_CHUNK_BYTES;
|
|
19658
19797
|
const appendFlush = async () => {
|
|
19659
19798
|
if (appendBatch.length === 0) return;
|
|
19660
19799
|
const batch = appendBatch;
|
|
19661
19800
|
appendBatch = [];
|
|
19801
|
+
appendBatchBytes = 0;
|
|
19662
19802
|
await postAppend(batch);
|
|
19663
19803
|
};
|
|
19664
|
-
const appendAdd = async (conv) => {
|
|
19804
|
+
const appendAdd = async (conv, bytes = 0) => {
|
|
19805
|
+
if (appendBatch.length > 0 && appendBatchBytes + bytes > APPEND_BATCH_MAX_BYTES) await appendFlush();
|
|
19665
19806
|
appendBatch.push(conv);
|
|
19807
|
+
appendBatchBytes += bytes;
|
|
19666
19808
|
if (appendBatch.length >= APPEND_BATCH_SIZE) await appendFlush();
|
|
19667
19809
|
};
|
|
19668
19810
|
const itemsBatch = makeBatcher("items", 100);
|
|
@@ -19712,7 +19854,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19712
19854
|
cred,
|
|
19713
19855
|
() => listAvailableBackends().flatMap((b) => {
|
|
19714
19856
|
try {
|
|
19715
|
-
return b.listSessions({});
|
|
19857
|
+
return b.listSessions({ previews: false });
|
|
19716
19858
|
} catch {
|
|
19717
19859
|
return [];
|
|
19718
19860
|
}
|
|
@@ -19741,7 +19883,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19741
19883
|
let externalFindings = null;
|
|
19742
19884
|
if (scanSecrets) {
|
|
19743
19885
|
externalFindings = /* @__PURE__ */ new Map();
|
|
19744
|
-
const toScan = slice.filter((ref) => modeOf(ref) === "full" &&
|
|
19886
|
+
const toScan = slice.filter((ref) => modeOf(ref) === "full" && sessionBuildBytes(ref) <= FULL_BUILD_MAX_BYTES);
|
|
19745
19887
|
trace?.(`batch secret scan start: ${toScan.length} session(s), \u2264${(BATCH_SCAN_MAX_BYTES / 1048576).toFixed(0)}MB per slice`);
|
|
19746
19888
|
const batch = batchScanExternal(
|
|
19747
19889
|
toScan.map((ref) => ({
|
|
@@ -19785,11 +19927,17 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19785
19927
|
const ack = ledger.get(ref.prefixedId);
|
|
19786
19928
|
try {
|
|
19787
19929
|
const tail = await buildConversationTail(ref, ack.o ?? 0, { mapPath, tenantRules });
|
|
19788
|
-
|
|
19930
|
+
const chunked = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
|
|
19931
|
+
if (tail && tail.findings.length > 0 && !chunked) {
|
|
19789
19932
|
promotedForFindings = true;
|
|
19790
19933
|
} else if (tail) {
|
|
19791
19934
|
redactions += tail.redactions;
|
|
19792
|
-
await appendAdd(tail.conv);
|
|
19935
|
+
await appendAdd(tail.conv, tail.bytes);
|
|
19936
|
+
if (tail.findings.length > 0) {
|
|
19937
|
+
await appendFlush();
|
|
19938
|
+
const all = await scanTranscriptFindingsChunked(ref, tenantRules);
|
|
19939
|
+
if (all.length > 0) await findingsBatch.add(all);
|
|
19940
|
+
}
|
|
19793
19941
|
walked++;
|
|
19794
19942
|
if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
|
|
19795
19943
|
continue;
|
|
@@ -19837,12 +19985,13 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19837
19985
|
}
|
|
19838
19986
|
redactions += built.redactions;
|
|
19839
19987
|
if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
|
|
19840
|
-
await
|
|
19988
|
+
if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
|
|
19989
|
+
else await convBatch.add(built.conv);
|
|
19841
19990
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
19842
19991
|
if (upload.sessionMeta) {
|
|
19843
19992
|
await accumulateKg(extractEntities(built.kgText, { projectPath: built.projectPath, sourceType: "session", sessionId: ref.prefixedId, validFrom: ref.mtime ? new Date(ref.mtime).toISOString().slice(0, 10) : void 0 }), ref.prefixedId);
|
|
19844
19993
|
}
|
|
19845
|
-
if (upload.sessionMeta && sessionFileBytes(ref) <=
|
|
19994
|
+
if (upload.sessionMeta && sessionFileBytes(ref) <= DERIVED_MAX_BYTES) {
|
|
19846
19995
|
try {
|
|
19847
19996
|
const count = { redactions: 0 };
|
|
19848
19997
|
const offloaded = await scanPool().runDerived({
|
|
@@ -20022,35 +20171,70 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
20022
20171
|
scanMs: Math.round(scanMs)
|
|
20023
20172
|
};
|
|
20024
20173
|
}
|
|
20174
|
+
async function scanTranscriptFindingsChunked(ref, tenantRules) {
|
|
20175
|
+
const backend = getBackendForId(ref.prefixedId);
|
|
20176
|
+
const findings = [];
|
|
20177
|
+
if (!backend?.readFromOffset) return findings;
|
|
20178
|
+
let offset = 0;
|
|
20179
|
+
let lineBase = 0;
|
|
20180
|
+
for (; ; ) {
|
|
20181
|
+
const chunk = await backend.readFromOffset(ref.prefixedId, offset, SYNC_CHUNK_BYTES);
|
|
20182
|
+
if (chunk.newOffset <= offset) break;
|
|
20183
|
+
offset = chunk.newOffset;
|
|
20184
|
+
if (chunk.skippedBytes) {
|
|
20185
|
+
lineBase += 1;
|
|
20186
|
+
continue;
|
|
20187
|
+
}
|
|
20188
|
+
try {
|
|
20189
|
+
for (const f of scanTextForFindings(chunk.text)) {
|
|
20190
|
+
findings.push({ session_id: ref.prefixedId, detector: "builtin", rule: f.rule, line: lineBase + f.line, preview: f.preview });
|
|
20191
|
+
}
|
|
20192
|
+
if (tenantRules && tenantRules.length > 0) {
|
|
20193
|
+
for (const f of scanTenantRules(chunk.text, tenantRules)) {
|
|
20194
|
+
findings.push({ session_id: ref.prefixedId, detector: f.detector, rule: f.rule, line: lineBase + f.line, preview: f.preview });
|
|
20195
|
+
}
|
|
20196
|
+
}
|
|
20197
|
+
} catch {
|
|
20198
|
+
}
|
|
20199
|
+
for (let i = chunk.text.indexOf("\n"); i >= 0; i = chunk.text.indexOf("\n", i + 1)) lineBase++;
|
|
20200
|
+
}
|
|
20201
|
+
return dropFuzzyFindings(findings, (f) => ({ detector: f.detector, rule: f.rule }));
|
|
20202
|
+
}
|
|
20025
20203
|
function sessionFileBytes(ref) {
|
|
20026
20204
|
const backend = getBackendForId(ref.prefixedId);
|
|
20027
20205
|
if (!backend?.isAppendOnly?.()) return 0;
|
|
20028
20206
|
return backend.fileSize?.(ref.prefixedId) ?? 0;
|
|
20029
20207
|
}
|
|
20208
|
+
function sessionBuildBytes(ref) {
|
|
20209
|
+
const main = sessionFileBytes(ref);
|
|
20210
|
+
if (main === 0) return 0;
|
|
20211
|
+
return Math.max(main, shadowUncompressedBytes(ref.toolId, ref.rawId));
|
|
20212
|
+
}
|
|
20030
20213
|
async function buildConversationSync(ref, mtime, opts = {}) {
|
|
20031
20214
|
const mapPath = opts.mapPath ?? ((p) => p);
|
|
20032
20215
|
let includeRaw = opts.includeRaw !== false;
|
|
20033
20216
|
let includeMeta = opts.includeMeta !== false;
|
|
20034
20217
|
let srcHash;
|
|
20035
|
-
const
|
|
20036
|
-
|
|
20037
|
-
let
|
|
20038
|
-
let tailOffsetEnd = 0;
|
|
20218
|
+
const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
|
|
20219
|
+
let headOffsetEnd = 0;
|
|
20220
|
+
let oversizedFindings = null;
|
|
20039
20221
|
let transcript = null;
|
|
20040
20222
|
let fullestContainer = null;
|
|
20041
20223
|
if (oversized) {
|
|
20042
20224
|
const backend = getBackendForId(ref.prefixedId);
|
|
20043
20225
|
if (!backend?.readFromOffset) return null;
|
|
20044
20226
|
try {
|
|
20045
|
-
|
|
20046
|
-
|
|
20047
|
-
|
|
20048
|
-
|
|
20227
|
+
let head = await backend.readFromOffset(ref.prefixedId, 0, SYNC_CHUNK_BYTES);
|
|
20228
|
+
for (let hops = 0; head.skippedBytes && hops < 8; hops++) {
|
|
20229
|
+
head = await backend.readFromOffset(ref.prefixedId, head.newOffset, SYNC_CHUNK_BYTES);
|
|
20230
|
+
}
|
|
20231
|
+
headOffsetEnd = head.newOffset;
|
|
20232
|
+
const messages = parseTailMessages(ref.toolId, head.text);
|
|
20049
20233
|
if (messages.length > 0) transcript = { messages, subagents: [] };
|
|
20050
20234
|
} catch {
|
|
20051
20235
|
}
|
|
20052
20236
|
includeRaw = false;
|
|
20053
|
-
|
|
20237
|
+
oversizedFindings = await scanTranscriptFindingsChunked(ref, opts.tenantRules);
|
|
20054
20238
|
} else {
|
|
20055
20239
|
try {
|
|
20056
20240
|
const backend = getBackendForId(ref.prefixedId) ?? getBackend("claude");
|
|
@@ -20111,7 +20295,6 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
20111
20295
|
);
|
|
20112
20296
|
let projectPath = ref.projectPath;
|
|
20113
20297
|
const meta = { messageCount: textMessages.length };
|
|
20114
|
-
if (oversized) meta.truncated = true;
|
|
20115
20298
|
if (textMessages.filter((m) => m.role === "user").length <= 1) meta.oneShot = true;
|
|
20116
20299
|
try {
|
|
20117
20300
|
const cwd = ref.fullPath ? readCwdFromJsonl(ref.fullPath) : "";
|
|
@@ -20225,21 +20408,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
20225
20408
|
}
|
|
20226
20409
|
scanMs = performance.now() - t0;
|
|
20227
20410
|
}
|
|
20228
|
-
if (
|
|
20229
|
-
const t0 = performance.now();
|
|
20230
|
-
try {
|
|
20231
|
-
for (const f of scanTextForFindings(tailText)) {
|
|
20232
|
-
findings.push({ session_id: ref.prefixedId, detector: "builtin", rule: f.rule, line: f.line, preview: f.preview });
|
|
20233
|
-
}
|
|
20234
|
-
if (opts.tenantRules && opts.tenantRules.length > 0) {
|
|
20235
|
-
for (const f of scanTenantRules(tailText, opts.tenantRules)) {
|
|
20236
|
-
findings.push({ session_id: ref.prefixedId, detector: f.detector, rule: f.rule, line: f.line, preview: f.preview });
|
|
20237
|
-
}
|
|
20238
|
-
}
|
|
20239
|
-
} catch {
|
|
20240
|
-
}
|
|
20241
|
-
scanMs = performance.now() - t0;
|
|
20242
|
-
}
|
|
20411
|
+
if (oversizedFindings) findings.push(...oversizedFindings);
|
|
20243
20412
|
const keptFindings = dropFuzzyFindings(findings, (f) => ({ detector: f.detector, rule: f.rule }));
|
|
20244
20413
|
findings.length = 0;
|
|
20245
20414
|
findings.push(...keptFindings);
|
|
@@ -20285,7 +20454,10 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
20285
20454
|
// (convBatch onFlush uses this, not a recomputed size) so the next
|
|
20286
20455
|
// append's base_offset matches exactly — no spurious continuity misses on
|
|
20287
20456
|
// an actively-growing session. undefined for non-append-only backends.
|
|
20288
|
-
from_offset: oversized ?
|
|
20457
|
+
from_offset: oversized ? headOffsetEnd : getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId),
|
|
20458
|
+
// The head of a chunked session. The server reports back when its shrink
|
|
20459
|
+
// guard keeps a fuller stored copy, so the client appends from there.
|
|
20460
|
+
...oversized ? { chunked: true } : {},
|
|
20289
20461
|
meta,
|
|
20290
20462
|
mtime
|
|
20291
20463
|
},
|
|
@@ -20307,12 +20479,30 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
|
|
|
20307
20479
|
const backend = getBackendForId(ref.prefixedId);
|
|
20308
20480
|
if (!backend?.readFromOffset) return null;
|
|
20309
20481
|
const mapPath = opts.mapPath ?? ((p) => p);
|
|
20310
|
-
const { text: tailText, newOffset } = await backend.readFromOffset(ref.prefixedId, fromOffset);
|
|
20311
|
-
if (
|
|
20312
|
-
const messages = parseTailMessages(ref.toolId, tailText);
|
|
20313
|
-
if (messages.length === 0) return null;
|
|
20482
|
+
const { text: tailText, newOffset, skippedBytes } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
|
|
20483
|
+
if (newOffset <= fromOffset) return null;
|
|
20484
|
+
const messages = skippedBytes ? [] : parseTailMessages(ref.toolId, tailText);
|
|
20314
20485
|
const textMessages = messages.filter((m) => m.role !== "summary" && m.content?.trim());
|
|
20315
|
-
|
|
20486
|
+
const hasContent = textMessages.length > 0 || messages.some((m) => m.toolCalls?.length);
|
|
20487
|
+
if (!hasContent) {
|
|
20488
|
+
return {
|
|
20489
|
+
conv: {
|
|
20490
|
+
session_id: ref.prefixedId,
|
|
20491
|
+
tool: ref.toolId,
|
|
20492
|
+
project_path: mapPath(ref.projectPath),
|
|
20493
|
+
append: true,
|
|
20494
|
+
base_offset: fromOffset,
|
|
20495
|
+
from_offset: newOffset,
|
|
20496
|
+
redacted_text: "",
|
|
20497
|
+
envelope: { v: TRANSCRIPT_VERSION, messages: [], subagents: [] },
|
|
20498
|
+
mtime: Math.floor(ref.mtime) || 0
|
|
20499
|
+
},
|
|
20500
|
+
redactions: 0,
|
|
20501
|
+
newOffset,
|
|
20502
|
+
findings: [],
|
|
20503
|
+
bytes: 0
|
|
20504
|
+
};
|
|
20505
|
+
}
|
|
20316
20506
|
const firstUser = textMessages.find((m) => m.role === "user");
|
|
20317
20507
|
if (isInternalToolPrompt(firstUser?.content)) return null;
|
|
20318
20508
|
const count = { redactions: 0 };
|
|
@@ -20355,7 +20545,8 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
|
|
|
20355
20545
|
},
|
|
20356
20546
|
redactions: count.redactions,
|
|
20357
20547
|
newOffset,
|
|
20358
|
-
findings
|
|
20548
|
+
findings,
|
|
20549
|
+
bytes: Buffer.byteLength(tailText)
|
|
20359
20550
|
};
|
|
20360
20551
|
}
|
|
20361
20552
|
function isSyncSkip(r) {
|
|
@@ -20385,7 +20576,7 @@ async function syncIncremental(opts = {}) {
|
|
|
20385
20576
|
lock.release();
|
|
20386
20577
|
}
|
|
20387
20578
|
}
|
|
20388
|
-
var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, SYNC_RULES_REFUSAL, hashPath, acceptedUploads, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES,
|
|
20579
|
+
var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, SYNC_RULES_REFUSAL, hashPath, acceptedUploads, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, DERIVED_MAX_BYTES, SYNC_CHUNK_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
20389
20580
|
var init_sync_client = __esm({
|
|
20390
20581
|
"src/sync-client.ts"() {
|
|
20391
20582
|
"use strict";
|
|
@@ -20430,7 +20621,7 @@ var init_sync_client = __esm({
|
|
|
20430
20621
|
ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
20431
20622
|
} catch {
|
|
20432
20623
|
try {
|
|
20433
|
-
if (true) ownVersion = "0.7.
|
|
20624
|
+
if (true) ownVersion = "0.7.2";
|
|
20434
20625
|
} catch {
|
|
20435
20626
|
}
|
|
20436
20627
|
}
|
|
@@ -20456,8 +20647,9 @@ var init_sync_client = __esm({
|
|
|
20456
20647
|
capsOk = /* @__PURE__ */ new Map();
|
|
20457
20648
|
advertisedIngestConc = /* @__PURE__ */ new Map();
|
|
20458
20649
|
advertisedGzipBody = /* @__PURE__ */ new Set();
|
|
20459
|
-
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "
|
|
20460
|
-
|
|
20650
|
+
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "24", 10)) * 1024 * 1024;
|
|
20651
|
+
DERIVED_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_DERIVED_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
20652
|
+
SYNC_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
20461
20653
|
BATCH_SCAN_MAX_BYTES = Math.max(1, parseInt(process.env.CHAT_RECALL_BATCHSCAN_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
20462
20654
|
}
|
|
20463
20655
|
});
|
|
@@ -20606,7 +20798,7 @@ var init_artifact_codec = __esm({
|
|
|
20606
20798
|
});
|
|
20607
20799
|
|
|
20608
20800
|
// ../engine/dist/core/toolkit-sync.js
|
|
20609
|
-
import { existsSync as
|
|
20801
|
+
import { existsSync as existsSync42, mkdirSync as mkdirSync11, readFileSync as readFileSync37, writeFileSync as writeFileSync10, cpSync } from "fs";
|
|
20610
20802
|
import { dirname as dirname20, join as join44, basename as basename22 } from "path";
|
|
20611
20803
|
import { homedir as homedir17 } from "os";
|
|
20612
20804
|
function rowFromMemoryItem(type, item) {
|
|
@@ -20640,11 +20832,11 @@ function skillsDirFor(tool) {
|
|
|
20640
20832
|
}
|
|
20641
20833
|
function copySkill(row, toTool) {
|
|
20642
20834
|
const skillDir = row.extra.skillDir || dirname20(row.filePath);
|
|
20643
|
-
if (!
|
|
20835
|
+
if (!existsSync42(skillDir))
|
|
20644
20836
|
return { ok: false, status: 404, error: `Source dir missing: ${skillDir}` };
|
|
20645
20837
|
const name = row.extra.skillName || basename22(skillDir);
|
|
20646
20838
|
const targetDir = join44(skillsDirFor(toTool), name);
|
|
20647
|
-
if (
|
|
20839
|
+
if (existsSync42(targetDir))
|
|
20648
20840
|
return { ok: false, status: 409, error: `Already exists: ${targetDir}` };
|
|
20649
20841
|
try {
|
|
20650
20842
|
mkdirSync11(dirname20(targetDir), { recursive: true });
|
|
@@ -20676,7 +20868,7 @@ function readMcpEntry(tool, name) {
|
|
|
20676
20868
|
return entry;
|
|
20677
20869
|
}
|
|
20678
20870
|
for (const t of tries) {
|
|
20679
|
-
if (!
|
|
20871
|
+
if (!existsSync42(t.path))
|
|
20680
20872
|
continue;
|
|
20681
20873
|
try {
|
|
20682
20874
|
const cfg = JSON.parse(readFileSync37(t.path, "utf-8"));
|
|
@@ -20689,7 +20881,7 @@ function readMcpEntry(tool, name) {
|
|
|
20689
20881
|
return null;
|
|
20690
20882
|
}
|
|
20691
20883
|
function readCodexMcpEntry(path, target) {
|
|
20692
|
-
if (!
|
|
20884
|
+
if (!existsSync42(path))
|
|
20693
20885
|
return null;
|
|
20694
20886
|
let content;
|
|
20695
20887
|
try {
|
|
@@ -20743,7 +20935,7 @@ function readCodexMcpEntry(path, target) {
|
|
|
20743
20935
|
}
|
|
20744
20936
|
function writeCodexMcpEntry(path, name, entry) {
|
|
20745
20937
|
let content = "";
|
|
20746
|
-
if (
|
|
20938
|
+
if (existsSync42(path))
|
|
20747
20939
|
content = readFileSync37(path, "utf-8");
|
|
20748
20940
|
const header = `[mcp_servers.${name}]`;
|
|
20749
20941
|
if (content.includes(header))
|
|
@@ -20801,7 +20993,7 @@ function writeMcpEntry(toTool, name, entry) {
|
|
|
20801
20993
|
key2 = "mcp";
|
|
20802
20994
|
}
|
|
20803
20995
|
let cfg = {};
|
|
20804
|
-
if (
|
|
20996
|
+
if (existsSync42(path)) {
|
|
20805
20997
|
try {
|
|
20806
20998
|
cfg = JSON.parse(readFileSync37(path, "utf-8"));
|
|
20807
20999
|
} catch {
|
|
@@ -20865,7 +21057,7 @@ function copyCommandOrAgent(type, row, toTool) {
|
|
|
20865
21057
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
20866
21058
|
}
|
|
20867
21059
|
const out = emit(type, art, toTool);
|
|
20868
|
-
if (
|
|
21060
|
+
if (existsSync42(out.path))
|
|
20869
21061
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
20870
21062
|
try {
|
|
20871
21063
|
mkdirSync11(dirname20(out.path), { recursive: true });
|
|
@@ -20885,7 +21077,7 @@ function copyInstructions(row, toTool) {
|
|
|
20885
21077
|
return { ok: false, status: 404, error: `Source unreadable: ${e instanceof Error ? e.message : "failed"}` };
|
|
20886
21078
|
}
|
|
20887
21079
|
const out = emit("instructions", art, toTool, row.projectPath || void 0);
|
|
20888
|
-
if (
|
|
21080
|
+
if (existsSync42(out.path))
|
|
20889
21081
|
return { ok: false, status: 409, error: `Already exists: ${out.path}` };
|
|
20890
21082
|
try {
|
|
20891
21083
|
mkdirSync11(dirname20(out.path), { recursive: true });
|
|
@@ -21028,7 +21220,7 @@ var init_toolkit_sync = __esm({
|
|
|
21028
21220
|
});
|
|
21029
21221
|
|
|
21030
21222
|
// ../engine/dist/core/which.js
|
|
21031
|
-
import { existsSync as
|
|
21223
|
+
import { existsSync as existsSync44, statSync as statSync39, accessSync, constants } from "node:fs";
|
|
21032
21224
|
import { join as join46, isAbsolute as isAbsolute2, delimiter as delimiter2, sep as sep3 } from "node:path";
|
|
21033
21225
|
function executable(p) {
|
|
21034
21226
|
try {
|
|
@@ -21069,7 +21261,7 @@ function resolveOnPath(name) {
|
|
|
21069
21261
|
continue;
|
|
21070
21262
|
for (const c of candidates(name)) {
|
|
21071
21263
|
const full = join46(dir, c);
|
|
21072
|
-
if (
|
|
21264
|
+
if (existsSync44(full) && executable(full))
|
|
21073
21265
|
return full;
|
|
21074
21266
|
}
|
|
21075
21267
|
}
|
|
@@ -21094,7 +21286,7 @@ __export(toolkit_pull_exports, {
|
|
|
21094
21286
|
planPull: () => planPull,
|
|
21095
21287
|
portableCommand: () => portableCommand
|
|
21096
21288
|
});
|
|
21097
|
-
import { existsSync as
|
|
21289
|
+
import { existsSync as existsSync45, mkdirSync as mkdirSync13, statSync as statSync40, writeFileSync as writeFileSync12 } from "node:fs";
|
|
21098
21290
|
import { dirname as dirname22, join as join47, basename as basename23, isAbsolute as isAbsolute3 } from "node:path";
|
|
21099
21291
|
function isExecutableFile(p) {
|
|
21100
21292
|
try {
|
|
@@ -21247,7 +21439,7 @@ function executePull(rows, opts = {}) {
|
|
|
21247
21439
|
for (const tool of tools) {
|
|
21248
21440
|
const dir = join47(skillsDirFor(tool), name);
|
|
21249
21441
|
const file = join47(dir, "SKILL.md");
|
|
21250
|
-
if (
|
|
21442
|
+
if (existsSync45(file)) {
|
|
21251
21443
|
outcomes.push({ type: "skill", name, tool, status: "present" });
|
|
21252
21444
|
continue;
|
|
21253
21445
|
}
|
|
@@ -21292,7 +21484,7 @@ function executePull(rows, opts = {}) {
|
|
|
21292
21484
|
outcomes.push({ type, name, tool, status: "failed", reason: e instanceof Error ? e.message : "emit failed" });
|
|
21293
21485
|
continue;
|
|
21294
21486
|
}
|
|
21295
|
-
if (
|
|
21487
|
+
if (existsSync45(out.path)) {
|
|
21296
21488
|
outcomes.push({ type, name, tool, status: "present" });
|
|
21297
21489
|
continue;
|
|
21298
21490
|
}
|
|
@@ -21468,6 +21660,9 @@ async function repairSession(id, opts = {}) {
|
|
|
21468
21660
|
note: "archive count is a lower bound; the rebuild also unions the on-disk tail"
|
|
21469
21661
|
};
|
|
21470
21662
|
}
|
|
21663
|
+
if (!opts.force && endpoints.every((ep) => (currentOnServer.get(ep.url) ?? 0) >= fullest.messages)) {
|
|
21664
|
+
return { sessionId: id, status: "already-full", fullestMessages: fullest.messages, fullestSource: fullest.source, pushed: [] };
|
|
21665
|
+
}
|
|
21471
21666
|
seedShadow(rawId, fullest.container);
|
|
21472
21667
|
const located = backend.findSession(rawId);
|
|
21473
21668
|
const projectPath = located?.projectPath || cwdFromContainer(fullest.container);
|
|
@@ -21510,7 +21705,7 @@ async function repairSession(id, opts = {}) {
|
|
|
21510
21705
|
try {
|
|
21511
21706
|
const res = await fetchWithTimeout(`${ep.url}/api/sync`, { method: "POST", headers, body: JSON.stringify({ conversations: [built.conv] }) }, 6e4);
|
|
21512
21707
|
if (!res.ok) {
|
|
21513
|
-
pushed.push({ server: ep.url, before, after: before });
|
|
21708
|
+
pushed.push({ server: ep.url, before, after: before, error: `HTTP ${res.status}` });
|
|
21514
21709
|
log6(`push to ${ep.url} FAILED: HTTP ${res.status}`);
|
|
21515
21710
|
continue;
|
|
21516
21711
|
}
|
|
@@ -21519,10 +21714,21 @@ async function repairSession(id, opts = {}) {
|
|
|
21519
21714
|
pushed.push({ server: ep.url, before, after: afterN });
|
|
21520
21715
|
log6(`pushed to ${ep.url}: ${before} \u2192 ${afterN} msg(s)`);
|
|
21521
21716
|
} catch (e) {
|
|
21522
|
-
|
|
21523
|
-
|
|
21717
|
+
const error = e instanceof Error ? e.message : String(e);
|
|
21718
|
+
pushed.push({ server: ep.url, before, after: before, error });
|
|
21719
|
+
log6(`push to ${ep.url} errored: ${error}`);
|
|
21524
21720
|
}
|
|
21525
21721
|
}
|
|
21722
|
+
if (pushed.every((p) => p.error)) {
|
|
21723
|
+
return {
|
|
21724
|
+
sessionId: id,
|
|
21725
|
+
status: "error",
|
|
21726
|
+
fullestMessages: builtCount,
|
|
21727
|
+
fullestSource: fullest.source,
|
|
21728
|
+
pushed,
|
|
21729
|
+
note: `every push failed: ${pushed.map((p) => `${p.server}: ${p.error}`).join("; ")}`
|
|
21730
|
+
};
|
|
21731
|
+
}
|
|
21526
21732
|
return { sessionId: id, status: "repaired", fullestMessages: builtCount, fullestSource: fullest.source, pushed };
|
|
21527
21733
|
}
|
|
21528
21734
|
async function repairSessions(ids, opts = {}) {
|
|
@@ -21592,7 +21798,7 @@ __export(shadow_prune_exports, {
|
|
|
21592
21798
|
DEFAULT_MAX_TOTAL_BYTES: () => DEFAULT_MAX_TOTAL_BYTES,
|
|
21593
21799
|
pruneShadow: () => pruneShadow
|
|
21594
21800
|
});
|
|
21595
|
-
import { readdirSync as readdirSync33, statSync as
|
|
21801
|
+
import { readdirSync as readdirSync33, statSync as statSync43, unlinkSync as unlinkSync3 } from "fs";
|
|
21596
21802
|
import { join as join50 } from "path";
|
|
21597
21803
|
function listShadows(isFullyAcked) {
|
|
21598
21804
|
const out = [];
|
|
@@ -21617,7 +21823,7 @@ function listShadows(isFullyAcked) {
|
|
|
21617
21823
|
const path = join50(dir, name);
|
|
21618
21824
|
let st;
|
|
21619
21825
|
try {
|
|
21620
|
-
st =
|
|
21826
|
+
st = statSync43(path);
|
|
21621
21827
|
} catch {
|
|
21622
21828
|
continue;
|
|
21623
21829
|
}
|
|
@@ -21689,9 +21895,9 @@ var init_shadow_prune = __esm({
|
|
|
21689
21895
|
});
|
|
21690
21896
|
|
|
21691
21897
|
// ../engine/dist/types/code-intel.js
|
|
21692
|
-
import { createHash as
|
|
21898
|
+
import { createHash as createHash12 } from "crypto";
|
|
21693
21899
|
function shortHash(s) {
|
|
21694
|
-
return
|
|
21900
|
+
return createHash12("sha256").update(s).digest("hex").slice(0, 16);
|
|
21695
21901
|
}
|
|
21696
21902
|
function snippetKey(snippet) {
|
|
21697
21903
|
return (snippet ?? "").replace(/\s+/g, " ").trim().slice(0, 200);
|
|
@@ -21732,11 +21938,11 @@ var init_code_intel = __esm({
|
|
|
21732
21938
|
});
|
|
21733
21939
|
|
|
21734
21940
|
// ../engine/dist/core/companions.js
|
|
21735
|
-
import { existsSync as
|
|
21941
|
+
import { existsSync as existsSync48, mkdirSync as mkdirSync16, statSync as statSync44, chmodSync as chmodSync4, unlinkSync as unlinkSync4, renameSync as renameSync5, createWriteStream, readFileSync as readFileSync42, writeFileSync as writeFileSync15 } from "node:fs";
|
|
21736
21942
|
import { homedir as homedir19 } from "node:os";
|
|
21737
21943
|
import { join as join51 } from "node:path";
|
|
21738
21944
|
import { execSync as execSync3 } from "node:child_process";
|
|
21739
|
-
import { createHash as
|
|
21945
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
21740
21946
|
function expectedCodeindexSha256(artifact) {
|
|
21741
21947
|
return CODEINDEX_SHA256[artifact.replace(/^codeindex-/, "").replace(/\.exe$/, "")] ?? null;
|
|
21742
21948
|
}
|
|
@@ -21783,7 +21989,7 @@ function checkCodeindexStatus() {
|
|
|
21783
21989
|
status.installed = true;
|
|
21784
21990
|
status.path = foundPath;
|
|
21785
21991
|
try {
|
|
21786
|
-
status.size =
|
|
21992
|
+
status.size = statSync44(foundPath).size;
|
|
21787
21993
|
} catch {
|
|
21788
21994
|
}
|
|
21789
21995
|
try {
|
|
@@ -21844,7 +22050,7 @@ async function installCodeindex(opts = {}) {
|
|
|
21844
22050
|
if (!expected) {
|
|
21845
22051
|
throw new Error(`No pinned checksum for ${status.artifactName} \u2014 refusing to install an unverified binary. Add its sha256 to CODEINDEX_SHA256 in companions.ts.`);
|
|
21846
22052
|
}
|
|
21847
|
-
const actual =
|
|
22053
|
+
const actual = createHash13("sha256").update(readFileSync42(tmpPath)).digest("hex");
|
|
21848
22054
|
if (actual !== expected) {
|
|
21849
22055
|
throw new Error(`Checksum mismatch for ${status.artifactName}.
|
|
21850
22056
|
expected ${expected}
|
|
@@ -21855,7 +22061,7 @@ Refusing to install. The release may have been re-uploaded, or something is serv
|
|
|
21855
22061
|
renameSync5(tmpPath, CODEINDEX_BIN_PATH);
|
|
21856
22062
|
} catch (err) {
|
|
21857
22063
|
try {
|
|
21858
|
-
if (
|
|
22064
|
+
if (existsSync48(tmpPath))
|
|
21859
22065
|
unlinkSync4(tmpPath);
|
|
21860
22066
|
} catch {
|
|
21861
22067
|
}
|
|
@@ -22008,7 +22214,10 @@ async function resolveCodeindexBin(autoInstall = true) {
|
|
|
22008
22214
|
}
|
|
22009
22215
|
function runMcp(binPath, workspace, calls, timeoutMs = 18e4) {
|
|
22010
22216
|
return new Promise((resolve3, reject) => {
|
|
22011
|
-
const p = spawn2(binPath, ["--mcp", "--workspace", workspace], {
|
|
22217
|
+
const p = spawn2(binPath, ["--mcp", "--workspace", workspace], {
|
|
22218
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
22219
|
+
env: { ...process.env, CODEINDEX_NO_DAEMON: "1" }
|
|
22220
|
+
});
|
|
22012
22221
|
const res = /* @__PURE__ */ new Map();
|
|
22013
22222
|
let pending = "";
|
|
22014
22223
|
let failed = false;
|
|
@@ -22939,7 +23148,7 @@ __export(service_installer_exports, {
|
|
|
22939
23148
|
uninstallService: () => uninstallService
|
|
22940
23149
|
});
|
|
22941
23150
|
import { execSync as execSync5 } from "child_process";
|
|
22942
|
-
import { existsSync as
|
|
23151
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync17, readFileSync as readFileSync44, rmSync as rmSync7, writeFileSync as writeFileSync16 } from "fs";
|
|
22943
23152
|
import { homedir as homedir20 } from "os";
|
|
22944
23153
|
import { join as join53 } from "path";
|
|
22945
23154
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
@@ -22966,7 +23175,7 @@ function isServiceRunning() {
|
|
|
22966
23175
|
return /com\.chat-recall\.watch/.test(tryCmd("launchctl list 2>/dev/null"));
|
|
22967
23176
|
}
|
|
22968
23177
|
if (process.platform === "linux") {
|
|
22969
|
-
return
|
|
23178
|
+
return /^active$/m.test(tryCmd("systemctl --user is-active chat-recall-watch.service 2>/dev/null"));
|
|
22970
23179
|
}
|
|
22971
23180
|
return false;
|
|
22972
23181
|
}
|
|
@@ -22975,7 +23184,7 @@ function refreshServiceDefinition() {
|
|
|
22975
23184
|
try {
|
|
22976
23185
|
const { watchJs, node, logFile } = resolveDaemonPaths();
|
|
22977
23186
|
const unitPath = join53(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
22978
|
-
if (!
|
|
23187
|
+
if (!existsSync49(unitPath)) return false;
|
|
22979
23188
|
const current = readFileSync44(unitPath, "utf8");
|
|
22980
23189
|
if (!current.includes(watchJs)) return false;
|
|
22981
23190
|
const wanted = renderSystemdUnit(watchJs, node, logFile);
|
|
@@ -23042,7 +23251,12 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
23042
23251
|
// sawtooth. 1536MB keeps GC honest (768 OOMed on the largest subagent-fanout session) with plenty of headroom for the
|
|
23043
23252
|
// largest transcripts.
|
|
23044
23253
|
`ExecStart=${node} --max-old-space-size=1536 ${watchJs}`,
|
|
23045
|
-
|
|
23254
|
+
// ALWAYS: the collector never ends its own work, so any exit systemd did
|
|
23255
|
+
// not ask for is a fault. Under on-failure a clean exit left it dead: on
|
|
23256
|
+
// 2026-09-16 the unit went "inactive (dead) … status=0/SUCCESS" and stayed
|
|
23257
|
+
// down for 8 days, so nothing synced and the auto-update tick, which runs
|
|
23258
|
+
// inside the daemon, never ran. `systemctl stop` still stops it.
|
|
23259
|
+
"Restart=always",
|
|
23046
23260
|
"RestartSec=10",
|
|
23047
23261
|
"Nice=10",
|
|
23048
23262
|
// NEVER STOP RETRYING. systemd's default start limiter gives up after a
|
|
@@ -23138,7 +23352,7 @@ function uninstallService() {
|
|
|
23138
23352
|
} catch {
|
|
23139
23353
|
}
|
|
23140
23354
|
const unitPath = join53(homedir20(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
23141
|
-
if (
|
|
23355
|
+
if (existsSync49(unitPath)) {
|
|
23142
23356
|
rmSync7(unitPath, { force: true });
|
|
23143
23357
|
removed = true;
|
|
23144
23358
|
}
|
|
@@ -23155,7 +23369,7 @@ function uninstallService() {
|
|
|
23155
23369
|
} catch {
|
|
23156
23370
|
}
|
|
23157
23371
|
let removed = false;
|
|
23158
|
-
if (
|
|
23372
|
+
if (existsSync49(plistPath)) {
|
|
23159
23373
|
rmSync7(plistPath, { force: true });
|
|
23160
23374
|
removed = true;
|
|
23161
23375
|
}
|
|
@@ -23212,12 +23426,12 @@ init_codex2();
|
|
|
23212
23426
|
init_cursor();
|
|
23213
23427
|
init_opencode();
|
|
23214
23428
|
init_agy();
|
|
23215
|
-
import { existsSync as
|
|
23429
|
+
import { existsSync as existsSync46, readFileSync as readFileSync39, writeFileSync as writeFileSync13, appendFileSync, mkdirSync as mkdirSync14 } from "node:fs";
|
|
23216
23430
|
import { join as join48 } from "node:path";
|
|
23217
23431
|
|
|
23218
23432
|
// src/project-tasks.ts
|
|
23219
23433
|
init_http();
|
|
23220
|
-
import { existsSync as
|
|
23434
|
+
import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, statSync as statSync38 } from "node:fs";
|
|
23221
23435
|
import { join as join45, dirname as dirname21 } from "node:path";
|
|
23222
23436
|
import { homedir as homedir18 } from "node:os";
|
|
23223
23437
|
|
|
@@ -23325,7 +23539,7 @@ async function pushProjectTaskStatuses(base2, authHeaders, opts = {}) {
|
|
|
23325
23539
|
}
|
|
23326
23540
|
for (const project of projects) {
|
|
23327
23541
|
const file = join45(project, fk.filename);
|
|
23328
|
-
if (!
|
|
23542
|
+
if (!existsSync43(file)) continue;
|
|
23329
23543
|
let mtime;
|
|
23330
23544
|
try {
|
|
23331
23545
|
mtime = statSync38(file).mtimeMs;
|
|
@@ -23386,7 +23600,7 @@ function instructionTargets(rootPath, isGlobal) {
|
|
|
23386
23600
|
const tools = installed.length ? installed : [INSTRUCTION_TOOLS[0]];
|
|
23387
23601
|
if (isGlobal) return [...new Set(tools.map((t) => instructionsPath(t.id)))];
|
|
23388
23602
|
if (!rootPath) return [];
|
|
23389
|
-
const present = INSTRUCTION_FILENAMES.map((f) => join48(rootPath, f)).filter((p) =>
|
|
23603
|
+
const present = INSTRUCTION_FILENAMES.map((f) => join48(rootPath, f)).filter((p) => existsSync46(p));
|
|
23390
23604
|
if (present.length) return present;
|
|
23391
23605
|
return [...new Set(tools.map((t) => join48(rootPath, instructionsFilename(t.id))))];
|
|
23392
23606
|
}
|
|
@@ -23414,7 +23628,7 @@ function applyCodeRecommendation(intent) {
|
|
|
23414
23628
|
mkdirSync14(dir, { recursive: true });
|
|
23415
23629
|
} catch {
|
|
23416
23630
|
}
|
|
23417
|
-
const existing =
|
|
23631
|
+
const existing = existsSync46(file) ? readFileSync39(file, "utf8") : "";
|
|
23418
23632
|
if (existing.includes(text)) {
|
|
23419
23633
|
skipped.push(file);
|
|
23420
23634
|
continue;
|
|
@@ -23516,7 +23730,7 @@ try {
|
|
|
23516
23730
|
ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
23517
23731
|
} catch {
|
|
23518
23732
|
try {
|
|
23519
|
-
if (true) ownVersion2 = "0.7.
|
|
23733
|
+
if (true) ownVersion2 = "0.7.2";
|
|
23520
23734
|
} catch {
|
|
23521
23735
|
}
|
|
23522
23736
|
}
|
|
@@ -23581,7 +23795,9 @@ init_auto_update();
|
|
|
23581
23795
|
|
|
23582
23796
|
// src/code-index-cursor.ts
|
|
23583
23797
|
init_paths();
|
|
23584
|
-
import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15 } from "fs";
|
|
23798
|
+
import { readFileSync as readFileSync40, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, statSync as statSync41 } from "fs";
|
|
23799
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
23800
|
+
import { createHash as createHash10 } from "crypto";
|
|
23585
23801
|
import { join as join49, dirname as dirname24 } from "path";
|
|
23586
23802
|
var cursorPath = () => join49(getDataDir(), "code-index-cursor.json");
|
|
23587
23803
|
function readCursor() {
|
|
@@ -23590,7 +23806,11 @@ function readCursor() {
|
|
|
23590
23806
|
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
23591
23807
|
const out = {};
|
|
23592
23808
|
for (const [k, v] of Object.entries(raw)) {
|
|
23593
|
-
if (typeof v === "number" && Number.isFinite(v)) out[k] = v;
|
|
23809
|
+
if (typeof v === "number" && Number.isFinite(v)) out[k] = { at: v };
|
|
23810
|
+
else if (v && typeof v === "object" && typeof v.at === "number" && Number.isFinite(v.at)) {
|
|
23811
|
+
const fp = v.fp;
|
|
23812
|
+
out[k] = typeof fp === "string" ? { at: v.at, fp } : { at: v.at };
|
|
23813
|
+
}
|
|
23594
23814
|
}
|
|
23595
23815
|
return out;
|
|
23596
23816
|
}
|
|
@@ -23606,13 +23826,44 @@ function writeCursor(c) {
|
|
|
23606
23826
|
} catch {
|
|
23607
23827
|
}
|
|
23608
23828
|
}
|
|
23609
|
-
function noteIndexed(workspace, now = Date.now()) {
|
|
23829
|
+
function noteIndexed(workspace, now = Date.now(), fp) {
|
|
23610
23830
|
const c = readCursor();
|
|
23611
|
-
c[workspace] = now;
|
|
23831
|
+
c[workspace] = fp ? { at: now, fp } : { at: now };
|
|
23612
23832
|
writeCursor(c);
|
|
23613
23833
|
}
|
|
23834
|
+
function workspaceFingerprint(workspace, collectorVersion) {
|
|
23835
|
+
try {
|
|
23836
|
+
const git2 = (args) => execFileSync4(
|
|
23837
|
+
"git",
|
|
23838
|
+
["-C", workspace, ...args],
|
|
23839
|
+
{ encoding: "utf-8", timeout: 1e4, maxBuffer: 16 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] }
|
|
23840
|
+
);
|
|
23841
|
+
const head = git2(["rev-parse", "HEAD"]).trim();
|
|
23842
|
+
const status = git2(["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
|
|
23843
|
+
const h = createHash10("sha256").update(`v${collectorVersion}\0${head}\0`);
|
|
23844
|
+
for (const entry of status.split("\0")) {
|
|
23845
|
+
if (entry.length < 4) continue;
|
|
23846
|
+
const rel = entry.slice(3);
|
|
23847
|
+
let stamp2 = "gone";
|
|
23848
|
+
try {
|
|
23849
|
+
const s = statSync41(join49(workspace, rel));
|
|
23850
|
+
stamp2 = `${s.size}:${Math.floor(s.mtimeMs)}`;
|
|
23851
|
+
} catch {
|
|
23852
|
+
}
|
|
23853
|
+
h.update(`${entry.slice(0, 2)}\0${rel}\0${stamp2}\0`);
|
|
23854
|
+
}
|
|
23855
|
+
return h.digest("hex");
|
|
23856
|
+
} catch {
|
|
23857
|
+
return null;
|
|
23858
|
+
}
|
|
23859
|
+
}
|
|
23860
|
+
var UNCHANGED_RESEND_MS = 7 * 24 * 3600 * 1e3;
|
|
23861
|
+
function isUnchangedSinceIndexed(workspace, fp, cursor, now = Date.now()) {
|
|
23862
|
+
const e = cursor[workspace];
|
|
23863
|
+
return !!fp && !!e && e.fp === fp && now - e.at < UNCHANGED_RESEND_MS;
|
|
23864
|
+
}
|
|
23614
23865
|
function orderByStaleness(workspaces, cursor = readCursor()) {
|
|
23615
|
-
return workspaces.map((w, i) => ({ w, i, at: cursor[w] ?? -1 })).sort((a, b) => a.at - b.at || a.i - b.i).map((e) => e.w);
|
|
23866
|
+
return workspaces.map((w, i) => ({ w, i, at: cursor[w]?.at ?? -1 })).sort((a, b) => a.at - b.at || a.i - b.i).map((e) => e.w);
|
|
23616
23867
|
}
|
|
23617
23868
|
function pruneCursor(known) {
|
|
23618
23869
|
const keep = new Set(known);
|
|
@@ -23732,7 +23983,7 @@ init_telemetry();
|
|
|
23732
23983
|
// src/self-restart.ts
|
|
23733
23984
|
import { spawn } from "child_process";
|
|
23734
23985
|
import { readFileSync as readFileSync41 } from "fs";
|
|
23735
|
-
import { createHash as
|
|
23986
|
+
import { createHash as createHash11 } from "crypto";
|
|
23736
23987
|
var EXIT_CODE_CODE_CHANGED = 75;
|
|
23737
23988
|
function codeFingerprint(entry = process.argv[1]) {
|
|
23738
23989
|
if (!entry) return null;
|
|
@@ -23741,7 +23992,7 @@ function codeFingerprint(entry = process.argv[1]) {
|
|
|
23741
23992
|
return {
|
|
23742
23993
|
path: entry,
|
|
23743
23994
|
size: buf.byteLength,
|
|
23744
|
-
hash:
|
|
23995
|
+
hash: createHash11("sha256").update(buf).digest("hex")
|
|
23745
23996
|
};
|
|
23746
23997
|
} catch {
|
|
23747
23998
|
return null;
|
|
@@ -23804,11 +24055,11 @@ function checkSelfRestart(opts) {
|
|
|
23804
24055
|
}
|
|
23805
24056
|
|
|
23806
24057
|
// src/log-rotate.ts
|
|
23807
|
-
import { statSync as
|
|
24058
|
+
import { statSync as statSync42, copyFileSync as copyFileSync3, truncateSync } from "fs";
|
|
23808
24059
|
var LOG_MAX_BYTES = 32 * 1024 * 1024;
|
|
23809
24060
|
function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
|
|
23810
24061
|
try {
|
|
23811
|
-
const size =
|
|
24062
|
+
const size = statSync42(logPath).size;
|
|
23812
24063
|
if (size < maxBytes) return { rotated: false, sizeBefore: 0 };
|
|
23813
24064
|
copyFileSync3(logPath, `${logPath}.1`);
|
|
23814
24065
|
truncateSync(logPath, 0);
|
|
@@ -23820,8 +24071,8 @@ function rotateLogIfLarge(logPath, maxBytes = LOG_MAX_BYTES) {
|
|
|
23820
24071
|
|
|
23821
24072
|
// src/collector-migrate.ts
|
|
23822
24073
|
init_http();
|
|
23823
|
-
import { existsSync as
|
|
23824
|
-
function selectProjectsToReindex(projects, current, existsFn =
|
|
24074
|
+
import { existsSync as existsSync47 } from "node:fs";
|
|
24075
|
+
function selectProjectsToReindex(projects, current, existsFn = existsSync47) {
|
|
23825
24076
|
const reindex = [];
|
|
23826
24077
|
const missing = [];
|
|
23827
24078
|
for (const p of projects) {
|
|
@@ -23863,8 +24114,8 @@ async function runCollectorMigration(opts) {
|
|
|
23863
24114
|
// auto-indexer/indexer.ts
|
|
23864
24115
|
init_sync_ledger();
|
|
23865
24116
|
init_collector_health();
|
|
23866
|
-
import { existsSync as
|
|
23867
|
-
var CLI_VERSION3 = true ? "0.7.
|
|
24117
|
+
import { existsSync as existsSync50, readFileSync as readFileSync45, statSync as statSync45 } from "fs";
|
|
24118
|
+
var CLI_VERSION3 = true ? "0.7.2" : "0.0.0";
|
|
23868
24119
|
var DEBOUNCE_MS = 5e3;
|
|
23869
24120
|
var CLAUDE_DIR = claudeBackend.projectsDir();
|
|
23870
24121
|
var PLANS_DIR = claudeBackend.plansDir();
|
|
@@ -23969,7 +24220,7 @@ var WATCH_WINDOW_MS = Math.max(1, Number(process.env.CHAT_RECALL_WATCH_WINDOW_DA
|
|
|
23969
24220
|
var sessionWatcher = watchWithFallback("sessions", `${CLAUDE_DIR}/**/*.jsonl`, {
|
|
23970
24221
|
ignored: (p, stats) => {
|
|
23971
24222
|
if (/agent-/.test(p) || /^\./.test(basename25(p))) return true;
|
|
23972
|
-
const st = stats ??
|
|
24223
|
+
const st = stats ?? statSync45(p, { throwIfNoEntry: false });
|
|
23973
24224
|
if (!st || st.isDirectory()) return false;
|
|
23974
24225
|
return st.mtimeMs < Date.now() - WATCH_WINDOW_MS;
|
|
23975
24226
|
},
|
|
@@ -24249,7 +24500,7 @@ function discoverWorkspaces() {
|
|
|
24249
24500
|
for (const b of listAvailableBackends()) {
|
|
24250
24501
|
let refs = [];
|
|
24251
24502
|
try {
|
|
24252
|
-
refs = b.listSessions({ sinceMs });
|
|
24503
|
+
refs = b.listSessions({ sinceMs, previews: false });
|
|
24253
24504
|
} catch {
|
|
24254
24505
|
}
|
|
24255
24506
|
for (const r of refs) {
|
|
@@ -24269,7 +24520,7 @@ function discoverWorkspaces() {
|
|
|
24269
24520
|
const isExcluded = (p) => excluded.some((x) => p.includes(x));
|
|
24270
24521
|
const candidates2 = [...newest.entries()].filter(([p]) => !isExcluded(p)).filter(([p]) => !isPersonalPath(p, includeProjects)).filter(([p]) => {
|
|
24271
24522
|
try {
|
|
24272
|
-
return
|
|
24523
|
+
return existsSync50(p);
|
|
24273
24524
|
} catch {
|
|
24274
24525
|
return false;
|
|
24275
24526
|
}
|
|
@@ -24301,7 +24552,7 @@ function isCodeWorkspace(p) {
|
|
|
24301
24552
|
}
|
|
24302
24553
|
return WORKSPACE_MARKERS.some((m) => {
|
|
24303
24554
|
try {
|
|
24304
|
-
return
|
|
24555
|
+
return existsSync50(join54(p, m));
|
|
24305
24556
|
} catch {
|
|
24306
24557
|
return false;
|
|
24307
24558
|
}
|
|
@@ -24317,7 +24568,7 @@ async function codeIndexTick() {
|
|
|
24317
24568
|
if (discovered.length === 0) return;
|
|
24318
24569
|
pruneCursor(discovered);
|
|
24319
24570
|
const workspaces = orderByStaleness(discovered);
|
|
24320
|
-
const { collectCode: collectCode2, resolveCodeindexBin: resolveCodeindexBin2 } = await Promise.resolve().then(() => (init_collector(), collector_exports));
|
|
24571
|
+
const { collectCode: collectCode2, resolveCodeindexBin: resolveCodeindexBin2, COLLECTOR_VERSION: COLLECTOR_VERSION2 } = await Promise.resolve().then(() => (init_collector(), collector_exports));
|
|
24321
24572
|
let bin;
|
|
24322
24573
|
try {
|
|
24323
24574
|
bin = await resolveCodeindexBin2(true);
|
|
@@ -24325,8 +24576,14 @@ async function codeIndexTick() {
|
|
|
24325
24576
|
daemonLog.error(`code intelligence skipped \u2014 codeindex unavailable: ${e instanceof Error ? e.message : e}`);
|
|
24326
24577
|
return;
|
|
24327
24578
|
}
|
|
24328
|
-
let ok = 0;
|
|
24579
|
+
let ok = 0, unchanged = 0;
|
|
24580
|
+
const cursor = readCursor();
|
|
24329
24581
|
for (const ws of workspaces) {
|
|
24582
|
+
const fp = workspaceFingerprint(ws, COLLECTOR_VERSION2);
|
|
24583
|
+
if (isUnchangedSinceIndexed(ws, fp, cursor)) {
|
|
24584
|
+
unchanged++;
|
|
24585
|
+
continue;
|
|
24586
|
+
}
|
|
24330
24587
|
const t0 = Date.now();
|
|
24331
24588
|
daemonLog.info(`code intelligence: indexing ${ws} \u2026`);
|
|
24332
24589
|
let result;
|
|
@@ -24344,10 +24601,10 @@ async function codeIndexTick() {
|
|
|
24344
24601
|
} catch {
|
|
24345
24602
|
}
|
|
24346
24603
|
}
|
|
24347
|
-
noteIndexed(ws);
|
|
24604
|
+
noteIndexed(ws, Date.now(), fp);
|
|
24348
24605
|
ok++;
|
|
24349
24606
|
}
|
|
24350
|
-
if (ok > 0) daemonLog.info(`code intelligence: indexed ${ok}/${workspaces.length} workspace(s)`);
|
|
24607
|
+
if (ok > 0 || unchanged > 0) daemonLog.info(`code intelligence: indexed ${ok}/${workspaces.length} workspace(s), ${unchanged} unchanged`);
|
|
24351
24608
|
} finally {
|
|
24352
24609
|
codeIndexInFlight = false;
|
|
24353
24610
|
}
|