chat-recall 0.7.0 → 0.7.1
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 +370 -183
- package/dist/cli.js.map +1 -1
- package/dist/mcp-relay.js +76 -13
- package/dist/mcp-relay.js.map +1 -1
- package/dist/mcp.js +620 -345
- 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 +44 -13
- 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 +191 -58
- 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 +310 -127
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -7156,7 +7156,7 @@ var init_raw = __esm({
|
|
|
7156
7156
|
// ../engine/dist/transcript/shadow.js
|
|
7157
7157
|
import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
|
|
7158
7158
|
import { createHash as createHash4 } from "crypto";
|
|
7159
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync7 } from "fs";
|
|
7159
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync7, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
|
|
7160
7160
|
import { dirname as dirname9, join as join11 } from "path";
|
|
7161
7161
|
function shadowRoot() {
|
|
7162
7162
|
return join11(getDataDir(), "shadow");
|
|
@@ -7332,6 +7332,29 @@ function updateShadow(sessionId, exp, prebuilt) {
|
|
|
7332
7332
|
path: path2
|
|
7333
7333
|
};
|
|
7334
7334
|
}
|
|
7335
|
+
function shadowUncompressedBytes(tool, rawId) {
|
|
7336
|
+
const path2 = shadowFileFor(tool, rawId);
|
|
7337
|
+
let fd = null;
|
|
7338
|
+
try {
|
|
7339
|
+
const size = statSync7(path2).size;
|
|
7340
|
+
if (size < 18)
|
|
7341
|
+
return 0;
|
|
7342
|
+
fd = openSync2(path2, "r");
|
|
7343
|
+
const tail = Buffer.alloc(4);
|
|
7344
|
+
if (readSync2(fd, tail, 0, 4, size - 4) !== 4)
|
|
7345
|
+
return 0;
|
|
7346
|
+
return tail.readUInt32LE(0);
|
|
7347
|
+
} catch {
|
|
7348
|
+
return 0;
|
|
7349
|
+
} finally {
|
|
7350
|
+
if (fd !== null) {
|
|
7351
|
+
try {
|
|
7352
|
+
closeSync2(fd);
|
|
7353
|
+
} catch {
|
|
7354
|
+
}
|
|
7355
|
+
}
|
|
7356
|
+
}
|
|
7357
|
+
}
|
|
7335
7358
|
var WHOLE_FILE_TOOLS, SINGLETON_META;
|
|
7336
7359
|
var init_shadow = __esm({
|
|
7337
7360
|
"../engine/dist/transcript/shadow.js"() {
|
|
@@ -7344,7 +7367,7 @@ var init_shadow = __esm({
|
|
|
7344
7367
|
});
|
|
7345
7368
|
|
|
7346
7369
|
// ../engine/dist/core/live-session-scan.js
|
|
7347
|
-
import { existsSync as existsSync8, readdirSync as readdirSync8, readFileSync as readFileSync6, statSync as statSync8, openSync as
|
|
7370
|
+
import { existsSync as existsSync8, readdirSync as readdirSync8, readFileSync as readFileSync6, statSync as statSync8, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
|
|
7348
7371
|
import { join as join12, basename as basename7 } from "path";
|
|
7349
7372
|
function detectTool(sessionId) {
|
|
7350
7373
|
return getBackendForId(sessionId)?.id ?? "claude";
|
|
@@ -7371,6 +7394,15 @@ function sessionFileIndex() {
|
|
|
7371
7394
|
return indexCache;
|
|
7372
7395
|
const byId = /* @__PURE__ */ new Map();
|
|
7373
7396
|
const seenRoots = /* @__PURE__ */ new Set();
|
|
7397
|
+
const projectPaths = /* @__PURE__ */ new Map();
|
|
7398
|
+
const projectPathOf = (dirName) => {
|
|
7399
|
+
let p = projectPaths.get(dirName);
|
|
7400
|
+
if (p === void 0) {
|
|
7401
|
+
p = resolveProjectDirName(dirName);
|
|
7402
|
+
projectPaths.set(dirName, p);
|
|
7403
|
+
}
|
|
7404
|
+
return p;
|
|
7405
|
+
};
|
|
7374
7406
|
for (const root of claudeProjectDirs()) {
|
|
7375
7407
|
if (seenRoots.has(root) || !existsSync8(root))
|
|
7376
7408
|
continue;
|
|
@@ -7398,7 +7430,7 @@ function sessionFileIndex() {
|
|
|
7398
7430
|
const located = {
|
|
7399
7431
|
path: join12(dir, name),
|
|
7400
7432
|
projectDir: entry.name,
|
|
7401
|
-
projectPath:
|
|
7433
|
+
projectPath: projectPathOf(entry.name)
|
|
7402
7434
|
};
|
|
7403
7435
|
const prior = byId.get(id);
|
|
7404
7436
|
if (prior)
|
|
@@ -8080,7 +8112,7 @@ var init_flat_string = __esm({
|
|
|
8080
8112
|
});
|
|
8081
8113
|
|
|
8082
8114
|
// ../engine/dist/core/first-prompt.js
|
|
8083
|
-
import { createReadStream as createReadStream2, existsSync as existsSync10, openSync as
|
|
8115
|
+
import { createReadStream as createReadStream2, existsSync as existsSync10, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
|
|
8084
8116
|
import { StringDecoder } from "string_decoder";
|
|
8085
8117
|
function stripBanners2(s) {
|
|
8086
8118
|
let out = s;
|
|
@@ -8134,7 +8166,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
|
|
|
8134
8166
|
const maxBytes = options.maxBytes ?? 4 * 1024 * 1024;
|
|
8135
8167
|
let fd;
|
|
8136
8168
|
try {
|
|
8137
|
-
fd =
|
|
8169
|
+
fd = openSync4(filePath, "r");
|
|
8138
8170
|
} catch {
|
|
8139
8171
|
return "";
|
|
8140
8172
|
}
|
|
@@ -8146,7 +8178,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
|
|
|
8146
8178
|
let pos = 0;
|
|
8147
8179
|
let lineNo = 0;
|
|
8148
8180
|
for (; ; ) {
|
|
8149
|
-
const n =
|
|
8181
|
+
const n = readSync4(fd, buf, 0, CHUNK, pos);
|
|
8150
8182
|
if (n <= 0)
|
|
8151
8183
|
break;
|
|
8152
8184
|
pos += n;
|
|
@@ -8172,7 +8204,7 @@ function extractFirstUserPromptSync(filePath, options = {}) {
|
|
|
8172
8204
|
return "";
|
|
8173
8205
|
} finally {
|
|
8174
8206
|
try {
|
|
8175
|
-
|
|
8207
|
+
closeSync4(fd);
|
|
8176
8208
|
} catch {
|
|
8177
8209
|
}
|
|
8178
8210
|
}
|
|
@@ -8191,8 +8223,8 @@ var init_first_prompt = __esm({
|
|
|
8191
8223
|
});
|
|
8192
8224
|
|
|
8193
8225
|
// ../engine/dist/core/backends/tail-read.js
|
|
8194
|
-
import { openSync as
|
|
8195
|
-
function readTailFromOffset(path2, offset) {
|
|
8226
|
+
import { openSync as openSync5, readSync as readSync5, closeSync as closeSync5, statSync as statSync9 } from "node:fs";
|
|
8227
|
+
function readTailFromOffset(path2, offset, maxBytes = TAIL_READ_MAX_BYTES) {
|
|
8196
8228
|
let size = 0;
|
|
8197
8229
|
try {
|
|
8198
8230
|
size = statSync9(path2).size;
|
|
@@ -8201,14 +8233,14 @@ function readTailFromOffset(path2, offset) {
|
|
|
8201
8233
|
}
|
|
8202
8234
|
if (size <= offset)
|
|
8203
8235
|
return { text: "", newOffset: offset };
|
|
8204
|
-
const len = Math.min(size - offset,
|
|
8236
|
+
const len = Math.min(size - offset, Math.max(1, maxBytes));
|
|
8205
8237
|
const buf = Buffer.allocUnsafe(len);
|
|
8206
8238
|
let fd = null;
|
|
8207
8239
|
try {
|
|
8208
|
-
fd =
|
|
8240
|
+
fd = openSync5(path2, "r");
|
|
8209
8241
|
let got = 0;
|
|
8210
8242
|
while (got < len) {
|
|
8211
|
-
const n =
|
|
8243
|
+
const n = readSync5(fd, buf, got, len - got, offset + got);
|
|
8212
8244
|
if (n <= 0)
|
|
8213
8245
|
break;
|
|
8214
8246
|
got += n;
|
|
@@ -8217,25 +8249,47 @@ function readTailFromOffset(path2, offset) {
|
|
|
8217
8249
|
return { text: "", newOffset: offset };
|
|
8218
8250
|
const slice = got < len ? buf.subarray(0, got) : buf;
|
|
8219
8251
|
const lastNl = slice.lastIndexOf(10);
|
|
8220
|
-
if (lastNl
|
|
8221
|
-
|
|
8252
|
+
if (lastNl >= 0) {
|
|
8253
|
+
const text = slice.subarray(0, lastNl + 1).toString("utf-8");
|
|
8254
|
+
return { text, newOffset: offset + lastNl + 1 };
|
|
8222
8255
|
}
|
|
8223
|
-
|
|
8224
|
-
|
|
8256
|
+
if (offset + got >= size)
|
|
8257
|
+
return { text: "", newOffset: offset };
|
|
8258
|
+
const end = findNewline(fd, offset + got, size);
|
|
8259
|
+
if (end < 0)
|
|
8260
|
+
return { text: "", newOffset: offset };
|
|
8261
|
+
return { text: "", newOffset: end + 1, skippedBytes: end + 1 - offset };
|
|
8225
8262
|
} catch {
|
|
8226
8263
|
return { text: "", newOffset: offset };
|
|
8227
8264
|
} finally {
|
|
8228
8265
|
if (fd !== null) {
|
|
8229
8266
|
try {
|
|
8230
|
-
|
|
8267
|
+
closeSync5(fd);
|
|
8231
8268
|
} catch {
|
|
8232
8269
|
}
|
|
8233
8270
|
}
|
|
8234
8271
|
}
|
|
8235
8272
|
}
|
|
8273
|
+
function findNewline(fd, from, size) {
|
|
8274
|
+
const block = Buffer.allocUnsafe(SKIP_SCAN_BYTES);
|
|
8275
|
+
let pos = from;
|
|
8276
|
+
while (pos < size) {
|
|
8277
|
+
const n = readSync5(fd, block, 0, Math.min(SKIP_SCAN_BYTES, size - pos), pos);
|
|
8278
|
+
if (n <= 0)
|
|
8279
|
+
return -1;
|
|
8280
|
+
const i = block.subarray(0, n).indexOf(10);
|
|
8281
|
+
if (i >= 0)
|
|
8282
|
+
return pos + i;
|
|
8283
|
+
pos += n;
|
|
8284
|
+
}
|
|
8285
|
+
return -1;
|
|
8286
|
+
}
|
|
8287
|
+
var TAIL_READ_MAX_BYTES, SKIP_SCAN_BYTES;
|
|
8236
8288
|
var init_tail_read = __esm({
|
|
8237
8289
|
"../engine/dist/core/backends/tail-read.js"() {
|
|
8238
8290
|
"use strict";
|
|
8291
|
+
TAIL_READ_MAX_BYTES = 16 * 1024 * 1024;
|
|
8292
|
+
SKIP_SCAN_BYTES = 1024 * 1024;
|
|
8239
8293
|
}
|
|
8240
8294
|
});
|
|
8241
8295
|
|
|
@@ -8512,7 +8566,7 @@ var init_generic_engine = __esm({
|
|
|
8512
8566
|
});
|
|
8513
8567
|
|
|
8514
8568
|
// ../engine/dist/core/backends/claude.js
|
|
8515
|
-
import { existsSync as existsSync11, readdirSync as readdirSync9, readFileSync as readFileSync7, statSync as statSync10, openSync as
|
|
8569
|
+
import { existsSync as existsSync11, readdirSync as readdirSync9, readFileSync as readFileSync7, statSync as statSync10, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
8516
8570
|
import { join as join13, basename as basename10 } from "path";
|
|
8517
8571
|
function stripReminders(text) {
|
|
8518
8572
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -8609,13 +8663,13 @@ var init_claude2 = __esm({
|
|
|
8609
8663
|
return null;
|
|
8610
8664
|
let head;
|
|
8611
8665
|
try {
|
|
8612
|
-
const fd =
|
|
8666
|
+
const fd = openSync6(located.path, "r");
|
|
8613
8667
|
try {
|
|
8614
8668
|
const buf = Buffer.alloc(65536);
|
|
8615
|
-
const n =
|
|
8669
|
+
const n = readSync6(fd, buf, 0, buf.length, 0);
|
|
8616
8670
|
head = buf.toString("utf-8", 0, n);
|
|
8617
8671
|
} finally {
|
|
8618
|
-
|
|
8672
|
+
closeSync6(fd);
|
|
8619
8673
|
}
|
|
8620
8674
|
} catch {
|
|
8621
8675
|
return null;
|
|
@@ -9087,14 +9141,14 @@ var init_claude2 = __esm({
|
|
|
9087
9141
|
spansMultipleSources(prefixedId) {
|
|
9088
9142
|
return findSessionFiles(this.toRawId(prefixedId)).length > 1;
|
|
9089
9143
|
}
|
|
9090
|
-
async readFromOffset(prefixedId, offset) {
|
|
9144
|
+
async readFromOffset(prefixedId, offset, maxBytes) {
|
|
9091
9145
|
const rawId = this.toRawId(prefixedId);
|
|
9092
9146
|
const copies = findSessionFiles(rawId);
|
|
9093
9147
|
if (copies.length === 0)
|
|
9094
9148
|
return { text: "", newOffset: offset };
|
|
9095
9149
|
if (copies.length > 1)
|
|
9096
9150
|
return { text: "", newOffset: offset };
|
|
9097
|
-
return readTailFromOffset(copies[0].path, offset);
|
|
9151
|
+
return readTailFromOffset(copies[0].path, offset, maxBytes);
|
|
9098
9152
|
}
|
|
9099
9153
|
};
|
|
9100
9154
|
claudeBackend = new ClaudeBackend();
|
|
@@ -9678,7 +9732,7 @@ var init_opencode = __esm({
|
|
|
9678
9732
|
});
|
|
9679
9733
|
|
|
9680
9734
|
// ../engine/dist/core/backends/codex.js
|
|
9681
|
-
import { readdirSync as readdirSync10, readFileSync as readFileSync8, statSync as statSync11, openSync as
|
|
9735
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync8, statSync as statSync11, openSync as openSync7, readSync as readSync7, closeSync as closeSync7 } from "fs";
|
|
9682
9736
|
import { basename as basename11, dirname as dirname12, join as join15 } from "path";
|
|
9683
9737
|
function parseShellWrites(cmd) {
|
|
9684
9738
|
const out = [];
|
|
@@ -10352,10 +10406,10 @@ var init_codex2 = __esm({
|
|
|
10352
10406
|
if (p === loc.path)
|
|
10353
10407
|
continue;
|
|
10354
10408
|
try {
|
|
10355
|
-
const fd =
|
|
10409
|
+
const fd = openSync7(p, "r");
|
|
10356
10410
|
const buf = Buffer.alloc(4096);
|
|
10357
|
-
const n =
|
|
10358
|
-
|
|
10411
|
+
const n = readSync7(fd, buf, 0, 4096, 0);
|
|
10412
|
+
closeSync7(fd);
|
|
10359
10413
|
const head = buf.toString("utf-8", 0, n);
|
|
10360
10414
|
if (head.includes(parentId) && head.includes("parent_thread_id"))
|
|
10361
10415
|
push(p, `subagents/${f}`);
|
|
@@ -10380,11 +10434,11 @@ var init_codex2 = __esm({
|
|
|
10380
10434
|
return 0;
|
|
10381
10435
|
}
|
|
10382
10436
|
}
|
|
10383
|
-
async readFromOffset(prefixedId, offset) {
|
|
10437
|
+
async readFromOffset(prefixedId, offset, maxBytes) {
|
|
10384
10438
|
const loc = this.findSession(prefixedId);
|
|
10385
10439
|
if (!loc)
|
|
10386
10440
|
return { text: "", newOffset: offset };
|
|
10387
|
-
return readTailFromOffset(loc.path, offset);
|
|
10441
|
+
return readTailFromOffset(loc.path, offset, maxBytes);
|
|
10388
10442
|
}
|
|
10389
10443
|
};
|
|
10390
10444
|
codexBackend = new CodexBackend();
|
|
@@ -10945,11 +10999,11 @@ var init_agy = __esm({
|
|
|
10945
10999
|
return 0;
|
|
10946
11000
|
}
|
|
10947
11001
|
}
|
|
10948
|
-
async readFromOffset(prefixedId, offset) {
|
|
11002
|
+
async readFromOffset(prefixedId, offset, maxBytes) {
|
|
10949
11003
|
const loc = this.findSession(prefixedId);
|
|
10950
11004
|
if (!loc)
|
|
10951
11005
|
return { text: "", newOffset: offset };
|
|
10952
|
-
return readTailFromOffset(loc.path, offset);
|
|
11006
|
+
return readTailFromOffset(loc.path, offset, maxBytes);
|
|
10953
11007
|
}
|
|
10954
11008
|
};
|
|
10955
11009
|
agyBackend = new AgyBackend();
|
|
@@ -14715,10 +14769,10 @@ var init_types = __esm({
|
|
|
14715
14769
|
|
|
14716
14770
|
// ../engine/dist/transcript/opencode.js
|
|
14717
14771
|
async function parseOpenCodeSubagents(parentSessionId) {
|
|
14718
|
-
const { existsSync:
|
|
14772
|
+
const { existsSync: existsSync48 } = await import("fs");
|
|
14719
14773
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
14720
14774
|
const dbPath = opencodeBackend2.dbPath();
|
|
14721
|
-
if (!
|
|
14775
|
+
if (!existsSync48(dbPath))
|
|
14722
14776
|
return [];
|
|
14723
14777
|
const realParent = parentSessionId.replace("opencode_", "");
|
|
14724
14778
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -14759,10 +14813,10 @@ async function parseOpenCodeSubagents(parentSessionId) {
|
|
|
14759
14813
|
}
|
|
14760
14814
|
}
|
|
14761
14815
|
async function parseOpenCodeTranscript(sessionId) {
|
|
14762
|
-
const { existsSync:
|
|
14816
|
+
const { existsSync: existsSync48 } = await import("fs");
|
|
14763
14817
|
const { opencodeBackend: opencodeBackend2 } = await Promise.resolve().then(() => (init_opencode(), opencode_exports));
|
|
14764
14818
|
const dbPath = opencodeBackend2.dbPath();
|
|
14765
|
-
if (!
|
|
14819
|
+
if (!existsSync48(dbPath))
|
|
14766
14820
|
return [];
|
|
14767
14821
|
const realId = sessionId.replace("opencode_", "");
|
|
14768
14822
|
const db = openSqliteReadonlyOrThrow(dbPath);
|
|
@@ -19248,7 +19302,7 @@ var init_sync_fields = __esm({
|
|
|
19248
19302
|
});
|
|
19249
19303
|
|
|
19250
19304
|
// ../engine/dist/core/index-lock.js
|
|
19251
|
-
import { existsSync as existsSync43, mkdirSync as mkdirSync11, openSync as
|
|
19305
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync11, openSync as openSync9, writeFileSync as writeFileSync8, readFileSync as readFileSync35, rmSync as rmSync4, statSync as statSync40, closeSync as closeSync9 } from "fs";
|
|
19252
19306
|
import { dirname as dirname18, join as join47 } from "path";
|
|
19253
19307
|
function acquireIndexLock(opts) {
|
|
19254
19308
|
const lockPath = lockFilePath();
|
|
@@ -19260,7 +19314,7 @@ function acquireIndexLock(opts) {
|
|
|
19260
19314
|
}
|
|
19261
19315
|
let fd;
|
|
19262
19316
|
try {
|
|
19263
|
-
fd =
|
|
19317
|
+
fd = openSync9(lockPath, "wx", 384);
|
|
19264
19318
|
} catch (err) {
|
|
19265
19319
|
if (err.code === "EEXIST")
|
|
19266
19320
|
return null;
|
|
@@ -19270,7 +19324,7 @@ function acquireIndexLock(opts) {
|
|
|
19270
19324
|
try {
|
|
19271
19325
|
writeFileSync8(fd, JSON.stringify(holder));
|
|
19272
19326
|
} finally {
|
|
19273
|
-
|
|
19327
|
+
closeSync9(fd);
|
|
19274
19328
|
}
|
|
19275
19329
|
let released = false;
|
|
19276
19330
|
return {
|
|
@@ -19364,7 +19418,7 @@ var init_http = __esm({
|
|
|
19364
19418
|
CLI_VERSION = JSON.parse(readFileSync36(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
19365
19419
|
} catch {
|
|
19366
19420
|
try {
|
|
19367
|
-
if (true) CLI_VERSION = "0.7.
|
|
19421
|
+
if (true) CLI_VERSION = "0.7.1";
|
|
19368
19422
|
} catch {
|
|
19369
19423
|
}
|
|
19370
19424
|
}
|
|
@@ -19863,7 +19917,7 @@ var init_telemetry = __esm({
|
|
|
19863
19917
|
init_sync_client();
|
|
19864
19918
|
cliVersion2 = () => {
|
|
19865
19919
|
try {
|
|
19866
|
-
return true ? "0.7.
|
|
19920
|
+
return true ? "0.7.1" : "dev";
|
|
19867
19921
|
} catch {
|
|
19868
19922
|
return "dev";
|
|
19869
19923
|
}
|
|
@@ -20023,16 +20077,17 @@ __export(auto_update_exports, {
|
|
|
20023
20077
|
noteUpdateFailure: () => noteUpdateFailure,
|
|
20024
20078
|
planAutoUpdate: () => planAutoUpdate,
|
|
20025
20079
|
readUpdateState: () => readUpdateState,
|
|
20080
|
+
resolveNpm: () => resolveNpm,
|
|
20026
20081
|
runAutoUpdate: () => runAutoUpdate,
|
|
20027
20082
|
runningPrefix: () => runningPrefix,
|
|
20028
20083
|
sweepStaleStaging: () => sweepStaleStaging,
|
|
20029
20084
|
tarballUrl: () => tarballUrl
|
|
20030
20085
|
});
|
|
20031
|
-
import { execSync as execSync4 } from "node:child_process";
|
|
20032
|
-
import { readFileSync as readFileSync37 } from "node:fs";
|
|
20086
|
+
import { execSync as execSync4, execFileSync as execFileSync3 } from "node:child_process";
|
|
20087
|
+
import { readFileSync as readFileSync37, existsSync as existsSync45 } from "node:fs";
|
|
20033
20088
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
20034
20089
|
import { writeFileSync as writeFileSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync5, readdirSync as readdirSync32, statSync as statSync41, mkdirSync as mkdirSync12 } from "node:fs";
|
|
20035
|
-
import { join as join48, dirname as dirname19, sep as sep3 } from "node:path";
|
|
20090
|
+
import { join as join48, dirname as dirname19, sep as sep3, posix as pathPosix, win32 as pathWin32 } from "node:path";
|
|
20036
20091
|
import { tmpdir as tmpdir3, homedir as homedir17 } from "node:os";
|
|
20037
20092
|
import { createHash as createHash10 } from "node:crypto";
|
|
20038
20093
|
function compareVersions(a, b) {
|
|
@@ -20147,25 +20202,46 @@ function runningPrefix(moduleUrl = import.meta.url) {
|
|
|
20147
20202
|
const beforeNodeModules = here.slice(0, at);
|
|
20148
20203
|
return beforeNodeModules.endsWith(`${sep3}lib`) ? beforeNodeModules.slice(0, -4) : beforeNodeModules;
|
|
20149
20204
|
}
|
|
20150
|
-
function npmInstall(
|
|
20205
|
+
function npmInstall(npm, args) {
|
|
20151
20206
|
try {
|
|
20152
|
-
|
|
20207
|
+
const opts = { stdio: ["ignore", "ignore", "pipe"], env: npm.env };
|
|
20208
|
+
if (npm.shell) execSync4([npm.file, ...npm.args, ...args].map((a) => `"${a}"`).join(" "), opts);
|
|
20209
|
+
else execFileSync3(npm.file, [...npm.args, ...args], opts);
|
|
20153
20210
|
} catch (e) {
|
|
20154
20211
|
const err = e;
|
|
20155
20212
|
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);
|
|
20156
20213
|
throw new Error(detail ? `${err.message ?? "install failed"} \u2014 ${detail}` : err.message ?? "install failed");
|
|
20157
20214
|
}
|
|
20158
20215
|
}
|
|
20216
|
+
function resolveNpm(loc) {
|
|
20217
|
+
const win = loc.platform === "win32";
|
|
20218
|
+
const p = win ? pathWin32 : pathPosix;
|
|
20219
|
+
const nodeDir = p.dirname(loc.execPath);
|
|
20220
|
+
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");
|
|
20221
|
+
const candidates2 = [
|
|
20222
|
+
cliUnder(win ? nodeDir : p.join(nodeDir, "..")),
|
|
20223
|
+
...loc.prefix ? [cliUnder(loc.prefix)] : []
|
|
20224
|
+
];
|
|
20225
|
+
const pathKey = Object.keys(loc.env).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
|
|
20226
|
+
const binDirs = [nodeDir, ...loc.prefix ? [win ? loc.prefix : p.join(loc.prefix, "bin")] : []];
|
|
20227
|
+
const delimiter3 = win ? ";" : ":";
|
|
20228
|
+
const current = loc.env[pathKey] ?? "";
|
|
20229
|
+
const env = { ...loc.env, [pathKey]: [...binDirs, ...current ? [current] : []].join(delimiter3) };
|
|
20230
|
+
const cli = candidates2.find((c) => loc.exists(c));
|
|
20231
|
+
if (cli) return { file: loc.execPath, args: [cli], env, shell: false };
|
|
20232
|
+
return { file: "npm", args: [], env, shell: true };
|
|
20233
|
+
}
|
|
20159
20234
|
function realInstall(tgz) {
|
|
20160
20235
|
const prefix = runningPrefix();
|
|
20236
|
+
const npm = resolveNpm({ execPath: process.execPath, prefix, platform: process.platform, env: process.env, exists: existsSync45 });
|
|
20161
20237
|
if (prefix) {
|
|
20162
|
-
npmInstall(
|
|
20238
|
+
npmInstall(npm, ["install", "-g", "--prefix", prefix, tgz]);
|
|
20163
20239
|
return;
|
|
20164
20240
|
}
|
|
20165
20241
|
try {
|
|
20166
|
-
npmInstall(
|
|
20242
|
+
npmInstall(npm, ["install", "-g", tgz]);
|
|
20167
20243
|
} catch {
|
|
20168
|
-
npmInstall(
|
|
20244
|
+
npmInstall(npm, ["install", "-g", "--prefix", join48(homedir17(), ".local"), tgz]);
|
|
20169
20245
|
}
|
|
20170
20246
|
}
|
|
20171
20247
|
function realRestart(platform2) {
|
|
@@ -20266,7 +20342,9 @@ var init_auto_update = __esm({
|
|
|
20266
20342
|
var sync_client_exports = {};
|
|
20267
20343
|
__export(sync_client_exports, {
|
|
20268
20344
|
BATCH_SCAN_MAX_BYTES: () => BATCH_SCAN_MAX_BYTES,
|
|
20345
|
+
DERIVED_MAX_BYTES: () => DERIVED_MAX_BYTES,
|
|
20269
20346
|
FULL_BUILD_MAX_BYTES: () => FULL_BUILD_MAX_BYTES,
|
|
20347
|
+
SYNC_CHUNK_BYTES: () => SYNC_CHUNK_BYTES,
|
|
20270
20348
|
_acceptedUploads: () => _acceptedUploads,
|
|
20271
20349
|
_fetchTenantSyncConfigForTests: () => _fetchTenantSyncConfigForTests,
|
|
20272
20350
|
_resetCapsCacheForTests: () => _resetCapsCacheForTests,
|
|
@@ -20285,8 +20363,10 @@ __export(sync_client_exports, {
|
|
|
20285
20363
|
reconcileFields: () => reconcileFields,
|
|
20286
20364
|
removeCredentials: () => removeCredentials,
|
|
20287
20365
|
saveCredentials: () => saveCredentials,
|
|
20366
|
+
scanTranscriptFindingsChunked: () => scanTranscriptFindingsChunked,
|
|
20288
20367
|
serverAcceptsGzipBody: () => serverAcceptsGzipBody,
|
|
20289
20368
|
serverIngestConcurrency: () => serverIngestConcurrency,
|
|
20369
|
+
sessionBuildBytes: () => sessionBuildBytes,
|
|
20290
20370
|
sessionFileBytes: () => sessionFileBytes,
|
|
20291
20371
|
setServerIngestConcurrency: () => setServerIngestConcurrency,
|
|
20292
20372
|
syncIncremental: () => syncIncremental,
|
|
@@ -21058,16 +21138,53 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21058
21138
|
clearTimeout(timer);
|
|
21059
21139
|
}
|
|
21060
21140
|
};
|
|
21141
|
+
const postChunkedHead = async (conv, fileSize) => {
|
|
21142
|
+
const headers = { "content-type": "application/json" };
|
|
21143
|
+
if (cred.token) headers.authorization = `Bearer ${cred.token}`;
|
|
21144
|
+
const ac = new AbortController();
|
|
21145
|
+
const timer = setTimeout(() => ac.abort(new Error(`upload timed out after ${UPLOAD_TIMEOUT_MS}ms`)), UPLOAD_TIMEOUT_MS);
|
|
21146
|
+
try {
|
|
21147
|
+
const res = await fetch(`${base}/api/sync`, {
|
|
21148
|
+
method: "POST",
|
|
21149
|
+
headers,
|
|
21150
|
+
body: JSON.stringify({ conversations: [conv] }),
|
|
21151
|
+
signal: ac.signal
|
|
21152
|
+
});
|
|
21153
|
+
if (!res.ok) throw new Error(`chunked head sync failed: HTTP ${res.status} ${await res.text().catch(() => "")}`);
|
|
21154
|
+
const body = await res.json().catch(() => ({}));
|
|
21155
|
+
const id = conv.session_id;
|
|
21156
|
+
const guarded = (body.shrink_guarded ?? []).find((g) => g.session_id === id);
|
|
21157
|
+
const mtime = conv.mtime;
|
|
21158
|
+
try {
|
|
21159
|
+
if (!guarded) {
|
|
21160
|
+
markSynced(base, [{ id, mtime, offset: conv.from_offset, size: conv.from_offset, acked: true }]);
|
|
21161
|
+
} else if (typeof guarded.o === "number" && guarded.o > 0 && guarded.o <= fileSize) {
|
|
21162
|
+
markSynced(base, [{ id, mtime, offset: guarded.o, size: guarded.o, acked: true }]);
|
|
21163
|
+
} else {
|
|
21164
|
+
markSynced(base, [{ id, mtime }]);
|
|
21165
|
+
}
|
|
21166
|
+
} catch {
|
|
21167
|
+
}
|
|
21168
|
+
appendResults.uploaded++;
|
|
21169
|
+
} finally {
|
|
21170
|
+
clearTimeout(timer);
|
|
21171
|
+
}
|
|
21172
|
+
};
|
|
21061
21173
|
let appendBatch = [];
|
|
21174
|
+
let appendBatchBytes = 0;
|
|
21062
21175
|
const APPEND_BATCH_SIZE = 50;
|
|
21176
|
+
const APPEND_BATCH_MAX_BYTES = SYNC_CHUNK_BYTES;
|
|
21063
21177
|
const appendFlush = async () => {
|
|
21064
21178
|
if (appendBatch.length === 0) return;
|
|
21065
21179
|
const batch = appendBatch;
|
|
21066
21180
|
appendBatch = [];
|
|
21181
|
+
appendBatchBytes = 0;
|
|
21067
21182
|
await postAppend(batch);
|
|
21068
21183
|
};
|
|
21069
|
-
const appendAdd = async (conv) => {
|
|
21184
|
+
const appendAdd = async (conv, bytes = 0) => {
|
|
21185
|
+
if (appendBatch.length > 0 && appendBatchBytes + bytes > APPEND_BATCH_MAX_BYTES) await appendFlush();
|
|
21070
21186
|
appendBatch.push(conv);
|
|
21187
|
+
appendBatchBytes += bytes;
|
|
21071
21188
|
if (appendBatch.length >= APPEND_BATCH_SIZE) await appendFlush();
|
|
21072
21189
|
};
|
|
21073
21190
|
const itemsBatch = makeBatcher("items", 100);
|
|
@@ -21146,7 +21263,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21146
21263
|
let externalFindings = null;
|
|
21147
21264
|
if (scanSecrets) {
|
|
21148
21265
|
externalFindings = /* @__PURE__ */ new Map();
|
|
21149
|
-
const toScan = slice.filter((ref) => modeOf(ref) === "full" &&
|
|
21266
|
+
const toScan = slice.filter((ref) => modeOf(ref) === "full" && sessionBuildBytes(ref) <= FULL_BUILD_MAX_BYTES);
|
|
21150
21267
|
trace?.(`batch secret scan start: ${toScan.length} session(s), \u2264${(BATCH_SCAN_MAX_BYTES / 1048576).toFixed(0)}MB per slice`);
|
|
21151
21268
|
const batch = batchScanExternal(
|
|
21152
21269
|
toScan.map((ref) => ({
|
|
@@ -21190,11 +21307,17 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21190
21307
|
const ack = ledger.get(ref.prefixedId);
|
|
21191
21308
|
try {
|
|
21192
21309
|
const tail = await buildConversationTail(ref, ack.o ?? 0, { mapPath, tenantRules });
|
|
21193
|
-
|
|
21310
|
+
const chunked = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
|
|
21311
|
+
if (tail && tail.findings.length > 0 && !chunked) {
|
|
21194
21312
|
promotedForFindings = true;
|
|
21195
21313
|
} else if (tail) {
|
|
21196
21314
|
redactions += tail.redactions;
|
|
21197
|
-
await appendAdd(tail.conv);
|
|
21315
|
+
await appendAdd(tail.conv, tail.bytes);
|
|
21316
|
+
if (tail.findings.length > 0) {
|
|
21317
|
+
await appendFlush();
|
|
21318
|
+
const all = await scanTranscriptFindingsChunked(ref, tenantRules);
|
|
21319
|
+
if (all.length > 0) await findingsBatch.add(all);
|
|
21320
|
+
}
|
|
21198
21321
|
walked++;
|
|
21199
21322
|
if (walked % 250 === 0) console.error(`[sync] ${walked}/${slice.length} sessions\u2026`);
|
|
21200
21323
|
continue;
|
|
@@ -21242,12 +21365,13 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21242
21365
|
}
|
|
21243
21366
|
redactions += built.redactions;
|
|
21244
21367
|
if (built.srcHash) shippedHash.set(ref.prefixedId, built.srcHash);
|
|
21245
|
-
await
|
|
21368
|
+
if (built.conv.chunked) await postChunkedHead(built.conv, sessionFileBytes(ref));
|
|
21369
|
+
else await convBatch.add(built.conv);
|
|
21246
21370
|
if (built.findings.length > 0) await findingsBatch.add(built.findings);
|
|
21247
21371
|
if (upload.sessionMeta) {
|
|
21248
21372
|
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);
|
|
21249
21373
|
}
|
|
21250
|
-
if (upload.sessionMeta && sessionFileBytes(ref) <=
|
|
21374
|
+
if (upload.sessionMeta && sessionFileBytes(ref) <= DERIVED_MAX_BYTES) {
|
|
21251
21375
|
try {
|
|
21252
21376
|
const count = { redactions: 0 };
|
|
21253
21377
|
const offloaded = await scanPool().runDerived({
|
|
@@ -21427,35 +21551,70 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
21427
21551
|
scanMs: Math.round(scanMs)
|
|
21428
21552
|
};
|
|
21429
21553
|
}
|
|
21554
|
+
async function scanTranscriptFindingsChunked(ref, tenantRules) {
|
|
21555
|
+
const backend = getBackendForId(ref.prefixedId);
|
|
21556
|
+
const findings = [];
|
|
21557
|
+
if (!backend?.readFromOffset) return findings;
|
|
21558
|
+
let offset = 0;
|
|
21559
|
+
let lineBase = 0;
|
|
21560
|
+
for (; ; ) {
|
|
21561
|
+
const chunk = await backend.readFromOffset(ref.prefixedId, offset, SYNC_CHUNK_BYTES);
|
|
21562
|
+
if (chunk.newOffset <= offset) break;
|
|
21563
|
+
offset = chunk.newOffset;
|
|
21564
|
+
if (chunk.skippedBytes) {
|
|
21565
|
+
lineBase += 1;
|
|
21566
|
+
continue;
|
|
21567
|
+
}
|
|
21568
|
+
try {
|
|
21569
|
+
for (const f of scanTextForFindings(chunk.text)) {
|
|
21570
|
+
findings.push({ session_id: ref.prefixedId, detector: "builtin", rule: f.rule, line: lineBase + f.line, preview: f.preview });
|
|
21571
|
+
}
|
|
21572
|
+
if (tenantRules && tenantRules.length > 0) {
|
|
21573
|
+
for (const f of scanTenantRules(chunk.text, tenantRules)) {
|
|
21574
|
+
findings.push({ session_id: ref.prefixedId, detector: f.detector, rule: f.rule, line: lineBase + f.line, preview: f.preview });
|
|
21575
|
+
}
|
|
21576
|
+
}
|
|
21577
|
+
} catch {
|
|
21578
|
+
}
|
|
21579
|
+
for (let i = chunk.text.indexOf("\n"); i >= 0; i = chunk.text.indexOf("\n", i + 1)) lineBase++;
|
|
21580
|
+
}
|
|
21581
|
+
return dropFuzzyFindings(findings, (f) => ({ detector: f.detector, rule: f.rule }));
|
|
21582
|
+
}
|
|
21430
21583
|
function sessionFileBytes(ref) {
|
|
21431
21584
|
const backend = getBackendForId(ref.prefixedId);
|
|
21432
21585
|
if (!backend?.isAppendOnly?.()) return 0;
|
|
21433
21586
|
return backend.fileSize?.(ref.prefixedId) ?? 0;
|
|
21434
21587
|
}
|
|
21588
|
+
function sessionBuildBytes(ref) {
|
|
21589
|
+
const main2 = sessionFileBytes(ref);
|
|
21590
|
+
if (main2 === 0) return 0;
|
|
21591
|
+
return Math.max(main2, shadowUncompressedBytes(ref.toolId, ref.rawId));
|
|
21592
|
+
}
|
|
21435
21593
|
async function buildConversationSync(ref, mtime, opts = {}) {
|
|
21436
21594
|
const mapPath = opts.mapPath ?? ((p) => p);
|
|
21437
21595
|
let includeRaw = opts.includeRaw !== false;
|
|
21438
21596
|
let includeMeta = opts.includeMeta !== false;
|
|
21439
21597
|
let srcHash;
|
|
21440
|
-
const
|
|
21441
|
-
|
|
21442
|
-
let
|
|
21443
|
-
let tailOffsetEnd = 0;
|
|
21598
|
+
const oversized = sessionBuildBytes(ref) > FULL_BUILD_MAX_BYTES;
|
|
21599
|
+
let headOffsetEnd = 0;
|
|
21600
|
+
let oversizedFindings = null;
|
|
21444
21601
|
let transcript = null;
|
|
21445
21602
|
let fullestContainer = null;
|
|
21446
21603
|
if (oversized) {
|
|
21447
21604
|
const backend = getBackendForId(ref.prefixedId);
|
|
21448
21605
|
if (!backend?.readFromOffset) return null;
|
|
21449
21606
|
try {
|
|
21450
|
-
|
|
21451
|
-
|
|
21452
|
-
|
|
21453
|
-
|
|
21607
|
+
let head = await backend.readFromOffset(ref.prefixedId, 0, SYNC_CHUNK_BYTES);
|
|
21608
|
+
for (let hops = 0; head.skippedBytes && hops < 8; hops++) {
|
|
21609
|
+
head = await backend.readFromOffset(ref.prefixedId, head.newOffset, SYNC_CHUNK_BYTES);
|
|
21610
|
+
}
|
|
21611
|
+
headOffsetEnd = head.newOffset;
|
|
21612
|
+
const messages = parseTailMessages(ref.toolId, head.text);
|
|
21454
21613
|
if (messages.length > 0) transcript = { messages, subagents: [] };
|
|
21455
21614
|
} catch {
|
|
21456
21615
|
}
|
|
21457
21616
|
includeRaw = false;
|
|
21458
|
-
|
|
21617
|
+
oversizedFindings = await scanTranscriptFindingsChunked(ref, opts.tenantRules);
|
|
21459
21618
|
} else {
|
|
21460
21619
|
try {
|
|
21461
21620
|
const backend = getBackendForId(ref.prefixedId) ?? getBackend("claude");
|
|
@@ -21516,7 +21675,6 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21516
21675
|
);
|
|
21517
21676
|
let projectPath = ref.projectPath;
|
|
21518
21677
|
const meta = { messageCount: textMessages.length };
|
|
21519
|
-
if (oversized) meta.truncated = true;
|
|
21520
21678
|
if (textMessages.filter((m) => m.role === "user").length <= 1) meta.oneShot = true;
|
|
21521
21679
|
try {
|
|
21522
21680
|
const cwd = ref.fullPath ? readCwdFromJsonl(ref.fullPath) : "";
|
|
@@ -21630,21 +21788,7 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21630
21788
|
}
|
|
21631
21789
|
scanMs = performance.now() - t0;
|
|
21632
21790
|
}
|
|
21633
|
-
if (
|
|
21634
|
-
const t0 = performance.now();
|
|
21635
|
-
try {
|
|
21636
|
-
for (const f of scanTextForFindings(tailText)) {
|
|
21637
|
-
findings.push({ session_id: ref.prefixedId, detector: "builtin", rule: f.rule, line: f.line, preview: f.preview });
|
|
21638
|
-
}
|
|
21639
|
-
if (opts.tenantRules && opts.tenantRules.length > 0) {
|
|
21640
|
-
for (const f of scanTenantRules(tailText, opts.tenantRules)) {
|
|
21641
|
-
findings.push({ session_id: ref.prefixedId, detector: f.detector, rule: f.rule, line: f.line, preview: f.preview });
|
|
21642
|
-
}
|
|
21643
|
-
}
|
|
21644
|
-
} catch {
|
|
21645
|
-
}
|
|
21646
|
-
scanMs = performance.now() - t0;
|
|
21647
|
-
}
|
|
21791
|
+
if (oversizedFindings) findings.push(...oversizedFindings);
|
|
21648
21792
|
const keptFindings = dropFuzzyFindings(findings, (f) => ({ detector: f.detector, rule: f.rule }));
|
|
21649
21793
|
findings.length = 0;
|
|
21650
21794
|
findings.push(...keptFindings);
|
|
@@ -21690,7 +21834,10 @@ async function buildConversationSync(ref, mtime, opts = {}) {
|
|
|
21690
21834
|
// (convBatch onFlush uses this, not a recomputed size) so the next
|
|
21691
21835
|
// append's base_offset matches exactly — no spurious continuity misses on
|
|
21692
21836
|
// an actively-growing session. undefined for non-append-only backends.
|
|
21693
|
-
from_offset: oversized ?
|
|
21837
|
+
from_offset: oversized ? headOffsetEnd : getBackendForId(ref.prefixedId)?.fileSize?.(ref.rawId),
|
|
21838
|
+
// The head of a chunked session. The server reports back when its shrink
|
|
21839
|
+
// guard keeps a fuller stored copy, so the client appends from there.
|
|
21840
|
+
...oversized ? { chunked: true } : {},
|
|
21694
21841
|
meta,
|
|
21695
21842
|
mtime
|
|
21696
21843
|
},
|
|
@@ -21712,12 +21859,30 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
|
|
|
21712
21859
|
const backend = getBackendForId(ref.prefixedId);
|
|
21713
21860
|
if (!backend?.readFromOffset) return null;
|
|
21714
21861
|
const mapPath = opts.mapPath ?? ((p) => p);
|
|
21715
|
-
const { text: tailText, newOffset } = await backend.readFromOffset(ref.prefixedId, fromOffset);
|
|
21716
|
-
if (
|
|
21717
|
-
const messages = parseTailMessages(ref.toolId, tailText);
|
|
21718
|
-
if (messages.length === 0) return null;
|
|
21862
|
+
const { text: tailText, newOffset, skippedBytes } = await backend.readFromOffset(ref.prefixedId, fromOffset, SYNC_CHUNK_BYTES);
|
|
21863
|
+
if (newOffset <= fromOffset) return null;
|
|
21864
|
+
const messages = skippedBytes ? [] : parseTailMessages(ref.toolId, tailText);
|
|
21719
21865
|
const textMessages = messages.filter((m) => m.role !== "summary" && m.content?.trim());
|
|
21720
|
-
|
|
21866
|
+
const hasContent = textMessages.length > 0 || messages.some((m) => m.toolCalls?.length);
|
|
21867
|
+
if (!hasContent) {
|
|
21868
|
+
return {
|
|
21869
|
+
conv: {
|
|
21870
|
+
session_id: ref.prefixedId,
|
|
21871
|
+
tool: ref.toolId,
|
|
21872
|
+
project_path: mapPath(ref.projectPath),
|
|
21873
|
+
append: true,
|
|
21874
|
+
base_offset: fromOffset,
|
|
21875
|
+
from_offset: newOffset,
|
|
21876
|
+
redacted_text: "",
|
|
21877
|
+
envelope: { v: TRANSCRIPT_VERSION, messages: [], subagents: [] },
|
|
21878
|
+
mtime: Math.floor(ref.mtime) || 0
|
|
21879
|
+
},
|
|
21880
|
+
redactions: 0,
|
|
21881
|
+
newOffset,
|
|
21882
|
+
findings: [],
|
|
21883
|
+
bytes: 0
|
|
21884
|
+
};
|
|
21885
|
+
}
|
|
21721
21886
|
const firstUser = textMessages.find((m) => m.role === "user");
|
|
21722
21887
|
if (isInternalToolPrompt(firstUser?.content)) return null;
|
|
21723
21888
|
const count = { redactions: 0 };
|
|
@@ -21760,7 +21925,8 @@ async function buildConversationTail(ref, fromOffset, opts = {}) {
|
|
|
21760
21925
|
},
|
|
21761
21926
|
redactions: count.redactions,
|
|
21762
21927
|
newOffset,
|
|
21763
|
-
findings
|
|
21928
|
+
findings,
|
|
21929
|
+
bytes: Buffer.byteLength(tailText)
|
|
21764
21930
|
};
|
|
21765
21931
|
}
|
|
21766
21932
|
function isSyncSkip(r) {
|
|
@@ -21790,7 +21956,7 @@ async function syncIncremental(opts = {}) {
|
|
|
21790
21956
|
lock.release();
|
|
21791
21957
|
}
|
|
21792
21958
|
}
|
|
21793
|
-
var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, SYNC_RULES_REFUSAL, hashPath, acceptedUploads, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES,
|
|
21959
|
+
var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, _fetchTenantSyncConfigForTests, 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;
|
|
21794
21960
|
var init_sync_client = __esm({
|
|
21795
21961
|
"src/sync-client.ts"() {
|
|
21796
21962
|
"use strict";
|
|
@@ -21835,7 +22001,7 @@ var init_sync_client = __esm({
|
|
|
21835
22001
|
ownVersion = JSON.parse(readFileSync38(join49(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21836
22002
|
} catch {
|
|
21837
22003
|
try {
|
|
21838
|
-
if (true) ownVersion = "0.7.
|
|
22004
|
+
if (true) ownVersion = "0.7.1";
|
|
21839
22005
|
} catch {
|
|
21840
22006
|
}
|
|
21841
22007
|
}
|
|
@@ -21862,8 +22028,9 @@ var init_sync_client = __esm({
|
|
|
21862
22028
|
capsOk = /* @__PURE__ */ new Map();
|
|
21863
22029
|
advertisedIngestConc = /* @__PURE__ */ new Map();
|
|
21864
22030
|
advertisedGzipBody = /* @__PURE__ */ new Set();
|
|
21865
|
-
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "
|
|
21866
|
-
|
|
22031
|
+
FULL_BUILD_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_FULL_BUILD_MAX_MB || "24", 10)) * 1024 * 1024;
|
|
22032
|
+
DERIVED_MAX_BYTES = Math.max(8, parseInt(process.env.CHAT_RECALL_DERIVED_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
22033
|
+
SYNC_CHUNK_BYTES = 8 * 1024 * 1024;
|
|
21867
22034
|
BATCH_SCAN_MAX_BYTES = Math.max(1, parseInt(process.env.CHAT_RECALL_BATCHSCAN_MAX_MB || "64", 10)) * 1024 * 1024;
|
|
21868
22035
|
}
|
|
21869
22036
|
});
|
|
@@ -22048,211 +22215,6 @@ var init_update_notice = __esm({
|
|
|
22048
22215
|
}
|
|
22049
22216
|
});
|
|
22050
22217
|
|
|
22051
|
-
// src/install-skills.ts
|
|
22052
|
-
var install_skills_exports = {};
|
|
22053
|
-
__export(install_skills_exports, {
|
|
22054
|
-
bundledSkillNames: () => bundledSkillNames,
|
|
22055
|
-
installSkills: () => installSkills,
|
|
22056
|
-
skillStatus: () => skillStatus,
|
|
22057
|
-
skillTargets: () => skillTargets,
|
|
22058
|
-
skillsNeedRefresh: () => skillsNeedRefresh,
|
|
22059
|
-
skillsSourceDir: () => skillsSourceDir,
|
|
22060
|
-
uninstallSkills: () => uninstallSkills
|
|
22061
|
-
});
|
|
22062
|
-
import { readdirSync as readdirSync34, existsSync as existsSync45, mkdirSync as mkdirSync14, rmSync as rmSync7, cpSync, writeFileSync as writeFileSync12, readFileSync as readFileSync41, statSync as statSync43, realpathSync as realpathSync4 } from "fs";
|
|
22063
|
-
import { createHash as createHash12 } from "crypto";
|
|
22064
|
-
import { join as join51, basename as basename23 } from "path";
|
|
22065
|
-
function skillsSourceDir() {
|
|
22066
|
-
return join51(import.meta.dirname, "..", "skills");
|
|
22067
|
-
}
|
|
22068
|
-
function version() {
|
|
22069
|
-
try {
|
|
22070
|
-
return JSON.parse(readFileSync41(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
|
|
22071
|
-
} catch {
|
|
22072
|
-
return "0.0.0";
|
|
22073
|
-
}
|
|
22074
|
-
}
|
|
22075
|
-
function skillsFingerprint() {
|
|
22076
|
-
const src = skillsSourceDir();
|
|
22077
|
-
const h = createHash12("sha256");
|
|
22078
|
-
for (const name of bundledSkillNames()) {
|
|
22079
|
-
for (const rel of filesUnder(join51(src, name)).sort()) {
|
|
22080
|
-
h.update(name + "/" + rel);
|
|
22081
|
-
h.update(readFileSync41(join51(src, name, rel)));
|
|
22082
|
-
}
|
|
22083
|
-
}
|
|
22084
|
-
return h.digest("hex").slice(0, 12);
|
|
22085
|
-
}
|
|
22086
|
-
function filesUnder(dir, prefix = "") {
|
|
22087
|
-
const out = [];
|
|
22088
|
-
for (const e of readdirSync34(dir, { withFileTypes: true })) {
|
|
22089
|
-
if (e.name === MARKER) continue;
|
|
22090
|
-
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
22091
|
-
if (e.isDirectory()) out.push(...filesUnder(join51(dir, e.name), rel));
|
|
22092
|
-
else out.push(rel);
|
|
22093
|
-
}
|
|
22094
|
-
return out;
|
|
22095
|
-
}
|
|
22096
|
-
function skillStamp() {
|
|
22097
|
-
return `${version()} ${skillsFingerprint()}`;
|
|
22098
|
-
}
|
|
22099
|
-
function bundledSkillNames() {
|
|
22100
|
-
const src = skillsSourceDir();
|
|
22101
|
-
if (!existsSync45(src)) return [];
|
|
22102
|
-
return readdirSync34(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync45(join51(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
|
|
22103
|
-
}
|
|
22104
|
-
function realPathOrSelf(p) {
|
|
22105
|
-
try {
|
|
22106
|
-
return realpathSync4(p);
|
|
22107
|
-
} catch {
|
|
22108
|
-
return p;
|
|
22109
|
-
}
|
|
22110
|
-
}
|
|
22111
|
-
function claudeSkillTargets() {
|
|
22112
|
-
const targets = [];
|
|
22113
|
-
const seen = /* @__PURE__ */ new Set();
|
|
22114
|
-
for (const home of claudeHomeDirs()) {
|
|
22115
|
-
const dir = join51(home, "skills");
|
|
22116
|
-
const key2 = realPathOrSelf(dir);
|
|
22117
|
-
if (seen.has(key2)) continue;
|
|
22118
|
-
seen.add(key2);
|
|
22119
|
-
const primary = targets.length === 0;
|
|
22120
|
-
targets.push({
|
|
22121
|
-
id: primary ? "claude" : `claude:${basename23(home)}`,
|
|
22122
|
-
label: primary ? "Claude Code" : `Claude Code (${basename23(home)})`,
|
|
22123
|
-
dir,
|
|
22124
|
-
// Judge each profile on ITS OWN transcripts, not the primary's: a home
|
|
22125
|
-
// with no projects/ is a directory someone made, not a Claude install.
|
|
22126
|
-
available: existsSync45(join51(home, "projects"))
|
|
22127
|
-
});
|
|
22128
|
-
}
|
|
22129
|
-
if (targets.length === 0) {
|
|
22130
|
-
targets.push({ id: "claude", label: "Claude Code", dir: claudeBackend.skillsDir(), available: claudeBackend.isAvailable() });
|
|
22131
|
-
}
|
|
22132
|
-
return targets;
|
|
22133
|
-
}
|
|
22134
|
-
function skillTargets() {
|
|
22135
|
-
return [
|
|
22136
|
-
// Per-tool dirs ONLY. We deliberately do NOT also write ~/.agents/skills:
|
|
22137
|
-
// some tools read BOTH ~/.agents/skills and their own dir, so installing to
|
|
22138
|
-
// both produces "skill conflict" duplicate warnings. Every tool we support
|
|
22139
|
-
// has its own dir, so per-tool coverage is complete.
|
|
22140
|
-
...claudeSkillTargets(),
|
|
22141
|
-
{ id: "agy", label: "Antigravity", dir: join51(agyBackend.homeDir(), "skills"), available: agyBackend.isAvailable() },
|
|
22142
|
-
{ id: "codex", label: "Codex", dir: codexBackend.skillsDir(), available: codexBackend.isAvailable() },
|
|
22143
|
-
{ id: "opencode", label: "OpenCode", dir: opencodeBackend.skillsDir(), available: opencodeBackend.isAvailable() },
|
|
22144
|
-
// Cursor DOES have its own dir (~/.cursor/skills). `skills-cursor` next to
|
|
22145
|
-
// it is Cursor's bundled set — read-only, never an install target.
|
|
22146
|
-
{ id: "cursor", label: "Cursor", dir: join51(cursorHomeDir(), "skills"), available: cursorBackend.isAvailable() }
|
|
22147
|
-
];
|
|
22148
|
-
}
|
|
22149
|
-
function isManaged(dir) {
|
|
22150
|
-
return existsSync45(join51(dir, MARKER));
|
|
22151
|
-
}
|
|
22152
|
-
function installSkills(opts = {}) {
|
|
22153
|
-
const onlyAvailable = opts.onlyAvailable ?? true;
|
|
22154
|
-
const src = skillsSourceDir();
|
|
22155
|
-
const names = bundledSkillNames();
|
|
22156
|
-
const v = version();
|
|
22157
|
-
const stamp = skillStamp();
|
|
22158
|
-
const perTarget = [];
|
|
22159
|
-
for (const t of skillTargets()) {
|
|
22160
|
-
const installed = [];
|
|
22161
|
-
const skippedUserOwned = [];
|
|
22162
|
-
if (onlyAvailable && !t.available) {
|
|
22163
|
-
perTarget.push({ ...t, installed, skippedUserOwned });
|
|
22164
|
-
continue;
|
|
22165
|
-
}
|
|
22166
|
-
for (const name of names) {
|
|
22167
|
-
const dest = join51(t.dir, name);
|
|
22168
|
-
if (existsSync45(dest) && !isManaged(dest)) {
|
|
22169
|
-
skippedUserOwned.push(name);
|
|
22170
|
-
continue;
|
|
22171
|
-
}
|
|
22172
|
-
mkdirSync14(t.dir, { recursive: true });
|
|
22173
|
-
rmSync7(dest, { recursive: true, force: true });
|
|
22174
|
-
cpSync(join51(src, name), dest, { recursive: true });
|
|
22175
|
-
writeFileSync12(join51(dest, MARKER), `${stamp}
|
|
22176
|
-
`);
|
|
22177
|
-
installed.push(name);
|
|
22178
|
-
}
|
|
22179
|
-
perTarget.push({ ...t, installed, skippedUserOwned });
|
|
22180
|
-
}
|
|
22181
|
-
return { version: v, perTarget };
|
|
22182
|
-
}
|
|
22183
|
-
function uninstallSkills() {
|
|
22184
|
-
const names = new Set(bundledSkillNames());
|
|
22185
|
-
const perTarget = [];
|
|
22186
|
-
for (const t of skillTargets()) {
|
|
22187
|
-
const removed = [];
|
|
22188
|
-
if (!existsSync45(t.dir)) {
|
|
22189
|
-
perTarget.push({ id: t.id, label: t.label, removed });
|
|
22190
|
-
continue;
|
|
22191
|
-
}
|
|
22192
|
-
for (const entry of readdirSync34(t.dir, { withFileTypes: true })) {
|
|
22193
|
-
if (!entry.isDirectory()) continue;
|
|
22194
|
-
const dir = join51(t.dir, entry.name);
|
|
22195
|
-
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
22196
|
-
rmSync7(dir, { recursive: true, force: true });
|
|
22197
|
-
removed.push(entry.name);
|
|
22198
|
-
}
|
|
22199
|
-
}
|
|
22200
|
-
perTarget.push({ id: t.id, label: t.label, removed });
|
|
22201
|
-
}
|
|
22202
|
-
return { perTarget };
|
|
22203
|
-
}
|
|
22204
|
-
function skillsNeedRefresh() {
|
|
22205
|
-
const cur = skillStamp();
|
|
22206
|
-
const names = bundledSkillNames();
|
|
22207
|
-
if (names.length === 0) return false;
|
|
22208
|
-
for (const t of skillTargets()) {
|
|
22209
|
-
if (!t.available) continue;
|
|
22210
|
-
for (const name of names) {
|
|
22211
|
-
const marker = join51(t.dir, name, MARKER);
|
|
22212
|
-
if (!existsSync45(marker)) return true;
|
|
22213
|
-
try {
|
|
22214
|
-
if (readFileSync41(marker, "utf-8").trim() !== cur) return true;
|
|
22215
|
-
} catch {
|
|
22216
|
-
return true;
|
|
22217
|
-
}
|
|
22218
|
-
}
|
|
22219
|
-
}
|
|
22220
|
-
return false;
|
|
22221
|
-
}
|
|
22222
|
-
function skillStatus() {
|
|
22223
|
-
const names = bundledSkillNames();
|
|
22224
|
-
const cur = skillStamp();
|
|
22225
|
-
return skillTargets().map((t) => {
|
|
22226
|
-
let installed = 0;
|
|
22227
|
-
let ver = null;
|
|
22228
|
-
for (const name of names) {
|
|
22229
|
-
const marker = join51(t.dir, name, MARKER);
|
|
22230
|
-
if (existsSync45(marker)) {
|
|
22231
|
-
installed++;
|
|
22232
|
-
try {
|
|
22233
|
-
ver = readFileSync41(marker, "utf-8").trim();
|
|
22234
|
-
} catch {
|
|
22235
|
-
}
|
|
22236
|
-
}
|
|
22237
|
-
}
|
|
22238
|
-
return { id: t.id, label: t.label, available: t.available, installed, version: installed === names.length ? ver : installed ? `${ver} (partial)` : null };
|
|
22239
|
-
}).filter((s) => s.available || s.installed > 0);
|
|
22240
|
-
}
|
|
22241
|
-
var MARKER;
|
|
22242
|
-
var init_install_skills = __esm({
|
|
22243
|
-
"src/install-skills.ts"() {
|
|
22244
|
-
"use strict";
|
|
22245
|
-
init_tool_paths();
|
|
22246
|
-
init_claude2();
|
|
22247
|
-
init_opencode();
|
|
22248
|
-
init_codex2();
|
|
22249
|
-
init_agy();
|
|
22250
|
-
init_cursor();
|
|
22251
|
-
init_tool_paths();
|
|
22252
|
-
MARKER = ".chat-recall-managed";
|
|
22253
|
-
}
|
|
22254
|
-
});
|
|
22255
|
-
|
|
22256
22218
|
// src/service-installer.ts
|
|
22257
22219
|
var service_installer_exports = {};
|
|
22258
22220
|
__export(service_installer_exports, {
|
|
@@ -22267,15 +22229,15 @@ __export(service_installer_exports, {
|
|
|
22267
22229
|
uninstallService: () => uninstallService
|
|
22268
22230
|
});
|
|
22269
22231
|
import { execSync as execSync5 } from "child_process";
|
|
22270
|
-
import { existsSync as existsSync46, mkdirSync as
|
|
22232
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync14, readFileSync as readFileSync41, rmSync as rmSync7, writeFileSync as writeFileSync12 } from "fs";
|
|
22271
22233
|
import { homedir as homedir18 } from "os";
|
|
22272
|
-
import { join as
|
|
22234
|
+
import { join as join51 } from "path";
|
|
22273
22235
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
22274
22236
|
function resolveDaemonPaths() {
|
|
22275
22237
|
const watchJs = fileURLToPath4(new URL("./watch.js", import.meta.url));
|
|
22276
22238
|
const node = process.execPath;
|
|
22277
|
-
const dataDir =
|
|
22278
|
-
const logFile =
|
|
22239
|
+
const dataDir = join51(homedir18(), ".chat-recall");
|
|
22240
|
+
const logFile = join51(dataDir, "watch.log");
|
|
22279
22241
|
return { watchJs, node, logFile, dataDir };
|
|
22280
22242
|
}
|
|
22281
22243
|
function tryCmd(cmd) {
|
|
@@ -22294,7 +22256,7 @@ function isServiceRunning() {
|
|
|
22294
22256
|
return /com\.chat-recall\.watch/.test(tryCmd("launchctl list 2>/dev/null"));
|
|
22295
22257
|
}
|
|
22296
22258
|
if (process.platform === "linux") {
|
|
22297
|
-
return
|
|
22259
|
+
return /^active$/m.test(tryCmd("systemctl --user is-active chat-recall-watch.service 2>/dev/null"));
|
|
22298
22260
|
}
|
|
22299
22261
|
return false;
|
|
22300
22262
|
}
|
|
@@ -22302,13 +22264,13 @@ function refreshServiceDefinition() {
|
|
|
22302
22264
|
if (process.platform !== "linux") return false;
|
|
22303
22265
|
try {
|
|
22304
22266
|
const { watchJs, node, logFile } = resolveDaemonPaths();
|
|
22305
|
-
const unitPath =
|
|
22267
|
+
const unitPath = join51(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
22306
22268
|
if (!existsSync46(unitPath)) return false;
|
|
22307
|
-
const current =
|
|
22269
|
+
const current = readFileSync41(unitPath, "utf8");
|
|
22308
22270
|
if (!current.includes(watchJs)) return false;
|
|
22309
22271
|
const wanted = renderSystemdUnit(watchJs, node, logFile);
|
|
22310
|
-
if (
|
|
22311
|
-
|
|
22272
|
+
if (readFileSync41(unitPath, "utf8") === wanted) return false;
|
|
22273
|
+
writeFileSync12(unitPath, wanted);
|
|
22312
22274
|
execSync5("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
22313
22275
|
return true;
|
|
22314
22276
|
} catch {
|
|
@@ -22317,7 +22279,7 @@ function refreshServiceDefinition() {
|
|
|
22317
22279
|
}
|
|
22318
22280
|
function installService() {
|
|
22319
22281
|
const { watchJs, node, logFile, dataDir } = resolveDaemonPaths();
|
|
22320
|
-
|
|
22282
|
+
mkdirSync14(dataDir, { recursive: true });
|
|
22321
22283
|
if (process.platform === "linux") {
|
|
22322
22284
|
return installSystemd(watchJs, node, logFile);
|
|
22323
22285
|
}
|
|
@@ -22333,11 +22295,11 @@ function installService() {
|
|
|
22333
22295
|
);
|
|
22334
22296
|
}
|
|
22335
22297
|
function installSystemd(watchJs, node, logFile) {
|
|
22336
|
-
const unitDir =
|
|
22337
|
-
const unitPath =
|
|
22298
|
+
const unitDir = join51(homedir18(), ".config", "systemd", "user");
|
|
22299
|
+
const unitPath = join51(unitDir, "chat-recall-watch.service");
|
|
22338
22300
|
const unit = renderSystemdUnit(watchJs, node, logFile);
|
|
22339
|
-
|
|
22340
|
-
|
|
22301
|
+
mkdirSync14(unitDir, { recursive: true });
|
|
22302
|
+
writeFileSync12(unitPath, unit);
|
|
22341
22303
|
try {
|
|
22342
22304
|
execSync5("systemctl --user daemon-reload && systemctl --user enable chat-recall-watch.service && systemctl --user restart chat-recall-watch.service", { stdio: "inherit" });
|
|
22343
22305
|
try {
|
|
@@ -22370,7 +22332,12 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
22370
22332
|
// sawtooth. 1536MB keeps GC honest (768 OOMed on the largest subagent-fanout session) with plenty of headroom for the
|
|
22371
22333
|
// largest transcripts.
|
|
22372
22334
|
`ExecStart=${node} --max-old-space-size=1536 ${watchJs}`,
|
|
22373
|
-
|
|
22335
|
+
// ALWAYS: the collector never ends its own work, so any exit systemd did
|
|
22336
|
+
// not ask for is a fault. Under on-failure a clean exit left it dead: on
|
|
22337
|
+
// 2026-09-16 the unit went "inactive (dead) … status=0/SUCCESS" and stayed
|
|
22338
|
+
// down for 8 days, so nothing synced and the auto-update tick, which runs
|
|
22339
|
+
// inside the daemon, never ran. `systemctl stop` still stops it.
|
|
22340
|
+
"Restart=always",
|
|
22374
22341
|
"RestartSec=10",
|
|
22375
22342
|
"Nice=10",
|
|
22376
22343
|
// NEVER STOP RETRYING. systemd's default start limiter gives up after a
|
|
@@ -22408,11 +22375,11 @@ function renderSystemdUnit(watchJs, node, logFile) {
|
|
|
22408
22375
|
}
|
|
22409
22376
|
function installLaunchd(watchJs, node, logFile) {
|
|
22410
22377
|
const label = "com.chat-recall.watch";
|
|
22411
|
-
const plistDir =
|
|
22412
|
-
const plistPath =
|
|
22378
|
+
const plistDir = join51(homedir18(), "Library", "LaunchAgents");
|
|
22379
|
+
const plistPath = join51(plistDir, `${label}.plist`);
|
|
22413
22380
|
const plist = renderLaunchdPlist(watchJs, node, logFile, label);
|
|
22414
|
-
|
|
22415
|
-
|
|
22381
|
+
mkdirSync14(plistDir, { recursive: true });
|
|
22382
|
+
writeFileSync12(plistPath, plist);
|
|
22416
22383
|
try {
|
|
22417
22384
|
try {
|
|
22418
22385
|
execSync5(`launchctl unload "${plistPath}"`, { stdio: "ignore" });
|
|
@@ -22465,9 +22432,9 @@ function uninstallService() {
|
|
|
22465
22432
|
removed = true;
|
|
22466
22433
|
} catch {
|
|
22467
22434
|
}
|
|
22468
|
-
const unitPath =
|
|
22435
|
+
const unitPath = join51(homedir18(), ".config", "systemd", "user", "chat-recall-watch.service");
|
|
22469
22436
|
if (existsSync46(unitPath)) {
|
|
22470
|
-
|
|
22437
|
+
rmSync7(unitPath, { force: true });
|
|
22471
22438
|
removed = true;
|
|
22472
22439
|
}
|
|
22473
22440
|
try {
|
|
@@ -22477,14 +22444,14 @@ function uninstallService() {
|
|
|
22477
22444
|
return removed;
|
|
22478
22445
|
}
|
|
22479
22446
|
if (process.platform === "darwin") {
|
|
22480
|
-
const plistPath =
|
|
22447
|
+
const plistPath = join51(homedir18(), "Library", "LaunchAgents", "com.chat-recall.watch.plist");
|
|
22481
22448
|
try {
|
|
22482
22449
|
execSync5(`launchctl unload "${plistPath}" 2>/dev/null`, { stdio: "ignore" });
|
|
22483
22450
|
} catch {
|
|
22484
22451
|
}
|
|
22485
22452
|
let removed = false;
|
|
22486
22453
|
if (existsSync46(plistPath)) {
|
|
22487
|
-
|
|
22454
|
+
rmSync7(plistPath, { force: true });
|
|
22488
22455
|
removed = true;
|
|
22489
22456
|
}
|
|
22490
22457
|
return removed;
|
|
@@ -22519,6 +22486,211 @@ var init_service_installer = __esm({
|
|
|
22519
22486
|
}
|
|
22520
22487
|
});
|
|
22521
22488
|
|
|
22489
|
+
// src/install-skills.ts
|
|
22490
|
+
var install_skills_exports = {};
|
|
22491
|
+
__export(install_skills_exports, {
|
|
22492
|
+
bundledSkillNames: () => bundledSkillNames,
|
|
22493
|
+
installSkills: () => installSkills,
|
|
22494
|
+
skillStatus: () => skillStatus,
|
|
22495
|
+
skillTargets: () => skillTargets,
|
|
22496
|
+
skillsNeedRefresh: () => skillsNeedRefresh,
|
|
22497
|
+
skillsSourceDir: () => skillsSourceDir,
|
|
22498
|
+
uninstallSkills: () => uninstallSkills
|
|
22499
|
+
});
|
|
22500
|
+
import { readdirSync as readdirSync34, existsSync as existsSync47, mkdirSync as mkdirSync15, rmSync as rmSync8, cpSync, writeFileSync as writeFileSync13, readFileSync as readFileSync42, statSync as statSync43, realpathSync as realpathSync4 } from "fs";
|
|
22501
|
+
import { createHash as createHash12 } from "crypto";
|
|
22502
|
+
import { join as join52, basename as basename23 } from "path";
|
|
22503
|
+
function skillsSourceDir() {
|
|
22504
|
+
return join52(import.meta.dirname, "..", "skills");
|
|
22505
|
+
}
|
|
22506
|
+
function version() {
|
|
22507
|
+
try {
|
|
22508
|
+
return JSON.parse(readFileSync42(new URL("../package.json", import.meta.url), "utf-8")).version || "0.0.0";
|
|
22509
|
+
} catch {
|
|
22510
|
+
return "0.0.0";
|
|
22511
|
+
}
|
|
22512
|
+
}
|
|
22513
|
+
function skillsFingerprint() {
|
|
22514
|
+
const src = skillsSourceDir();
|
|
22515
|
+
const h = createHash12("sha256");
|
|
22516
|
+
for (const name of bundledSkillNames()) {
|
|
22517
|
+
for (const rel of filesUnder(join52(src, name)).sort()) {
|
|
22518
|
+
h.update(name + "/" + rel);
|
|
22519
|
+
h.update(readFileSync42(join52(src, name, rel)));
|
|
22520
|
+
}
|
|
22521
|
+
}
|
|
22522
|
+
return h.digest("hex").slice(0, 12);
|
|
22523
|
+
}
|
|
22524
|
+
function filesUnder(dir, prefix = "") {
|
|
22525
|
+
const out = [];
|
|
22526
|
+
for (const e of readdirSync34(dir, { withFileTypes: true })) {
|
|
22527
|
+
if (e.name === MARKER) continue;
|
|
22528
|
+
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
22529
|
+
if (e.isDirectory()) out.push(...filesUnder(join52(dir, e.name), rel));
|
|
22530
|
+
else out.push(rel);
|
|
22531
|
+
}
|
|
22532
|
+
return out;
|
|
22533
|
+
}
|
|
22534
|
+
function skillStamp() {
|
|
22535
|
+
return `${version()} ${skillsFingerprint()}`;
|
|
22536
|
+
}
|
|
22537
|
+
function bundledSkillNames() {
|
|
22538
|
+
const src = skillsSourceDir();
|
|
22539
|
+
if (!existsSync47(src)) return [];
|
|
22540
|
+
return readdirSync34(src, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync47(join52(src, e.name, "SKILL.md"))).map((e) => e.name).sort();
|
|
22541
|
+
}
|
|
22542
|
+
function realPathOrSelf(p) {
|
|
22543
|
+
try {
|
|
22544
|
+
return realpathSync4(p);
|
|
22545
|
+
} catch {
|
|
22546
|
+
return p;
|
|
22547
|
+
}
|
|
22548
|
+
}
|
|
22549
|
+
function claudeSkillTargets() {
|
|
22550
|
+
const targets = [];
|
|
22551
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22552
|
+
for (const home of claudeHomeDirs()) {
|
|
22553
|
+
const dir = join52(home, "skills");
|
|
22554
|
+
const key2 = realPathOrSelf(dir);
|
|
22555
|
+
if (seen.has(key2)) continue;
|
|
22556
|
+
seen.add(key2);
|
|
22557
|
+
const primary = targets.length === 0;
|
|
22558
|
+
targets.push({
|
|
22559
|
+
id: primary ? "claude" : `claude:${basename23(home)}`,
|
|
22560
|
+
label: primary ? "Claude Code" : `Claude Code (${basename23(home)})`,
|
|
22561
|
+
dir,
|
|
22562
|
+
// Judge each profile on ITS OWN transcripts, not the primary's: a home
|
|
22563
|
+
// with no projects/ is a directory someone made, not a Claude install.
|
|
22564
|
+
available: existsSync47(join52(home, "projects"))
|
|
22565
|
+
});
|
|
22566
|
+
}
|
|
22567
|
+
if (targets.length === 0) {
|
|
22568
|
+
targets.push({ id: "claude", label: "Claude Code", dir: claudeBackend.skillsDir(), available: claudeBackend.isAvailable() });
|
|
22569
|
+
}
|
|
22570
|
+
return targets;
|
|
22571
|
+
}
|
|
22572
|
+
function skillTargets() {
|
|
22573
|
+
return [
|
|
22574
|
+
// Per-tool dirs ONLY. We deliberately do NOT also write ~/.agents/skills:
|
|
22575
|
+
// some tools read BOTH ~/.agents/skills and their own dir, so installing to
|
|
22576
|
+
// both produces "skill conflict" duplicate warnings. Every tool we support
|
|
22577
|
+
// has its own dir, so per-tool coverage is complete.
|
|
22578
|
+
...claudeSkillTargets(),
|
|
22579
|
+
{ id: "agy", label: "Antigravity", dir: join52(agyBackend.homeDir(), "skills"), available: agyBackend.isAvailable() },
|
|
22580
|
+
{ id: "codex", label: "Codex", dir: codexBackend.skillsDir(), available: codexBackend.isAvailable() },
|
|
22581
|
+
{ id: "opencode", label: "OpenCode", dir: opencodeBackend.skillsDir(), available: opencodeBackend.isAvailable() },
|
|
22582
|
+
// Cursor DOES have its own dir (~/.cursor/skills). `skills-cursor` next to
|
|
22583
|
+
// it is Cursor's bundled set — read-only, never an install target.
|
|
22584
|
+
{ id: "cursor", label: "Cursor", dir: join52(cursorHomeDir(), "skills"), available: cursorBackend.isAvailable() }
|
|
22585
|
+
];
|
|
22586
|
+
}
|
|
22587
|
+
function isManaged(dir) {
|
|
22588
|
+
return existsSync47(join52(dir, MARKER));
|
|
22589
|
+
}
|
|
22590
|
+
function installSkills(opts = {}) {
|
|
22591
|
+
const onlyAvailable = opts.onlyAvailable ?? true;
|
|
22592
|
+
const src = skillsSourceDir();
|
|
22593
|
+
const names = bundledSkillNames();
|
|
22594
|
+
const v = version();
|
|
22595
|
+
const stamp = skillStamp();
|
|
22596
|
+
const perTarget = [];
|
|
22597
|
+
for (const t of skillTargets()) {
|
|
22598
|
+
const installed = [];
|
|
22599
|
+
const skippedUserOwned = [];
|
|
22600
|
+
if (onlyAvailable && !t.available) {
|
|
22601
|
+
perTarget.push({ ...t, installed, skippedUserOwned });
|
|
22602
|
+
continue;
|
|
22603
|
+
}
|
|
22604
|
+
for (const name of names) {
|
|
22605
|
+
const dest = join52(t.dir, name);
|
|
22606
|
+
if (existsSync47(dest) && !isManaged(dest)) {
|
|
22607
|
+
skippedUserOwned.push(name);
|
|
22608
|
+
continue;
|
|
22609
|
+
}
|
|
22610
|
+
mkdirSync15(t.dir, { recursive: true });
|
|
22611
|
+
rmSync8(dest, { recursive: true, force: true });
|
|
22612
|
+
cpSync(join52(src, name), dest, { recursive: true });
|
|
22613
|
+
writeFileSync13(join52(dest, MARKER), `${stamp}
|
|
22614
|
+
`);
|
|
22615
|
+
installed.push(name);
|
|
22616
|
+
}
|
|
22617
|
+
perTarget.push({ ...t, installed, skippedUserOwned });
|
|
22618
|
+
}
|
|
22619
|
+
return { version: v, perTarget };
|
|
22620
|
+
}
|
|
22621
|
+
function uninstallSkills() {
|
|
22622
|
+
const names = new Set(bundledSkillNames());
|
|
22623
|
+
const perTarget = [];
|
|
22624
|
+
for (const t of skillTargets()) {
|
|
22625
|
+
const removed = [];
|
|
22626
|
+
if (!existsSync47(t.dir)) {
|
|
22627
|
+
perTarget.push({ id: t.id, label: t.label, removed });
|
|
22628
|
+
continue;
|
|
22629
|
+
}
|
|
22630
|
+
for (const entry of readdirSync34(t.dir, { withFileTypes: true })) {
|
|
22631
|
+
if (!entry.isDirectory()) continue;
|
|
22632
|
+
const dir = join52(t.dir, entry.name);
|
|
22633
|
+
if (isManaged(dir) && (names.has(entry.name) || entry.name.startsWith("chat-recall"))) {
|
|
22634
|
+
rmSync8(dir, { recursive: true, force: true });
|
|
22635
|
+
removed.push(entry.name);
|
|
22636
|
+
}
|
|
22637
|
+
}
|
|
22638
|
+
perTarget.push({ id: t.id, label: t.label, removed });
|
|
22639
|
+
}
|
|
22640
|
+
return { perTarget };
|
|
22641
|
+
}
|
|
22642
|
+
function skillsNeedRefresh() {
|
|
22643
|
+
const cur = skillStamp();
|
|
22644
|
+
const names = bundledSkillNames();
|
|
22645
|
+
if (names.length === 0) return false;
|
|
22646
|
+
for (const t of skillTargets()) {
|
|
22647
|
+
if (!t.available) continue;
|
|
22648
|
+
for (const name of names) {
|
|
22649
|
+
const marker = join52(t.dir, name, MARKER);
|
|
22650
|
+
if (!existsSync47(marker)) return true;
|
|
22651
|
+
try {
|
|
22652
|
+
if (readFileSync42(marker, "utf-8").trim() !== cur) return true;
|
|
22653
|
+
} catch {
|
|
22654
|
+
return true;
|
|
22655
|
+
}
|
|
22656
|
+
}
|
|
22657
|
+
}
|
|
22658
|
+
return false;
|
|
22659
|
+
}
|
|
22660
|
+
function skillStatus() {
|
|
22661
|
+
const names = bundledSkillNames();
|
|
22662
|
+
const cur = skillStamp();
|
|
22663
|
+
return skillTargets().map((t) => {
|
|
22664
|
+
let installed = 0;
|
|
22665
|
+
let ver = null;
|
|
22666
|
+
for (const name of names) {
|
|
22667
|
+
const marker = join52(t.dir, name, MARKER);
|
|
22668
|
+
if (existsSync47(marker)) {
|
|
22669
|
+
installed++;
|
|
22670
|
+
try {
|
|
22671
|
+
ver = readFileSync42(marker, "utf-8").trim();
|
|
22672
|
+
} catch {
|
|
22673
|
+
}
|
|
22674
|
+
}
|
|
22675
|
+
}
|
|
22676
|
+
return { id: t.id, label: t.label, available: t.available, installed, version: installed === names.length ? ver : installed ? `${ver} (partial)` : null };
|
|
22677
|
+
}).filter((s) => s.available || s.installed > 0);
|
|
22678
|
+
}
|
|
22679
|
+
var MARKER;
|
|
22680
|
+
var init_install_skills = __esm({
|
|
22681
|
+
"src/install-skills.ts"() {
|
|
22682
|
+
"use strict";
|
|
22683
|
+
init_tool_paths();
|
|
22684
|
+
init_claude2();
|
|
22685
|
+
init_opencode();
|
|
22686
|
+
init_codex2();
|
|
22687
|
+
init_agy();
|
|
22688
|
+
init_cursor();
|
|
22689
|
+
init_tool_paths();
|
|
22690
|
+
MARKER = ".chat-recall-managed";
|
|
22691
|
+
}
|
|
22692
|
+
});
|
|
22693
|
+
|
|
22522
22694
|
// src/mcp.ts
|
|
22523
22695
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
22524
22696
|
import { spawn as spawn3 } from "child_process";
|
|
@@ -22639,6 +22811,107 @@ function socketPathFromArgv(argv) {
|
|
|
22639
22811
|
return v && !v.startsWith("--") ? v : void 0;
|
|
22640
22812
|
}
|
|
22641
22813
|
|
|
22814
|
+
// src/relay-lifecycle.ts
|
|
22815
|
+
var PARENT_POLL_MS = 5e3;
|
|
22816
|
+
function pidAlive(pid) {
|
|
22817
|
+
try {
|
|
22818
|
+
process.kill(pid, 0);
|
|
22819
|
+
return true;
|
|
22820
|
+
} catch (err) {
|
|
22821
|
+
return err.code === "EPERM";
|
|
22822
|
+
}
|
|
22823
|
+
}
|
|
22824
|
+
var processProbe = {
|
|
22825
|
+
ppid: () => process.ppid,
|
|
22826
|
+
alive: pidAlive
|
|
22827
|
+
};
|
|
22828
|
+
function parentGone(originalPpid, probe) {
|
|
22829
|
+
if (probe.ppid() !== originalPpid) return true;
|
|
22830
|
+
return !probe.alive(originalPpid);
|
|
22831
|
+
}
|
|
22832
|
+
function watchParent(onGone, opts = {}) {
|
|
22833
|
+
const probe = opts.probe ?? processProbe;
|
|
22834
|
+
const original = probe.ppid();
|
|
22835
|
+
if (original <= 1) return () => {
|
|
22836
|
+
};
|
|
22837
|
+
const timer = setInterval(() => {
|
|
22838
|
+
if (!parentGone(original, probe)) return;
|
|
22839
|
+
clearInterval(timer);
|
|
22840
|
+
onGone();
|
|
22841
|
+
}, opts.intervalMs ?? PARENT_POLL_MS);
|
|
22842
|
+
timer.unref?.();
|
|
22843
|
+
return () => clearInterval(timer);
|
|
22844
|
+
}
|
|
22845
|
+
function onInputFinished(input, onEnd) {
|
|
22846
|
+
let fired = false;
|
|
22847
|
+
const fire = () => {
|
|
22848
|
+
if (fired) return;
|
|
22849
|
+
fired = true;
|
|
22850
|
+
onEnd();
|
|
22851
|
+
};
|
|
22852
|
+
input.once("end", fire);
|
|
22853
|
+
input.once("close", fire);
|
|
22854
|
+
input.once("error", fire);
|
|
22855
|
+
}
|
|
22856
|
+
|
|
22857
|
+
// src/sync-supervisor.ts
|
|
22858
|
+
function createSyncSupervisor(opts) {
|
|
22859
|
+
let owner = null;
|
|
22860
|
+
let inFlight = false;
|
|
22861
|
+
let tookOver = false;
|
|
22862
|
+
const log6 = opts.log ?? (() => {
|
|
22863
|
+
});
|
|
22864
|
+
const serviceRunning = () => {
|
|
22865
|
+
try {
|
|
22866
|
+
return opts.serviceRunning();
|
|
22867
|
+
} catch {
|
|
22868
|
+
return false;
|
|
22869
|
+
}
|
|
22870
|
+
};
|
|
22871
|
+
const check = async () => {
|
|
22872
|
+
if (serviceRunning()) {
|
|
22873
|
+
if (owner !== "service") {
|
|
22874
|
+
log6(owner === "mcp" ? "watch service is running again \u2014 it owns sync; MCP background sync stands by" : "watch service active \u2014 MCP will not run background sync (the service syncs)");
|
|
22875
|
+
}
|
|
22876
|
+
owner = "service";
|
|
22877
|
+
return;
|
|
22878
|
+
}
|
|
22879
|
+
const scope = owner === "mcp" ? "changed" : "full";
|
|
22880
|
+
if (owner !== "mcp") {
|
|
22881
|
+
log6(owner === "service" ? "watch service is no longer running \u2014 MCP takes over background sync" : "no watch service running \u2014 MCP runs background sync");
|
|
22882
|
+
if (!tookOver) {
|
|
22883
|
+
tookOver = true;
|
|
22884
|
+
opts.onFirstTakeover?.();
|
|
22885
|
+
}
|
|
22886
|
+
}
|
|
22887
|
+
owner = "mcp";
|
|
22888
|
+
if (inFlight) return;
|
|
22889
|
+
inFlight = true;
|
|
22890
|
+
try {
|
|
22891
|
+
await opts.tick(scope);
|
|
22892
|
+
} catch {
|
|
22893
|
+
} finally {
|
|
22894
|
+
inFlight = false;
|
|
22895
|
+
}
|
|
22896
|
+
};
|
|
22897
|
+
const first = setTimeout(() => {
|
|
22898
|
+
void check();
|
|
22899
|
+
}, opts.firstCheckMs);
|
|
22900
|
+
first.unref?.();
|
|
22901
|
+
const every = setInterval(() => {
|
|
22902
|
+
void check();
|
|
22903
|
+
}, opts.intervalMs);
|
|
22904
|
+
every.unref?.();
|
|
22905
|
+
return {
|
|
22906
|
+
check,
|
|
22907
|
+
owner: () => owner,
|
|
22908
|
+
stop: () => {
|
|
22909
|
+
clearTimeout(first);
|
|
22910
|
+
clearInterval(every);
|
|
22911
|
+
}
|
|
22912
|
+
};
|
|
22913
|
+
}
|
|
22914
|
+
|
|
22642
22915
|
// src/mcp.ts
|
|
22643
22916
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
22644
22917
|
|
|
@@ -23553,7 +23826,7 @@ function sanitizeQuery(query) {
|
|
|
23553
23826
|
|
|
23554
23827
|
// ../engine/dist/core/write-ahead-log.js
|
|
23555
23828
|
init_paths();
|
|
23556
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync5, appendFileSync, openSync as
|
|
23829
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync5, appendFileSync, openSync as openSync8, closeSync as closeSync8, chmodSync as chmodSync3 } from "fs";
|
|
23557
23830
|
import { join as join20 } from "path";
|
|
23558
23831
|
var REDACT_KEYS = /* @__PURE__ */ new Set([
|
|
23559
23832
|
"content",
|
|
@@ -23579,8 +23852,8 @@ var WriteAheadLog = class {
|
|
|
23579
23852
|
}
|
|
23580
23853
|
this.walPath = join20(dir, "write_log.jsonl");
|
|
23581
23854
|
if (!existsSync17(this.walPath)) {
|
|
23582
|
-
const fd =
|
|
23583
|
-
|
|
23855
|
+
const fd = openSync8(this.walPath, "w", 384);
|
|
23856
|
+
closeSync8(fd);
|
|
23584
23857
|
}
|
|
23585
23858
|
}
|
|
23586
23859
|
/**
|
|
@@ -28371,12 +28644,6 @@ function startBackgroundSync() {
|
|
|
28371
28644
|
console.error("[mcp] background sync tick failed:", err instanceof Error ? err.message : err);
|
|
28372
28645
|
}
|
|
28373
28646
|
};
|
|
28374
|
-
setInterval(() => {
|
|
28375
|
-
void tick("changed");
|
|
28376
|
-
}, SYNC_TICK_MS).unref();
|
|
28377
|
-
setTimeout(() => {
|
|
28378
|
-
void tick("full");
|
|
28379
|
-
}, 15e3).unref();
|
|
28380
28647
|
const updateTick = async () => {
|
|
28381
28648
|
try {
|
|
28382
28649
|
const { refreshUpdateCheck: refreshUpdateCheck2, updateNotice: updateNotice3 } = await Promise.resolve().then(() => (init_update_notice(), update_notice_exports));
|
|
@@ -28386,12 +28653,27 @@ function startBackgroundSync() {
|
|
|
28386
28653
|
} catch {
|
|
28387
28654
|
}
|
|
28388
28655
|
};
|
|
28389
|
-
|
|
28390
|
-
|
|
28391
|
-
|
|
28392
|
-
|
|
28393
|
-
|
|
28394
|
-
|
|
28656
|
+
const startUpdateProbe = () => {
|
|
28657
|
+
setTimeout(() => {
|
|
28658
|
+
void updateTick();
|
|
28659
|
+
}, 5e3).unref();
|
|
28660
|
+
setInterval(() => {
|
|
28661
|
+
void updateTick();
|
|
28662
|
+
}, 6 * 60 * 60 * 1e3).unref();
|
|
28663
|
+
};
|
|
28664
|
+
let isServiceRunning2 = null;
|
|
28665
|
+
createSyncSupervisor({
|
|
28666
|
+
serviceRunning: () => isServiceRunning2?.() ?? false,
|
|
28667
|
+
tick,
|
|
28668
|
+
intervalMs: SYNC_TICK_MS,
|
|
28669
|
+
firstCheckMs: 15e3,
|
|
28670
|
+
onFirstTakeover: startUpdateProbe,
|
|
28671
|
+
log: (msg) => console.error(`[mcp] ${msg}`)
|
|
28672
|
+
});
|
|
28673
|
+
void Promise.resolve().then(() => (init_service_installer(), service_installer_exports)).then((m) => {
|
|
28674
|
+
isServiceRunning2 = m.isServiceRunning;
|
|
28675
|
+
}).catch(() => {
|
|
28676
|
+
});
|
|
28395
28677
|
}
|
|
28396
28678
|
function installCrashGuards() {
|
|
28397
28679
|
process.on("unhandledRejection", (reason) => {
|
|
@@ -28404,7 +28686,7 @@ function installCrashGuards() {
|
|
|
28404
28686
|
reportClientEvent2("mcp_crash", { message: err.stack || err.message });
|
|
28405
28687
|
});
|
|
28406
28688
|
}
|
|
28407
|
-
var RELAY_VERSION = true ? "0.7.
|
|
28689
|
+
var RELAY_VERSION = true ? "0.7.1" : "0.0.0";
|
|
28408
28690
|
function daemonIdleSecs() {
|
|
28409
28691
|
const raw = process.env.CHAT_RECALL_DAEMON_IDLE_SECS;
|
|
28410
28692
|
if (raw === void 0) return 900;
|
|
@@ -28509,6 +28791,9 @@ async function main() {
|
|
|
28509
28791
|
} else {
|
|
28510
28792
|
const transport2 = new StdioServerTransport();
|
|
28511
28793
|
await createMcpServer().connect(transport2);
|
|
28794
|
+
const leave = () => process.exit(0);
|
|
28795
|
+
onInputFinished(process.stdin, leave);
|
|
28796
|
+
watchParent(leave);
|
|
28512
28797
|
}
|
|
28513
28798
|
void (async () => {
|
|
28514
28799
|
try {
|
|
@@ -28529,16 +28814,6 @@ async function main() {
|
|
|
28529
28814
|
}
|
|
28530
28815
|
} catch {
|
|
28531
28816
|
}
|
|
28532
|
-
|
|
28533
|
-
try {
|
|
28534
|
-
const { isServiceRunning: isServiceRunning2 } = await Promise.resolve().then(() => (init_service_installer(), service_installer_exports));
|
|
28535
|
-
daemonRunning = isServiceRunning2();
|
|
28536
|
-
} catch {
|
|
28537
|
-
}
|
|
28538
|
-
if (daemonRunning) {
|
|
28539
|
-
console.error("[mcp] watch daemon active \u2014 MCP will not run background sync (keeps the tool server lightweight; the daemon syncs).");
|
|
28540
|
-
} else {
|
|
28541
|
-
startBackgroundSync();
|
|
28542
|
-
}
|
|
28817
|
+
startBackgroundSync();
|
|
28543
28818
|
}
|
|
28544
28819
|
main().catch(console.error);
|