chat-recall 0.6.8 → 0.7.0
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/README.md +2 -2
- package/dist/cli.js +1054 -1397
- package/dist/cli.js.map +1 -1
- package/dist/escalate.js +2 -2
- package/dist/escalate.js.map +1 -1
- package/dist/mcp-relay.js +1 -1
- package/dist/mcp.js +2283 -1940
- package/dist/scan-worker.js +329 -30
- package/dist/scan-worker.js.map +1 -1
- package/dist/sync-client.d.ts +13 -0
- package/dist/sync-client.d.ts.map +1 -1
- package/dist/sync-client.js +38 -4
- package/dist/sync-client.js.map +1 -1
- package/dist/watch.js +1110 -1499
- package/package.json +1 -1
- package/skills/chat-recall/SKILL.md +2 -1
- package/skills/chat-recall-memory/SKILL.md +15 -0
package/dist/watch.js
CHANGED
|
@@ -115,6 +115,25 @@ var init_tool_backend = __esm({
|
|
|
115
115
|
}
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
+
// ../engine/dist/parsers/banners.js
|
|
119
|
+
function stripInjectedBanners(text) {
|
|
120
|
+
let result = text;
|
|
121
|
+
for (const re of INJECTED_BANNERS)
|
|
122
|
+
result = result.replace(re, " ");
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
var INJECTED_BANNERS;
|
|
126
|
+
var init_banners = __esm({
|
|
127
|
+
"../engine/dist/parsers/banners.js"() {
|
|
128
|
+
"use strict";
|
|
129
|
+
INJECTED_BANNERS = [
|
|
130
|
+
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
131
|
+
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
132
|
+
/API Error:[^\n]{0,120}/g
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
118
137
|
// ../engine/dist/core/project-path-match.js
|
|
119
138
|
function canonicalProjectPath(p) {
|
|
120
139
|
return (p || "").trim().replace(/\\/g, "/").replace(/[-_]/g, "/").replace(/\/{2,}/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -5346,929 +5365,291 @@ var init_tool_paths = __esm({
|
|
|
5346
5365
|
}
|
|
5347
5366
|
});
|
|
5348
5367
|
|
|
5349
|
-
// ../engine/dist/core/
|
|
5350
|
-
import {
|
|
5351
|
-
function
|
|
5352
|
-
|
|
5353
|
-
if (raw == null)
|
|
5354
|
-
return null;
|
|
5355
|
-
if (rule.where && !rule.where(raw))
|
|
5356
|
-
return null;
|
|
5357
|
-
return raw;
|
|
5368
|
+
// ../engine/dist/core/project-dir-name.js
|
|
5369
|
+
import { readdirSync as readdirSync4 } from "node:fs";
|
|
5370
|
+
function looksWindowsEncoded(dirName) {
|
|
5371
|
+
return /^[A-Za-z]--/.test(dirName);
|
|
5358
5372
|
}
|
|
5359
|
-
function
|
|
5360
|
-
if (
|
|
5361
|
-
return
|
|
5362
|
-
if (
|
|
5363
|
-
|
|
5364
|
-
|
|
5373
|
+
function decodeProjectDirName(dirName) {
|
|
5374
|
+
if (!dirName)
|
|
5375
|
+
return "";
|
|
5376
|
+
if (looksWindowsEncoded(dirName)) {
|
|
5377
|
+
const drive = dirName[0].toUpperCase();
|
|
5378
|
+
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
5379
|
+
return `${drive}:\\${rest}`;
|
|
5380
|
+
}
|
|
5381
|
+
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
5365
5382
|
}
|
|
5366
|
-
function
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
continue;
|
|
5382
|
-
}
|
|
5383
|
-
ranges.push({ start: winStart + tm.index, end: winStart + tm.index + tm[0].length });
|
|
5383
|
+
function resolveProjectDirName(dirName, deps = {}) {
|
|
5384
|
+
const structural = decodeProjectDirName(dirName);
|
|
5385
|
+
if (!dirName)
|
|
5386
|
+
return structural;
|
|
5387
|
+
if (looksWindowsEncoded(dirName))
|
|
5388
|
+
return structural;
|
|
5389
|
+
const readdir3 = deps.readdir ?? ((p) => readdirSync4(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name));
|
|
5390
|
+
const encodeName = (name) => name.replace(/[-_.]/g, "-");
|
|
5391
|
+
let remaining = dirName.replace(/^-/, "");
|
|
5392
|
+
let current = "/";
|
|
5393
|
+
while (remaining) {
|
|
5394
|
+
let children;
|
|
5395
|
+
try {
|
|
5396
|
+
children = readdir3(current);
|
|
5397
|
+
} catch {
|
|
5384
5398
|
break;
|
|
5385
5399
|
}
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5400
|
+
let best = "";
|
|
5401
|
+
for (const child of children) {
|
|
5402
|
+
const encoded = encodeName(child);
|
|
5403
|
+
if (!encoded || encoded.length < best.length)
|
|
5404
|
+
continue;
|
|
5405
|
+
if (!remaining.startsWith(encoded))
|
|
5406
|
+
continue;
|
|
5407
|
+
const next = remaining[encoded.length];
|
|
5408
|
+
if (next !== void 0 && next !== "-")
|
|
5409
|
+
continue;
|
|
5410
|
+
if (encoded.length > best.length)
|
|
5411
|
+
best = child;
|
|
5394
5412
|
}
|
|
5395
|
-
|
|
5413
|
+
if (!best)
|
|
5414
|
+
break;
|
|
5415
|
+
current = current === "/" ? `/${best}` : `${current}/${best}`;
|
|
5416
|
+
remaining = remaining.slice(encodeName(best).length).replace(/^-/, "");
|
|
5396
5417
|
}
|
|
5397
|
-
return
|
|
5398
|
-
}
|
|
5399
|
-
function isEnvRedactionRequested() {
|
|
5400
|
-
const v = process.env.CHAT_RECALL_REDACT_INDEX;
|
|
5401
|
-
if (v === void 0)
|
|
5402
|
-
return null;
|
|
5403
|
-
return v === "1" || v === "true" || v === "yes";
|
|
5418
|
+
return remaining ? structural : current;
|
|
5404
5419
|
}
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
mtimeMs = statSync3(settingsFilePath()).mtimeMs;
|
|
5409
|
-
} catch {
|
|
5420
|
+
var init_project_dir_name = __esm({
|
|
5421
|
+
"../engine/dist/core/project-dir-name.js"() {
|
|
5422
|
+
"use strict";
|
|
5410
5423
|
}
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5424
|
+
});
|
|
5425
|
+
|
|
5426
|
+
// ../engine/dist/core/model-pricing.js
|
|
5427
|
+
function pricingFor(modelId) {
|
|
5428
|
+
if (!modelId)
|
|
5429
|
+
return null;
|
|
5430
|
+
const lower = modelId.toLowerCase();
|
|
5431
|
+
let best = null;
|
|
5432
|
+
let bestLen = -1;
|
|
5433
|
+
for (const [prefix, entry] of Object.entries(TABLE)) {
|
|
5434
|
+
if (lower.startsWith(prefix.toLowerCase()) && prefix.length > bestLen) {
|
|
5435
|
+
best = entry;
|
|
5436
|
+
bestLen = prefix.length;
|
|
5423
5437
|
}
|
|
5424
|
-
} catch {
|
|
5425
|
-
}
|
|
5426
|
-
cache = { mtimeMs, enabled, rules: [...DEFAULT_REDACTION_RULES, ...extra] };
|
|
5427
|
-
return cache;
|
|
5428
|
-
}
|
|
5429
|
-
function compileServerRule(spec) {
|
|
5430
|
-
const name = spec.name || "(unnamed)";
|
|
5431
|
-
if (!spec.regex)
|
|
5432
|
-
return { name, reason: "empty pattern" };
|
|
5433
|
-
if (spec.regex.length > MAX_PATTERN_LEN)
|
|
5434
|
-
return { name, reason: `pattern longer than ${MAX_PATTERN_LEN} chars` };
|
|
5435
|
-
let re;
|
|
5436
|
-
try {
|
|
5437
|
-
const flags = "g" + (spec.flags || "").replace(/[^ims]/g, "");
|
|
5438
|
-
re = new RegExp(spec.regex, flags);
|
|
5439
|
-
} catch (e) {
|
|
5440
|
-
return { name, reason: `invalid regex: ${e instanceof Error ? e.message : e}` };
|
|
5441
5438
|
}
|
|
5442
|
-
|
|
5443
|
-
return { name, reason: "matches the empty string (would redact everything)" };
|
|
5444
|
-
re.lastIndex = 0;
|
|
5445
|
-
if (re.test(CANARY))
|
|
5446
|
-
return { name, reason: "matches benign text \u2014 too broad" };
|
|
5447
|
-
re.lastIndex = 0;
|
|
5448
|
-
return { label: `${spec.source === "pack" ? "pack" : "tenant"}:${name}`, pattern: re };
|
|
5439
|
+
return best;
|
|
5449
5440
|
}
|
|
5450
|
-
function
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
for (const
|
|
5454
|
-
if (
|
|
5455
|
-
rejected.push({ name: spec.name || "(unnamed)", reason: `pack exceeds ${MAX_PACK_RULES} rules` });
|
|
5441
|
+
function estimateCostUsdOrNull(modelsUsed, tokens) {
|
|
5442
|
+
let best = null;
|
|
5443
|
+
let bestRate = -1;
|
|
5444
|
+
for (const m of modelsUsed) {
|
|
5445
|
+
if (!m || m === "<synthetic>")
|
|
5456
5446
|
continue;
|
|
5447
|
+
const p = pricingFor(m);
|
|
5448
|
+
if (p && p.output > bestRate) {
|
|
5449
|
+
best = p;
|
|
5450
|
+
bestRate = p.output;
|
|
5457
5451
|
}
|
|
5458
|
-
const out = compileServerRule(spec);
|
|
5459
|
-
if ("reason" in out)
|
|
5460
|
-
rejected.push(out);
|
|
5461
|
-
else
|
|
5462
|
-
rules.push(out);
|
|
5463
|
-
}
|
|
5464
|
-
const version = pack.version || "";
|
|
5465
|
-
serverPack = { version, rules };
|
|
5466
|
-
return { version, accepted: rules.length, rejected };
|
|
5467
|
-
}
|
|
5468
|
-
function serverRulePackVersion() {
|
|
5469
|
-
return serverPack ? serverPack.version || "unversioned" : null;
|
|
5470
|
-
}
|
|
5471
|
-
function activeRules() {
|
|
5472
|
-
const base2 = settingsView().rules;
|
|
5473
|
-
return serverPack && serverPack.rules.length > 0 ? [...base2, ...serverPack.rules] : base2;
|
|
5474
|
-
}
|
|
5475
|
-
function isRedactionEnabled() {
|
|
5476
|
-
const env = isEnvRedactionRequested();
|
|
5477
|
-
if (env !== null)
|
|
5478
|
-
return env;
|
|
5479
|
-
return settingsView().enabled;
|
|
5480
|
-
}
|
|
5481
|
-
function redactSecrets(text, opts = {}) {
|
|
5482
|
-
if (!opts.force && !isRedactionEnabled())
|
|
5483
|
-
return text;
|
|
5484
|
-
if (!text)
|
|
5485
|
-
return text;
|
|
5486
|
-
const rules = opts.rules || activeRules();
|
|
5487
|
-
let out = text;
|
|
5488
|
-
for (const r of rules) {
|
|
5489
|
-
out = out.replace(r.pattern, (...args) => {
|
|
5490
|
-
const whole = args[0];
|
|
5491
|
-
const m = args.slice(0, args.length);
|
|
5492
|
-
const secret = secretOf(r, m);
|
|
5493
|
-
if (secret == null)
|
|
5494
|
-
return whole;
|
|
5495
|
-
if (opts.count)
|
|
5496
|
-
opts.count.redactions++;
|
|
5497
|
-
return whole.slice(0, whole.length - secret.length) + `[REDACTED:${r.label}]`;
|
|
5498
|
-
});
|
|
5499
|
-
}
|
|
5500
|
-
const ctx = findContextualSecrets(out);
|
|
5501
|
-
for (let i = ctx.length - 1; i >= 0; i--) {
|
|
5502
|
-
const { start, end } = ctx[i];
|
|
5503
|
-
if (opts.count)
|
|
5504
|
-
opts.count.redactions++;
|
|
5505
|
-
out = out.slice(0, start) + "[REDACTED:secret-context]" + out.slice(end);
|
|
5506
5452
|
}
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
if (s.length <= 4)
|
|
5513
|
-
return "*".repeat(s.length);
|
|
5514
|
-
return "*".repeat(Math.min(s.length - 4, 60)) + s.slice(-4);
|
|
5453
|
+
if (!best)
|
|
5454
|
+
return null;
|
|
5455
|
+
const nonCachedInput = Math.max(0, tokens.inputTokens - tokens.cacheReadTokens - tokens.cacheCreationTokens);
|
|
5456
|
+
const cost = nonCachedInput / 1e6 * best.input + tokens.outputTokens / 1e6 * best.output + tokens.cacheReadTokens / 1e6 * best.cacheRead + tokens.cacheCreationTokens / 1e6 * best.cacheCreate;
|
|
5457
|
+
return Math.round(cost * 100) / 100;
|
|
5515
5458
|
}
|
|
5516
|
-
function
|
|
5517
|
-
|
|
5518
|
-
const key2 = pattern.source + "\0" + flags;
|
|
5519
|
-
let re = globalRegexCache.get(key2);
|
|
5520
|
-
if (!re) {
|
|
5521
|
-
re = new RegExp(pattern.source, flags);
|
|
5522
|
-
globalRegexCache.set(key2, re);
|
|
5523
|
-
}
|
|
5524
|
-
return re;
|
|
5459
|
+
function estimateCostUsd(modelsUsed, tokens) {
|
|
5460
|
+
return estimateCostUsdOrNull(modelsUsed, tokens) ?? 0;
|
|
5525
5461
|
}
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5462
|
+
var TABLE, METADATA_VERSION;
|
|
5463
|
+
var init_model_pricing = __esm({
|
|
5464
|
+
"../engine/dist/core/model-pricing.js"() {
|
|
5465
|
+
"use strict";
|
|
5466
|
+
TABLE = {
|
|
5467
|
+
// Anthropic — Claude 4.x family
|
|
5468
|
+
"claude-opus-4-7": {
|
|
5469
|
+
input: 15,
|
|
5470
|
+
output: 75,
|
|
5471
|
+
cacheRead: 1.5,
|
|
5472
|
+
cacheCreate: 18.75,
|
|
5473
|
+
lastReviewed: "2026-01-15",
|
|
5474
|
+
source: "Anthropic public pricing (Opus 4.x)"
|
|
5475
|
+
},
|
|
5476
|
+
"claude-opus-4-6": {
|
|
5477
|
+
input: 15,
|
|
5478
|
+
output: 75,
|
|
5479
|
+
cacheRead: 1.5,
|
|
5480
|
+
cacheCreate: 18.75,
|
|
5481
|
+
lastReviewed: "2026-01-15",
|
|
5482
|
+
source: "Anthropic public pricing (Opus 4.x)"
|
|
5483
|
+
},
|
|
5484
|
+
"claude-opus-4": {
|
|
5485
|
+
input: 15,
|
|
5486
|
+
output: 75,
|
|
5487
|
+
cacheRead: 1.5,
|
|
5488
|
+
cacheCreate: 18.75,
|
|
5489
|
+
lastReviewed: "2026-01-15",
|
|
5490
|
+
source: "Anthropic public pricing (Opus 4.x)"
|
|
5491
|
+
},
|
|
5492
|
+
"claude-sonnet-4-6": {
|
|
5493
|
+
input: 3,
|
|
5494
|
+
output: 15,
|
|
5495
|
+
cacheRead: 0.3,
|
|
5496
|
+
cacheCreate: 3.75,
|
|
5497
|
+
lastReviewed: "2026-01-15",
|
|
5498
|
+
source: "Anthropic public pricing (Sonnet 4.x)"
|
|
5499
|
+
},
|
|
5500
|
+
"claude-sonnet-4": {
|
|
5501
|
+
input: 3,
|
|
5502
|
+
output: 15,
|
|
5503
|
+
cacheRead: 0.3,
|
|
5504
|
+
cacheCreate: 3.75,
|
|
5505
|
+
lastReviewed: "2026-01-15",
|
|
5506
|
+
source: "Anthropic public pricing (Sonnet 4.x)"
|
|
5507
|
+
},
|
|
5508
|
+
"claude-haiku-4-5": {
|
|
5509
|
+
input: 1,
|
|
5510
|
+
output: 5,
|
|
5511
|
+
cacheRead: 0.1,
|
|
5512
|
+
cacheCreate: 1.25,
|
|
5513
|
+
lastReviewed: "2026-01-15",
|
|
5514
|
+
source: "Anthropic public pricing (Haiku 4.5)"
|
|
5515
|
+
},
|
|
5516
|
+
// Anthropic — older Claude 3.x (kept for back-compat with historical transcripts)
|
|
5517
|
+
"claude-3-7-sonnet": {
|
|
5518
|
+
input: 3,
|
|
5519
|
+
output: 15,
|
|
5520
|
+
cacheRead: 0.3,
|
|
5521
|
+
cacheCreate: 3.75,
|
|
5522
|
+
lastReviewed: "2026-01-15",
|
|
5523
|
+
source: "Anthropic public pricing"
|
|
5524
|
+
},
|
|
5525
|
+
"claude-3-5-sonnet": {
|
|
5526
|
+
input: 3,
|
|
5527
|
+
output: 15,
|
|
5528
|
+
cacheRead: 0.3,
|
|
5529
|
+
cacheCreate: 3.75,
|
|
5530
|
+
lastReviewed: "2026-01-15",
|
|
5531
|
+
source: "Anthropic public pricing"
|
|
5532
|
+
},
|
|
5533
|
+
"claude-3-5-haiku": {
|
|
5534
|
+
input: 0.8,
|
|
5535
|
+
output: 4,
|
|
5536
|
+
cacheRead: 0.08,
|
|
5537
|
+
cacheCreate: 1,
|
|
5538
|
+
lastReviewed: "2026-01-15",
|
|
5539
|
+
source: "Anthropic public pricing"
|
|
5540
|
+
},
|
|
5541
|
+
"claude-3-opus": {
|
|
5542
|
+
input: 15,
|
|
5543
|
+
output: 75,
|
|
5544
|
+
cacheRead: 1.5,
|
|
5545
|
+
cacheCreate: 18.75,
|
|
5546
|
+
lastReviewed: "2026-01-15",
|
|
5547
|
+
source: "Anthropic public pricing"
|
|
5548
|
+
},
|
|
5549
|
+
// OpenAI — current GPT-* (used by Codex CLI)
|
|
5550
|
+
"gpt-5": {
|
|
5551
|
+
input: 1.25,
|
|
5552
|
+
output: 10,
|
|
5553
|
+
cacheRead: 0.125,
|
|
5554
|
+
cacheCreate: 1.25,
|
|
5555
|
+
lastReviewed: "2026-01-15",
|
|
5556
|
+
source: "OpenAI public pricing (GPT-5)"
|
|
5557
|
+
},
|
|
5558
|
+
"gpt-5-mini": {
|
|
5559
|
+
input: 0.25,
|
|
5560
|
+
output: 2,
|
|
5561
|
+
cacheRead: 0.025,
|
|
5562
|
+
cacheCreate: 0.25,
|
|
5563
|
+
lastReviewed: "2026-01-15",
|
|
5564
|
+
source: "OpenAI public pricing (GPT-5 Mini)"
|
|
5565
|
+
},
|
|
5566
|
+
"gpt-4o": {
|
|
5567
|
+
input: 2.5,
|
|
5568
|
+
output: 10,
|
|
5569
|
+
cacheRead: 1.25,
|
|
5570
|
+
cacheCreate: 2.5,
|
|
5571
|
+
lastReviewed: "2026-01-15",
|
|
5572
|
+
source: "OpenAI public pricing"
|
|
5573
|
+
},
|
|
5574
|
+
// Google Gemini — 2.x family (used by Gemini CLI)
|
|
5575
|
+
"gemini-2.5-pro": {
|
|
5576
|
+
input: 1.25,
|
|
5577
|
+
output: 10,
|
|
5578
|
+
cacheRead: 0.31,
|
|
5579
|
+
cacheCreate: 1.25,
|
|
5580
|
+
lastReviewed: "2026-01-15",
|
|
5581
|
+
source: "Google AI Studio public pricing"
|
|
5582
|
+
},
|
|
5583
|
+
"gemini-2.5-flash": {
|
|
5584
|
+
input: 0.3,
|
|
5585
|
+
output: 2.5,
|
|
5586
|
+
cacheRead: 0.075,
|
|
5587
|
+
cacheCreate: 0.3,
|
|
5588
|
+
lastReviewed: "2026-01-15",
|
|
5589
|
+
source: "Google AI Studio public pricing"
|
|
5565
5590
|
}
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
}
|
|
5591
|
+
};
|
|
5592
|
+
METADATA_VERSION = 3;
|
|
5569
5593
|
}
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5594
|
+
});
|
|
5595
|
+
|
|
5596
|
+
// ../engine/dist/parsers/session.js
|
|
5597
|
+
import { createReadStream, existsSync as existsSync5, readdirSync as readdirSync5, readFileSync as readFileSync2, statSync as statSync3, openSync, readSync, closeSync } from "fs";
|
|
5598
|
+
import { createInterface } from "readline";
|
|
5599
|
+
import { join as join5, basename as basename2 } from "path";
|
|
5600
|
+
function removeCodeBlocks(text) {
|
|
5601
|
+
let result = text.replace(/```[\s\S]*?```/g, "[code block]");
|
|
5602
|
+
result = result.replace(/`[^`]+`/g, "[code]");
|
|
5603
|
+
return result;
|
|
5604
|
+
}
|
|
5605
|
+
function extractKeyText(text, maxLength = 800) {
|
|
5606
|
+
let result = removeCodeBlocks(text);
|
|
5607
|
+
const boilerplate = [
|
|
5608
|
+
/^Let me /i,
|
|
5609
|
+
/^I'll /i,
|
|
5610
|
+
/^I will /i,
|
|
5611
|
+
/^Now I'll /i,
|
|
5612
|
+
/^Here's what /i
|
|
5613
|
+
];
|
|
5614
|
+
for (const pattern of boilerplate) {
|
|
5615
|
+
result = result.replace(pattern, "");
|
|
5573
5616
|
}
|
|
5574
|
-
|
|
5617
|
+
result = result.replace(/\s+/g, " ").trim();
|
|
5618
|
+
return result.slice(0, maxLength);
|
|
5575
5619
|
}
|
|
5576
|
-
function
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
mtimeMs = statSync3(settingsFilePath()).mtimeMs;
|
|
5580
|
-
} catch {
|
|
5620
|
+
function isValuableToolResult(content, toolName = "") {
|
|
5621
|
+
if (!content || content.length < 20) {
|
|
5622
|
+
return false;
|
|
5581
5623
|
}
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5624
|
+
const skipPatterns = [
|
|
5625
|
+
/^Tool ran without output/i,
|
|
5626
|
+
/^No (?:matches|results) found/i,
|
|
5627
|
+
/^File (?:created|updated|deleted)/i,
|
|
5628
|
+
/^Command completed/i,
|
|
5629
|
+
/^\s*$/
|
|
5630
|
+
];
|
|
5631
|
+
for (const pattern of skipPatterns) {
|
|
5632
|
+
if (pattern.test(content)) {
|
|
5633
|
+
return false;
|
|
5634
|
+
}
|
|
5590
5635
|
}
|
|
5591
|
-
|
|
5592
|
-
|
|
5636
|
+
if (["WebSearch", "WebFetch"].includes(toolName) || content.toLowerCase().includes("http")) {
|
|
5637
|
+
return true;
|
|
5638
|
+
}
|
|
5639
|
+
if (content.length > 5e3) {
|
|
5640
|
+
return false;
|
|
5641
|
+
}
|
|
5642
|
+
return true;
|
|
5593
5643
|
}
|
|
5594
|
-
function
|
|
5595
|
-
|
|
5644
|
+
function hasSubagentsDir(sessionPath) {
|
|
5645
|
+
const dir = sessionPath.slice(0, -6);
|
|
5646
|
+
return existsSync5(join5(dir, "subagents"));
|
|
5596
5647
|
}
|
|
5597
|
-
function
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache, privacyCache;
|
|
5603
|
-
var init_secret_redactor = __esm({
|
|
5604
|
-
"../engine/dist/core/secret-redactor.js"() {
|
|
5605
|
-
"use strict";
|
|
5606
|
-
init_settings();
|
|
5607
|
-
DEFAULT_REDACTION_RULES = [
|
|
5608
|
-
// AWS access tokens. Prefix-anchored: AKIA, ASIA, ABIA (long-term,
|
|
5609
|
-
// STS, EC2). Always exactly 16 hex/alphanumeric after the prefix.
|
|
5610
|
-
// NOTE: this matches only the access-key-ID, NOT the secret key value —
|
|
5611
|
-
// the `env-secret` rule below covers AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN.
|
|
5612
|
-
{ label: "aws-access-token", pattern: /\b(?:AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}\b/g },
|
|
5613
|
-
// AWS STS session tokens. These are long base64 blobs with NO `NAME=` context
|
|
5614
|
-
// when pasted bare into prose/code, so `env-secret` misses them — but they
|
|
5615
|
-
// reliably start with one of a handful of base64 prefixes (the encoded
|
|
5616
|
-
// `{"...` JSON header). Prefix-anchored → low false-positive. This is the
|
|
5617
|
-
// bare-value form that leaked (`search('IQoJEXAMPLEfakeSESSIONtokenNOTreal01234567890abcDEF==...')`).
|
|
5618
|
-
{ label: "aws-session-token", pattern: /\b(?:IQoJ|FwoG|FwoH|FQoG|FQoH|FwoD)[A-Za-z0-9/+]{40,}={0,2}/g },
|
|
5619
|
-
// Env/shell-assignment secrets — a VAR whose name ends in KEY/SECRET/TOKEN/
|
|
5620
|
-
// PASSWORD/CREDENTIAL, then `=`/`:`, then the value. Zero-width lookbehind so
|
|
5621
|
-
// only the VALUE is redacted (the var name stays for context). This is the
|
|
5622
|
-
// dominant real-world leak vector (`export` dumps, .env files, `curl -H`,
|
|
5623
|
-
// tool output) and is exactly what leaked AWS_SECRET_ACCESS_KEY and
|
|
5624
|
-
// AWS_SESSION_TOKEN in cleartext while the access-key-ID rule above caught
|
|
5625
|
-
// only the (least-sensitive) ID.
|
|
5626
|
-
// Suffix list deliberately broad: DB_PASS (our own helm chart's name!),
|
|
5627
|
-
// NPM_AUTH, SENTRY_DSN, SESSION/COOKIE secrets and BEARER vars all leaked
|
|
5628
|
-
// past the original KEY/SECRET/TOKEN/PASSWORD-only list. Values under 12
|
|
5629
|
-
// chars don't redact, so flag-ish vars (BYPASS=true) stay readable.
|
|
5630
|
-
// Context CONSUMED, secret in group 1 — see RedactionRule.secret. As a
|
|
5631
|
-
// lookbehind this was the second most expensive rule in the collector.
|
|
5632
|
-
{ label: "env-secret", secret: 1, pattern: /\b[A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PASS|PWD|CREDENTIAL|AUTH|DSN|SESSION|COOKIE|BEARER|SIGNATURE)S?["']?[ \t]{0,3}[:=][ \t]{0,3}["']?([A-Za-z0-9/+_.~=:@-]{12,})/g },
|
|
5633
|
-
// Credentials embedded in a connection URL: scheme://user:PASSWORD@host.
|
|
5634
|
-
// Redacts only the password segment (keeps scheme/user/host for context).
|
|
5635
|
-
//
|
|
5636
|
-
// Scheme-agnostic on purpose. The old rule allowlisted eight DB schemes, so
|
|
5637
|
-
// `https://user:pass@host`, `ssh://`, `ftp://`, `smtp://` and every other
|
|
5638
|
-
// userinfo URL walked through in cleartext — and a `jdbc:postgresql://…`
|
|
5639
|
-
// prefix broke the \b anchor for the one family it did cover. Any scheme
|
|
5640
|
-
// followed by userinfo is a credential, so match the shape, not a list.
|
|
5641
|
-
{ label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/]{1,64}:([^@\s/]{1,256})(?=@)/g },
|
|
5642
|
-
// Bare AWS secret-access-key VALUE: EXACTLY 40 base64 chars, word-bounded,
|
|
5643
|
-
// containing upper+lower+digit. This is the gitleaks heuristic — the mixed-case
|
|
5644
|
-
// requirement excludes 40-char lowercase-hex git SHAs, and the exact-40 bound
|
|
5645
|
-
// excludes longer blobs/tokens. It catches the value when it appears bare in
|
|
5646
|
-
// prose with NO `NAME=` and NO nearby context word (e.g. inside a markdown
|
|
5647
|
-
// table or quoted in analysis) — the residual leak path the env-secret and
|
|
5648
|
-
// contextual rules both miss. Placed AFTER env-secret/url-password so the
|
|
5649
|
-
// keyed/URL forms keep their more-specific labels.
|
|
5650
|
-
// The three stacked lookaheads each re-scanned the same 40 characters, which
|
|
5651
|
-
// made this the MOST expensive rule of all 106 the collector runs (13.1% of a
|
|
5652
|
-
// 29.5 MB scan). The mixed-case-plus-digit test is now one JS pass.
|
|
5653
|
-
{
|
|
5654
|
-
label: "aws-secret-key",
|
|
5655
|
-
secret: 1,
|
|
5656
|
-
pattern: /(?<![A-Za-z0-9/+])([A-Za-z0-9/+]{40})(?![A-Za-z0-9/+])/g,
|
|
5657
|
-
where: (v) => /[a-z]/.test(v) && /[A-Z]/.test(v) && /[0-9]/.test(v)
|
|
5658
|
-
},
|
|
5659
|
-
// GitHub personal access tokens.
|
|
5660
|
-
{ label: "github-pat", pattern: /\bghp_[A-Za-z0-9]{36}\b/g },
|
|
5661
|
-
// GitHub fine-grained PATs.
|
|
5662
|
-
{ label: "github-fine", pattern: /\bgithub_pat_[A-Za-z0-9_]{82}\b/g },
|
|
5663
|
-
// GitHub OAuth.
|
|
5664
|
-
{ label: "github-oauth", pattern: /\bgho_[A-Za-z0-9]{36}\b/g },
|
|
5665
|
-
// GitHub app + refresh.
|
|
5666
|
-
{ label: "github-app", pattern: /\b(?:ghs|ghu|ghr)_[A-Za-z0-9]{36}\b/g },
|
|
5667
|
-
// Slack bot/user/app tokens.
|
|
5668
|
-
{ label: "slack-token", pattern: /\bxox[abopr]-[A-Za-z0-9-]{10,}\b/g },
|
|
5669
|
-
// Slack incoming webhook URL.
|
|
5670
|
-
{ label: "slack-webhook", pattern: /\bhttps:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+\b/g },
|
|
5671
|
-
// Stripe live + test keys.
|
|
5672
|
-
{ label: "stripe-key", pattern: /\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g },
|
|
5673
|
-
// Anthropic.
|
|
5674
|
-
{ label: "anthropic-key", pattern: /\bsk-ant-[a-zA-Z0-9_-]{40,}\b/g },
|
|
5675
|
-
// OpenAI. Two shapes, deliberately kept apart. The classic key is
|
|
5676
|
-
// `sk-` + base62 with NO hyphens; the modern scoped keys carry an explicit
|
|
5677
|
-
// proj/svcacct/admin segment first. Allowing hyphens after a bare `sk-`
|
|
5678
|
-
// (which is what admitted sk-proj- in the first place) also matches ordinary
|
|
5679
|
-
// kebab-case text — `sk-fix-the-login-redirect-bug`, `.sk-button-primary`,
|
|
5680
|
-
// `sk-2024-01-01-backup` — and this corpus is full of branch names and CSS
|
|
5681
|
-
// classes. Requiring the segment keeps sk-proj- coverage without that.
|
|
5682
|
-
{ label: "openai-key", pattern: /\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{20,}\b|\bsk-[A-Za-z0-9]{20,}\b/g },
|
|
5683
|
-
// Google API key (AIza…).
|
|
5684
|
-
{ label: "google-api-key", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
5685
|
-
// Generic JWT — three base64url segments.
|
|
5686
|
-
{ label: "jwt", pattern: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g },
|
|
5687
|
-
// Private key blocks (PEM). The label is a free word run rather than a fixed
|
|
5688
|
-
// list, so ENCRYPTED PRIVATE KEY and PGP PRIVATE KEY BLOCK are covered
|
|
5689
|
-
// without another enumeration, and \1 forces END to name the same kind as
|
|
5690
|
-
// BEGIN.
|
|
5691
|
-
//
|
|
5692
|
-
// The body is [^-], NOT [\s\S]*?. That is a performance boundary, not a
|
|
5693
|
-
// style choice. An unanchored prefix with an unbounded lazy gap re-scans to
|
|
5694
|
-
// end-of-input from every candidate start, so text carrying many BEGIN
|
|
5695
|
-
// markers and no matching END costs O(n^2): 500KB of that measured 810ms
|
|
5696
|
-
// here, and this runs synchronously on the server's event loop over
|
|
5697
|
-
// tenant-supplied text (services/secret-rescan.ts). A PEM body is base64
|
|
5698
|
-
// plus headers and contains no '-', so excluding it makes the scan stop at
|
|
5699
|
-
// the next delimiter instead of at EOF — same matches, linear cost.
|
|
5700
|
-
{ label: "private-key", pattern: /-----BEGIN ([A-Z0-9 ]{0,32})PRIVATE KEY(?: BLOCK)?-----[^-]{0,10000}?-----END \1PRIVATE KEY(?: BLOCK)?-----/g },
|
|
5701
|
-
// PuTTY keys are not PEM. Match the Private-Lines payload — the actual key
|
|
5702
|
-
// material — rather than spanning the whole file, which would need the same
|
|
5703
|
-
// unbounded gap the rule above just removed. Line-anchored and base64-only,
|
|
5704
|
-
// so it cannot run away.
|
|
5705
|
-
{ label: "putty-key", pattern: /^Private-Lines:[ \t]*\d{1,4}[\r\n]+(?:[A-Za-z0-9+/=]{8,120}[\r\n]+){1,400}/gm },
|
|
5706
|
-
// npm tokens (uuid-shaped — overlap with our UUID filter; intentional).
|
|
5707
|
-
{ label: "npm-token", pattern: /\bnpm_[A-Za-z0-9]{36}\b/g },
|
|
5708
|
-
// .npmrc auth lines: //registry.npmjs.org/:_authToken=VALUE (the key is not
|
|
5709
|
-
// ALL-CAPS, so the env-secret rule above never matched it). The leading `:`
|
|
5710
|
-
// is required — it is what makes this npmrc syntax rather than any shell var
|
|
5711
|
-
// ending in _AUTH, which env-secret already owns and labels better.
|
|
5712
|
-
// [^\s"'`]+ so the closing quote is not swallowed, and a ${VAR} placeholder
|
|
5713
|
-
// is left alone — redacting it destroys a config example and hides nothing.
|
|
5714
|
-
// The rule the perf profile caught the wedged daemon inside: 98.94% of samples.
|
|
5715
|
-
{ label: "npmrc-auth", secret: 1, pattern: /:_(?:authToken|password|auth)[ \t]*=[ \t]*(?!\$\{)([^\s"'`]{12,})/gi },
|
|
5716
|
-
// HTTP Authorization headers. env-secret requires an ALL-CAPS name, and
|
|
5717
|
-
// `Authorization` is mixed case, so both Bearer and Basic walked straight
|
|
5718
|
-
// through — including short opaque tokens the contextual pass also misses
|
|
5719
|
-
// (it needs 32+ chars AND mixed-case-plus-digit).
|
|
5720
|
-
// Same two guards as npmrc-auth: stop at a quote, and skip the obvious
|
|
5721
|
-
// placeholders that fill documentation (<YOUR_TOKEN>, ${TOKEN}, xxx…).
|
|
5722
|
-
{ label: "auth-header", secret: 1, pattern: /\bauthorization[ \t]*:[ \t]*(?:bearer|basic|token)[ \t]+(?![<$])([^\s"'`<]{8,})/gi },
|
|
5723
|
-
// Vendor tokens with unambiguous prefixes. Each is a fixed literal, so a
|
|
5724
|
-
// false positive is essentially impossible and the cost of listing is low.
|
|
5725
|
-
{ label: "gitlab-pat", pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
|
|
5726
|
-
{ label: "slack-app-token", pattern: /\bxapp-\d-[A-Z0-9]{8,}-\d{10,}-[a-f0-9]{32,}\b/g },
|
|
5727
|
-
{ label: "sendgrid-key", pattern: /\bSG\.[A-Za-z0-9_-]{20,24}\.[A-Za-z0-9_-]{40,50}\b/g },
|
|
5728
|
-
// (?<![-\w]) so `cache-key-<md5>` is not read as a mailgun key.
|
|
5729
|
-
{ label: "mailgun-key", pattern: /(?<![-\w])key-[a-f0-9]{32}\b/g },
|
|
5730
|
-
{ label: "digitalocean-pat", pattern: /\bdop_v1_[a-f0-9]{64}\b/g },
|
|
5731
|
-
{ label: "huggingface-token", pattern: /\bhf_[A-Za-z0-9]{30,}\b/g },
|
|
5732
|
-
{ label: "shopify-token", pattern: /\bshp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}\b/g },
|
|
5733
|
-
{ label: "pypi-token", pattern: /\bpypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}\b/g },
|
|
5734
|
-
// No twilio-sid rule: AC…/SK… are Twilio SIDs, which are public account and
|
|
5735
|
-
// key identifiers, not the auth token. Redacting them hid nothing and
|
|
5736
|
-
// collided with 32-hex etags and MD5 sums.
|
|
5737
|
-
// No discord-bot-token rule either: the shape (word.word.word) matched
|
|
5738
|
-
// ordinary dotted symbols such as a.b.ApplicationContextProviderImpl.
|
|
5739
|
-
{ label: "telegram-bot-token", pattern: /\b\d{8,10}:AA[A-Za-z0-9_-]{32,}\b/g },
|
|
5740
|
-
{ label: "doppler-token", pattern: /\bdp\.(?:pt|st|sa|ct)\.[A-Za-z0-9_-]{20,}\b/g },
|
|
5741
|
-
// Azure Storage SAS signature — the `sig=` parameter is the actual secret.
|
|
5742
|
-
{ label: "azure-sas", secret: 1, pattern: /[?&]sig=([A-Za-z0-9%/+=]{20,})/g }
|
|
5743
|
-
];
|
|
5744
|
-
SECRET_CONTEXT_RE = /\b(?:secret|password|passwd|credential|access[ _-]?key|private[ _-]?key|api[ _-]?key|auth(?:oriz\w*)?|bearer|token)\b/gi;
|
|
5745
|
-
HIGH_ENTROPY_TOKEN_RE = /[A-Za-z0-9/+_-]{32,}/g;
|
|
5746
|
-
cache = null;
|
|
5747
|
-
CANARY = "the quick brown fox jumps over the lazy dog 0123456789 commit 8ba1f109551bd432803012645ac136ddd475d0fb src/index.ts:42";
|
|
5748
|
-
MAX_PACK_RULES = 200;
|
|
5749
|
-
MAX_PATTERN_LEN = 512;
|
|
5750
|
-
serverPack = null;
|
|
5751
|
-
globalRegexCache = /* @__PURE__ */ new Map();
|
|
5752
|
-
privacyCache = null;
|
|
5753
|
-
}
|
|
5754
|
-
});
|
|
5755
|
-
|
|
5756
|
-
// ../engine/dist/parsers/chunker.js
|
|
5757
|
-
function stripInjectedBanners(text) {
|
|
5758
|
-
let result = text;
|
|
5759
|
-
for (const re of INJECTED_BANNERS)
|
|
5760
|
-
result = result.replace(re, " ");
|
|
5761
|
-
return result;
|
|
5762
|
-
}
|
|
5763
|
-
function cleanText(text) {
|
|
5764
|
-
let result = text.replace(/<system-reminder>.*?<\/system-reminder>/gs, "");
|
|
5765
|
-
result = stripInjectedBanners(result);
|
|
5766
|
-
result = result.replace(/\x1b\[[0-9;]*m/g, "");
|
|
5767
|
-
result = result.replace(/\s+/g, " ");
|
|
5768
|
-
return result.trim();
|
|
5769
|
-
}
|
|
5770
|
-
function windowText(text, maxChars, maxWindows = 12) {
|
|
5771
|
-
const clean = cleanText(text);
|
|
5772
|
-
if (clean.length <= maxChars)
|
|
5773
|
-
return clean ? [clean] : [];
|
|
5774
|
-
const out = [];
|
|
5775
|
-
const overlap = 80;
|
|
5776
|
-
const step = Math.max(1, maxChars - overlap);
|
|
5777
|
-
for (let i = 0; i < clean.length && out.length < maxWindows; i += step) {
|
|
5778
|
-
out.push(clean.slice(i, i + maxChars));
|
|
5779
|
-
}
|
|
5780
|
-
return out;
|
|
5781
|
-
}
|
|
5782
|
-
function chunkSession(entry, content, maxChunks = 80, maxTokensPerChunk = 500) {
|
|
5783
|
-
const chunks = [];
|
|
5784
|
-
const maxChars = maxTokensPerChunk * 4;
|
|
5785
|
-
const baseData = {
|
|
5786
|
-
sessionId: entry.sessionId,
|
|
5787
|
-
projectPath: entry.projectPath,
|
|
5788
|
-
created: entry.created,
|
|
5789
|
-
modified: entry.modified,
|
|
5790
|
-
mtime: entry.fileMtime,
|
|
5791
|
-
firstPrompt: entry.firstPrompt || content.firstPrompt,
|
|
5792
|
-
sourceFile: content.sessionPath
|
|
5793
|
-
};
|
|
5794
|
-
for (let i = 0; i < Math.min(2, content.summaries.length); i++) {
|
|
5795
|
-
const summary = content.summaries[i];
|
|
5796
|
-
if (!summary?.trim())
|
|
5797
|
-
continue;
|
|
5798
|
-
const chunkText = cleanText(summary.slice(0, maxChars));
|
|
5799
|
-
if (chunkText.length > 8e3) {
|
|
5800
|
-
chunks.push({
|
|
5801
|
-
chunkId: `${entry.sessionId}_summary_${i}`,
|
|
5802
|
-
chunkType: "summary",
|
|
5803
|
-
text: chunkText.slice(0, 8e3),
|
|
5804
|
-
sourceLine: 0,
|
|
5805
|
-
...baseData
|
|
5806
|
-
});
|
|
5807
|
-
} else {
|
|
5808
|
-
chunks.push({
|
|
5809
|
-
chunkId: `${entry.sessionId}_summary_${i}`,
|
|
5810
|
-
chunkType: "summary",
|
|
5811
|
-
text: chunkText,
|
|
5812
|
-
sourceLine: 0,
|
|
5813
|
-
...baseData
|
|
5814
|
-
});
|
|
5815
|
-
}
|
|
5816
|
-
}
|
|
5817
|
-
if (chunks.length >= maxChunks) {
|
|
5818
|
-
return chunks.slice(0, maxChunks);
|
|
5819
|
-
}
|
|
5820
|
-
const firstPrompt = entry.firstPrompt || content.firstPrompt;
|
|
5821
|
-
if (firstPrompt?.trim()) {
|
|
5822
|
-
const firstLine = content.userMessages[0]?.lineNumber || 0;
|
|
5823
|
-
chunks.push({
|
|
5824
|
-
chunkId: `${entry.sessionId}_first_prompt`,
|
|
5825
|
-
chunkType: "first_prompt",
|
|
5826
|
-
text: cleanText(firstPrompt.slice(0, maxChars)),
|
|
5827
|
-
sourceLine: firstLine,
|
|
5828
|
-
...baseData
|
|
5829
|
-
});
|
|
5830
|
-
}
|
|
5831
|
-
if (chunks.length >= maxChunks) {
|
|
5832
|
-
return chunks.slice(0, maxChunks);
|
|
5833
|
-
}
|
|
5834
|
-
const userStart = firstPrompt ? 1 : 0;
|
|
5835
|
-
for (let i = userStart; i < content.userMessages.length; i++) {
|
|
5836
|
-
if (chunks.length >= maxChunks)
|
|
5837
|
-
break;
|
|
5838
|
-
const msg = content.userMessages[i];
|
|
5839
|
-
if (!msg.text.trim())
|
|
5840
|
-
continue;
|
|
5841
|
-
const windows = windowText(msg.text, maxChars);
|
|
5842
|
-
for (let w = 0; w < windows.length; w++) {
|
|
5843
|
-
if (chunks.length >= maxChunks)
|
|
5844
|
-
break;
|
|
5845
|
-
chunks.push({
|
|
5846
|
-
chunkId: `${entry.sessionId}_user_${i}_${w}`,
|
|
5847
|
-
chunkType: "user_context",
|
|
5848
|
-
text: windows[w],
|
|
5849
|
-
sourceLine: msg.lineNumber,
|
|
5850
|
-
...baseData
|
|
5851
|
-
});
|
|
5852
|
-
}
|
|
5853
|
-
}
|
|
5854
|
-
if (chunks.length >= maxChunks) {
|
|
5855
|
-
return chunks.slice(0, maxChunks);
|
|
5856
|
-
}
|
|
5857
|
-
for (let i = 0; i < content.assistantMessages.length; i++) {
|
|
5858
|
-
if (chunks.length >= maxChunks)
|
|
5859
|
-
break;
|
|
5860
|
-
const msg = content.assistantMessages[i];
|
|
5861
|
-
if (!msg.text.trim() || msg.text.length <= 50)
|
|
5862
|
-
continue;
|
|
5863
|
-
const windows = windowText(msg.text, maxChars);
|
|
5864
|
-
for (let w = 0; w < windows.length; w++) {
|
|
5865
|
-
if (chunks.length >= maxChunks)
|
|
5866
|
-
break;
|
|
5867
|
-
chunks.push({
|
|
5868
|
-
chunkId: `${entry.sessionId}_assistant_${i}_${w}`,
|
|
5869
|
-
chunkType: "assistant",
|
|
5870
|
-
text: windows[w],
|
|
5871
|
-
sourceLine: msg.lineNumber,
|
|
5872
|
-
...baseData
|
|
5873
|
-
});
|
|
5874
|
-
}
|
|
5875
|
-
}
|
|
5876
|
-
if (chunks.length >= maxChunks) {
|
|
5877
|
-
return chunks.slice(0, maxChunks);
|
|
5878
|
-
}
|
|
5879
|
-
if (content.toolResults.length > 0) {
|
|
5880
|
-
const webSearches = content.toolResults.filter((r) => r.contentType === "web_search");
|
|
5881
|
-
const otherResults = content.toolResults.filter((r) => r.contentType !== "web_search");
|
|
5882
|
-
const resultsToProcess = [...webSearches.slice(0, 5), ...otherResults.slice(0, 10)];
|
|
5883
|
-
const stripBodies = isToolOutputRedactionEnabled();
|
|
5884
|
-
for (let i = 0; i < resultsToProcess.length; i++) {
|
|
5885
|
-
if (chunks.length >= maxChunks)
|
|
5886
|
-
break;
|
|
5887
|
-
const result = resultsToProcess[i];
|
|
5888
|
-
if (result.text.trim()) {
|
|
5889
|
-
const body = stripBodies && result.contentType !== "web_search" ? redactToolResultBody(result.contentType, result.text) : result.text.slice(0, maxChars);
|
|
5890
|
-
chunks.push({
|
|
5891
|
-
chunkId: `${entry.sessionId}_${result.contentType}_${i}`,
|
|
5892
|
-
chunkType: result.contentType,
|
|
5893
|
-
text: cleanText(body),
|
|
5894
|
-
sourceLine: result.lineNumber,
|
|
5895
|
-
...baseData
|
|
5896
|
-
});
|
|
5897
|
-
}
|
|
5898
|
-
}
|
|
5899
|
-
}
|
|
5900
|
-
return chunks.slice(0, maxChunks);
|
|
5901
|
-
}
|
|
5902
|
-
var INJECTED_BANNERS;
|
|
5903
|
-
var init_chunker = __esm({
|
|
5904
|
-
"../engine/dist/parsers/chunker.js"() {
|
|
5905
|
-
"use strict";
|
|
5906
|
-
init_secret_redactor();
|
|
5907
|
-
INJECTED_BANNERS = [
|
|
5908
|
-
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
5909
|
-
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
5910
|
-
/API Error:[^\n]{0,120}/g
|
|
5911
|
-
];
|
|
5912
|
-
}
|
|
5913
|
-
});
|
|
5914
|
-
|
|
5915
|
-
// ../engine/dist/core/project-dir-name.js
|
|
5916
|
-
import { readdirSync as readdirSync4 } from "node:fs";
|
|
5917
|
-
function looksWindowsEncoded(dirName) {
|
|
5918
|
-
return /^[A-Za-z]--/.test(dirName);
|
|
5919
|
-
}
|
|
5920
|
-
function decodeProjectDirName(dirName) {
|
|
5921
|
-
if (!dirName)
|
|
5922
|
-
return "";
|
|
5923
|
-
if (looksWindowsEncoded(dirName)) {
|
|
5924
|
-
const drive = dirName[0].toUpperCase();
|
|
5925
|
-
const rest = dirName.slice(3).replace(/-/g, "\\");
|
|
5926
|
-
return `${drive}:\\${rest}`;
|
|
5927
|
-
}
|
|
5928
|
-
return "/" + dirName.replace(/^-/, "").replace(/-/g, "/");
|
|
5929
|
-
}
|
|
5930
|
-
function resolveProjectDirName(dirName, deps = {}) {
|
|
5931
|
-
const structural = decodeProjectDirName(dirName);
|
|
5932
|
-
if (!dirName)
|
|
5933
|
-
return structural;
|
|
5934
|
-
if (looksWindowsEncoded(dirName))
|
|
5935
|
-
return structural;
|
|
5936
|
-
const readdir3 = deps.readdir ?? ((p) => readdirSync4(p, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name));
|
|
5937
|
-
const encodeName = (name) => name.replace(/[-_.]/g, "-");
|
|
5938
|
-
let remaining = dirName.replace(/^-/, "");
|
|
5939
|
-
let current = "/";
|
|
5940
|
-
while (remaining) {
|
|
5941
|
-
let children;
|
|
5942
|
-
try {
|
|
5943
|
-
children = readdir3(current);
|
|
5944
|
-
} catch {
|
|
5945
|
-
break;
|
|
5946
|
-
}
|
|
5947
|
-
let best = "";
|
|
5948
|
-
for (const child of children) {
|
|
5949
|
-
const encoded = encodeName(child);
|
|
5950
|
-
if (!encoded || encoded.length < best.length)
|
|
5951
|
-
continue;
|
|
5952
|
-
if (!remaining.startsWith(encoded))
|
|
5953
|
-
continue;
|
|
5954
|
-
const next = remaining[encoded.length];
|
|
5955
|
-
if (next !== void 0 && next !== "-")
|
|
5956
|
-
continue;
|
|
5957
|
-
if (encoded.length > best.length)
|
|
5958
|
-
best = child;
|
|
5959
|
-
}
|
|
5960
|
-
if (!best)
|
|
5961
|
-
break;
|
|
5962
|
-
current = current === "/" ? `/${best}` : `${current}/${best}`;
|
|
5963
|
-
remaining = remaining.slice(encodeName(best).length).replace(/^-/, "");
|
|
5964
|
-
}
|
|
5965
|
-
return remaining ? structural : current;
|
|
5966
|
-
}
|
|
5967
|
-
var init_project_dir_name = __esm({
|
|
5968
|
-
"../engine/dist/core/project-dir-name.js"() {
|
|
5969
|
-
"use strict";
|
|
5970
|
-
}
|
|
5971
|
-
});
|
|
5972
|
-
|
|
5973
|
-
// ../engine/dist/core/model-pricing.js
|
|
5974
|
-
function pricingFor(modelId) {
|
|
5975
|
-
if (!modelId)
|
|
5976
|
-
return null;
|
|
5977
|
-
const lower = modelId.toLowerCase();
|
|
5978
|
-
let best = null;
|
|
5979
|
-
let bestLen = -1;
|
|
5980
|
-
for (const [prefix, entry] of Object.entries(TABLE)) {
|
|
5981
|
-
if (lower.startsWith(prefix.toLowerCase()) && prefix.length > bestLen) {
|
|
5982
|
-
best = entry;
|
|
5983
|
-
bestLen = prefix.length;
|
|
5984
|
-
}
|
|
5985
|
-
}
|
|
5986
|
-
return best;
|
|
5987
|
-
}
|
|
5988
|
-
function estimateCostUsdOrNull(modelsUsed, tokens) {
|
|
5989
|
-
let best = null;
|
|
5990
|
-
let bestRate = -1;
|
|
5991
|
-
for (const m of modelsUsed) {
|
|
5992
|
-
if (!m || m === "<synthetic>")
|
|
5993
|
-
continue;
|
|
5994
|
-
const p = pricingFor(m);
|
|
5995
|
-
if (p && p.output > bestRate) {
|
|
5996
|
-
best = p;
|
|
5997
|
-
bestRate = p.output;
|
|
5998
|
-
}
|
|
5999
|
-
}
|
|
6000
|
-
if (!best)
|
|
6001
|
-
return null;
|
|
6002
|
-
const nonCachedInput = Math.max(0, tokens.inputTokens - tokens.cacheReadTokens - tokens.cacheCreationTokens);
|
|
6003
|
-
const cost = nonCachedInput / 1e6 * best.input + tokens.outputTokens / 1e6 * best.output + tokens.cacheReadTokens / 1e6 * best.cacheRead + tokens.cacheCreationTokens / 1e6 * best.cacheCreate;
|
|
6004
|
-
return Math.round(cost * 100) / 100;
|
|
6005
|
-
}
|
|
6006
|
-
function estimateCostUsd(modelsUsed, tokens) {
|
|
6007
|
-
return estimateCostUsdOrNull(modelsUsed, tokens) ?? 0;
|
|
6008
|
-
}
|
|
6009
|
-
var TABLE, METADATA_VERSION;
|
|
6010
|
-
var init_model_pricing = __esm({
|
|
6011
|
-
"../engine/dist/core/model-pricing.js"() {
|
|
6012
|
-
"use strict";
|
|
6013
|
-
TABLE = {
|
|
6014
|
-
// Anthropic — Claude 4.x family
|
|
6015
|
-
"claude-opus-4-7": {
|
|
6016
|
-
input: 15,
|
|
6017
|
-
output: 75,
|
|
6018
|
-
cacheRead: 1.5,
|
|
6019
|
-
cacheCreate: 18.75,
|
|
6020
|
-
lastReviewed: "2026-01-15",
|
|
6021
|
-
source: "Anthropic public pricing (Opus 4.x)"
|
|
6022
|
-
},
|
|
6023
|
-
"claude-opus-4-6": {
|
|
6024
|
-
input: 15,
|
|
6025
|
-
output: 75,
|
|
6026
|
-
cacheRead: 1.5,
|
|
6027
|
-
cacheCreate: 18.75,
|
|
6028
|
-
lastReviewed: "2026-01-15",
|
|
6029
|
-
source: "Anthropic public pricing (Opus 4.x)"
|
|
6030
|
-
},
|
|
6031
|
-
"claude-opus-4": {
|
|
6032
|
-
input: 15,
|
|
6033
|
-
output: 75,
|
|
6034
|
-
cacheRead: 1.5,
|
|
6035
|
-
cacheCreate: 18.75,
|
|
6036
|
-
lastReviewed: "2026-01-15",
|
|
6037
|
-
source: "Anthropic public pricing (Opus 4.x)"
|
|
6038
|
-
},
|
|
6039
|
-
"claude-sonnet-4-6": {
|
|
6040
|
-
input: 3,
|
|
6041
|
-
output: 15,
|
|
6042
|
-
cacheRead: 0.3,
|
|
6043
|
-
cacheCreate: 3.75,
|
|
6044
|
-
lastReviewed: "2026-01-15",
|
|
6045
|
-
source: "Anthropic public pricing (Sonnet 4.x)"
|
|
6046
|
-
},
|
|
6047
|
-
"claude-sonnet-4": {
|
|
6048
|
-
input: 3,
|
|
6049
|
-
output: 15,
|
|
6050
|
-
cacheRead: 0.3,
|
|
6051
|
-
cacheCreate: 3.75,
|
|
6052
|
-
lastReviewed: "2026-01-15",
|
|
6053
|
-
source: "Anthropic public pricing (Sonnet 4.x)"
|
|
6054
|
-
},
|
|
6055
|
-
"claude-haiku-4-5": {
|
|
6056
|
-
input: 1,
|
|
6057
|
-
output: 5,
|
|
6058
|
-
cacheRead: 0.1,
|
|
6059
|
-
cacheCreate: 1.25,
|
|
6060
|
-
lastReviewed: "2026-01-15",
|
|
6061
|
-
source: "Anthropic public pricing (Haiku 4.5)"
|
|
6062
|
-
},
|
|
6063
|
-
// Anthropic — older Claude 3.x (kept for back-compat with historical transcripts)
|
|
6064
|
-
"claude-3-7-sonnet": {
|
|
6065
|
-
input: 3,
|
|
6066
|
-
output: 15,
|
|
6067
|
-
cacheRead: 0.3,
|
|
6068
|
-
cacheCreate: 3.75,
|
|
6069
|
-
lastReviewed: "2026-01-15",
|
|
6070
|
-
source: "Anthropic public pricing"
|
|
6071
|
-
},
|
|
6072
|
-
"claude-3-5-sonnet": {
|
|
6073
|
-
input: 3,
|
|
6074
|
-
output: 15,
|
|
6075
|
-
cacheRead: 0.3,
|
|
6076
|
-
cacheCreate: 3.75,
|
|
6077
|
-
lastReviewed: "2026-01-15",
|
|
6078
|
-
source: "Anthropic public pricing"
|
|
6079
|
-
},
|
|
6080
|
-
"claude-3-5-haiku": {
|
|
6081
|
-
input: 0.8,
|
|
6082
|
-
output: 4,
|
|
6083
|
-
cacheRead: 0.08,
|
|
6084
|
-
cacheCreate: 1,
|
|
6085
|
-
lastReviewed: "2026-01-15",
|
|
6086
|
-
source: "Anthropic public pricing"
|
|
6087
|
-
},
|
|
6088
|
-
"claude-3-opus": {
|
|
6089
|
-
input: 15,
|
|
6090
|
-
output: 75,
|
|
6091
|
-
cacheRead: 1.5,
|
|
6092
|
-
cacheCreate: 18.75,
|
|
6093
|
-
lastReviewed: "2026-01-15",
|
|
6094
|
-
source: "Anthropic public pricing"
|
|
6095
|
-
},
|
|
6096
|
-
// OpenAI — current GPT-* (used by Codex CLI)
|
|
6097
|
-
"gpt-5": {
|
|
6098
|
-
input: 1.25,
|
|
6099
|
-
output: 10,
|
|
6100
|
-
cacheRead: 0.125,
|
|
6101
|
-
cacheCreate: 1.25,
|
|
6102
|
-
lastReviewed: "2026-01-15",
|
|
6103
|
-
source: "OpenAI public pricing (GPT-5)"
|
|
6104
|
-
},
|
|
6105
|
-
"gpt-5-mini": {
|
|
6106
|
-
input: 0.25,
|
|
6107
|
-
output: 2,
|
|
6108
|
-
cacheRead: 0.025,
|
|
6109
|
-
cacheCreate: 0.25,
|
|
6110
|
-
lastReviewed: "2026-01-15",
|
|
6111
|
-
source: "OpenAI public pricing (GPT-5 Mini)"
|
|
6112
|
-
},
|
|
6113
|
-
"gpt-4o": {
|
|
6114
|
-
input: 2.5,
|
|
6115
|
-
output: 10,
|
|
6116
|
-
cacheRead: 1.25,
|
|
6117
|
-
cacheCreate: 2.5,
|
|
6118
|
-
lastReviewed: "2026-01-15",
|
|
6119
|
-
source: "OpenAI public pricing"
|
|
6120
|
-
},
|
|
6121
|
-
// Google Gemini — 2.x family (used by Gemini CLI)
|
|
6122
|
-
"gemini-2.5-pro": {
|
|
6123
|
-
input: 1.25,
|
|
6124
|
-
output: 10,
|
|
6125
|
-
cacheRead: 0.31,
|
|
6126
|
-
cacheCreate: 1.25,
|
|
6127
|
-
lastReviewed: "2026-01-15",
|
|
6128
|
-
source: "Google AI Studio public pricing"
|
|
6129
|
-
},
|
|
6130
|
-
"gemini-2.5-flash": {
|
|
6131
|
-
input: 0.3,
|
|
6132
|
-
output: 2.5,
|
|
6133
|
-
cacheRead: 0.075,
|
|
6134
|
-
cacheCreate: 0.3,
|
|
6135
|
-
lastReviewed: "2026-01-15",
|
|
6136
|
-
source: "Google AI Studio public pricing"
|
|
6137
|
-
}
|
|
6138
|
-
};
|
|
6139
|
-
METADATA_VERSION = 3;
|
|
6140
|
-
}
|
|
6141
|
-
});
|
|
6142
|
-
|
|
6143
|
-
// ../engine/dist/parsers/session.js
|
|
6144
|
-
import { createReadStream, existsSync as existsSync5, readdirSync as readdirSync5, readFileSync as readFileSync2, statSync as statSync4, openSync, readSync, closeSync } from "fs";
|
|
6145
|
-
import { createInterface } from "readline";
|
|
6146
|
-
import { join as join5, basename as basename2 } from "path";
|
|
6147
|
-
function removeCodeBlocks(text) {
|
|
6148
|
-
let result = text.replace(/```[\s\S]*?```/g, "[code block]");
|
|
6149
|
-
result = result.replace(/`[^`]+`/g, "[code]");
|
|
6150
|
-
return result;
|
|
6151
|
-
}
|
|
6152
|
-
function extractKeyText(text, maxLength = 800) {
|
|
6153
|
-
let result = removeCodeBlocks(text);
|
|
6154
|
-
const boilerplate = [
|
|
6155
|
-
/^Let me /i,
|
|
6156
|
-
/^I'll /i,
|
|
6157
|
-
/^I will /i,
|
|
6158
|
-
/^Now I'll /i,
|
|
6159
|
-
/^Here's what /i
|
|
6160
|
-
];
|
|
6161
|
-
for (const pattern of boilerplate) {
|
|
6162
|
-
result = result.replace(pattern, "");
|
|
6163
|
-
}
|
|
6164
|
-
result = result.replace(/\s+/g, " ").trim();
|
|
6165
|
-
return result.slice(0, maxLength);
|
|
6166
|
-
}
|
|
6167
|
-
function isValuableToolResult(content, toolName = "") {
|
|
6168
|
-
if (!content || content.length < 20) {
|
|
6169
|
-
return false;
|
|
6170
|
-
}
|
|
6171
|
-
const skipPatterns = [
|
|
6172
|
-
/^Tool ran without output/i,
|
|
6173
|
-
/^No (?:matches|results) found/i,
|
|
6174
|
-
/^File (?:created|updated|deleted)/i,
|
|
6175
|
-
/^Command completed/i,
|
|
6176
|
-
/^\s*$/
|
|
6177
|
-
];
|
|
6178
|
-
for (const pattern of skipPatterns) {
|
|
6179
|
-
if (pattern.test(content)) {
|
|
6180
|
-
return false;
|
|
6181
|
-
}
|
|
6182
|
-
}
|
|
6183
|
-
if (["WebSearch", "WebFetch"].includes(toolName) || content.toLowerCase().includes("http")) {
|
|
6184
|
-
return true;
|
|
6185
|
-
}
|
|
6186
|
-
if (content.length > 5e3) {
|
|
6187
|
-
return false;
|
|
6188
|
-
}
|
|
6189
|
-
return true;
|
|
6190
|
-
}
|
|
6191
|
-
function parseSessionsIndex(indexPath) {
|
|
6192
|
-
if (!existsSync5(indexPath)) {
|
|
6193
|
-
return [];
|
|
6194
|
-
}
|
|
6195
|
-
const data = JSON.parse(readFileSync2(indexPath, "utf-8"));
|
|
6196
|
-
const entries = data.entries || [];
|
|
6197
|
-
return entries.map((e) => ({
|
|
6198
|
-
sessionId: e.sessionId || "",
|
|
6199
|
-
fullPath: e.fullPath || "",
|
|
6200
|
-
fileMtime: e.fileMtime || 0,
|
|
6201
|
-
firstPrompt: e.firstPrompt || "",
|
|
6202
|
-
messageCount: e.messageCount || 0,
|
|
6203
|
-
created: e.created || "",
|
|
6204
|
-
modified: e.modified || "",
|
|
6205
|
-
gitBranch: e.gitBranch || "",
|
|
6206
|
-
projectPath: e.projectPath || "",
|
|
6207
|
-
isSidechain: e.isSidechain || false
|
|
6208
|
-
}));
|
|
6209
|
-
}
|
|
6210
|
-
function* iterAllSessionIndices(claudeDir) {
|
|
6211
|
-
const dir = claudeDir || claudeBackend.projectsDir();
|
|
6212
|
-
if (!existsSync5(dir)) {
|
|
6213
|
-
return;
|
|
6214
|
-
}
|
|
6215
|
-
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
6216
|
-
for (const entry of entries) {
|
|
6217
|
-
if (!entry.isDirectory())
|
|
6218
|
-
continue;
|
|
6219
|
-
const projectDir = join5(dir, entry.name);
|
|
6220
|
-
const indexPath = join5(projectDir, "sessions-index.json");
|
|
6221
|
-
if (existsSync5(indexPath)) {
|
|
6222
|
-
const sessions = parseSessionsIndex(indexPath);
|
|
6223
|
-
if (sessions.length > 0) {
|
|
6224
|
-
yield [projectDir, sessions];
|
|
6225
|
-
}
|
|
6226
|
-
}
|
|
6227
|
-
}
|
|
6228
|
-
}
|
|
6229
|
-
function hasSubagentsDir(sessionPath) {
|
|
6230
|
-
const dir = sessionPath.slice(0, -6);
|
|
6231
|
-
return existsSync5(join5(dir, "subagents"));
|
|
6232
|
-
}
|
|
6233
|
-
function getSubagentPaths(sessionPath) {
|
|
6234
|
-
const subagentsDir = join5(sessionPath.slice(0, -6), "subagents");
|
|
6235
|
-
if (!existsSync5(subagentsDir))
|
|
6236
|
-
return [];
|
|
6237
|
-
return readdirSync5(subagentsDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join5(subagentsDir, f));
|
|
6238
|
-
}
|
|
6239
|
-
function getSubagentProjectPath(sessionPath, folderDerivedPath) {
|
|
6240
|
-
const subagentPaths = getSubagentPaths(sessionPath);
|
|
6241
|
-
if (subagentPaths.length === 0)
|
|
6242
|
-
return folderDerivedPath;
|
|
6243
|
-
const cwdCounts = /* @__PURE__ */ new Map();
|
|
6244
|
-
for (const filePath of subagentPaths) {
|
|
6245
|
-
try {
|
|
6246
|
-
const lines = readFileSync2(filePath, "utf-8").split("\n");
|
|
6247
|
-
for (const line of lines) {
|
|
6248
|
-
if (!line.trim())
|
|
6249
|
-
continue;
|
|
6250
|
-
try {
|
|
6251
|
-
const entry = JSON.parse(line);
|
|
6252
|
-
if (entry.type === "user" && typeof entry.cwd === "string" && entry.cwd) {
|
|
6253
|
-
cwdCounts.set(entry.cwd, (cwdCounts.get(entry.cwd) ?? 0) + 1);
|
|
6254
|
-
}
|
|
6255
|
-
} catch {
|
|
6256
|
-
}
|
|
6257
|
-
}
|
|
6258
|
-
} catch {
|
|
6259
|
-
}
|
|
6260
|
-
}
|
|
6261
|
-
if (cwdCounts.size === 0)
|
|
6262
|
-
return folderDerivedPath;
|
|
6263
|
-
let best = folderDerivedPath;
|
|
6264
|
-
let bestCount = 0;
|
|
6265
|
-
for (const [cwd, count] of cwdCounts) {
|
|
6266
|
-
if (count > bestCount) {
|
|
6267
|
-
best = cwd;
|
|
6268
|
-
bestCount = count;
|
|
6269
|
-
}
|
|
6270
|
-
}
|
|
6271
|
-
return best;
|
|
5648
|
+
function getSubagentPaths(sessionPath) {
|
|
5649
|
+
const subagentsDir = join5(sessionPath.slice(0, -6), "subagents");
|
|
5650
|
+
if (!existsSync5(subagentsDir))
|
|
5651
|
+
return [];
|
|
5652
|
+
return readdirSync5(subagentsDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join5(subagentsDir, f));
|
|
6272
5653
|
}
|
|
6273
5654
|
function readCwdFromJsonl(sessionPath) {
|
|
6274
5655
|
try {
|
|
@@ -6298,22 +5679,6 @@ function readCwdFromJsonl(sessionPath) {
|
|
|
6298
5679
|
}
|
|
6299
5680
|
return "";
|
|
6300
5681
|
}
|
|
6301
|
-
function getSessionMtime(sessionPath) {
|
|
6302
|
-
const subagentPaths = getSubagentPaths(sessionPath);
|
|
6303
|
-
if (subagentPaths.length === 0) {
|
|
6304
|
-
return statSync4(sessionPath).mtimeMs;
|
|
6305
|
-
}
|
|
6306
|
-
let maxMtime = statSync4(sessionPath).mtimeMs;
|
|
6307
|
-
for (const p of subagentPaths) {
|
|
6308
|
-
try {
|
|
6309
|
-
const m = statSync4(p).mtimeMs;
|
|
6310
|
-
if (m > maxMtime)
|
|
6311
|
-
maxMtime = m;
|
|
6312
|
-
} catch {
|
|
6313
|
-
}
|
|
6314
|
-
}
|
|
6315
|
-
return maxMtime;
|
|
6316
|
-
}
|
|
6317
5682
|
async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
6318
5683
|
const sessionId = basename2(sessionPath, ".jsonl");
|
|
6319
5684
|
const content = {
|
|
@@ -6551,76 +5916,10 @@ ${resultText}` : resultText;
|
|
|
6551
5916
|
});
|
|
6552
5917
|
return content;
|
|
6553
5918
|
}
|
|
6554
|
-
function* getAllSessions(claudeDir) {
|
|
6555
|
-
const seenSessionIds = /* @__PURE__ */ new Set();
|
|
6556
|
-
const projectDirs = claudeDir ? [claudeDir] : claudeProjectDirs();
|
|
6557
|
-
for (const dir of projectDirs) {
|
|
6558
|
-
for (const [, entries] of iterAllSessionIndices(dir)) {
|
|
6559
|
-
for (const entry of entries) {
|
|
6560
|
-
if (!seenSessionIds.has(entry.sessionId) && existsSync5(entry.fullPath)) {
|
|
6561
|
-
seenSessionIds.add(entry.sessionId);
|
|
6562
|
-
yield [entry, entry.fullPath];
|
|
6563
|
-
}
|
|
6564
|
-
}
|
|
6565
|
-
}
|
|
6566
|
-
if (!existsSync5(dir))
|
|
6567
|
-
continue;
|
|
6568
|
-
const dirEntries = readdirSync5(dir, { withFileTypes: true });
|
|
6569
|
-
for (const projDirEntry of dirEntries) {
|
|
6570
|
-
if (!projDirEntry.isDirectory())
|
|
6571
|
-
continue;
|
|
6572
|
-
const projectPath = join5(dir, projDirEntry.name);
|
|
6573
|
-
const files = readdirSync5(projectPath);
|
|
6574
|
-
for (const file of files) {
|
|
6575
|
-
if (!file.endsWith(".jsonl"))
|
|
6576
|
-
continue;
|
|
6577
|
-
if (file.startsWith("agent-"))
|
|
6578
|
-
continue;
|
|
6579
|
-
if (file === "sessions-index.json")
|
|
6580
|
-
continue;
|
|
6581
|
-
const sessionId = basename2(file, ".jsonl");
|
|
6582
|
-
if (seenSessionIds.has(sessionId))
|
|
6583
|
-
continue;
|
|
6584
|
-
const fullPath = join5(projectPath, file);
|
|
6585
|
-
try {
|
|
6586
|
-
const stat3 = statSync4(fullPath);
|
|
6587
|
-
const derivedProjectPath = resolveProjectDirName(projDirEntry.name);
|
|
6588
|
-
const effectiveMtime = getSessionMtime(fullPath);
|
|
6589
|
-
let projectPath2 = "";
|
|
6590
|
-
if (hasSubagentsDir(fullPath)) {
|
|
6591
|
-
projectPath2 = getSubagentProjectPath(fullPath, derivedProjectPath);
|
|
6592
|
-
} else {
|
|
6593
|
-
const fromJsonl = readCwdFromJsonl(fullPath);
|
|
6594
|
-
if (fromJsonl)
|
|
6595
|
-
projectPath2 = fromJsonl;
|
|
6596
|
-
}
|
|
6597
|
-
if (!projectPath2)
|
|
6598
|
-
projectPath2 = derivedProjectPath;
|
|
6599
|
-
const entry = {
|
|
6600
|
-
sessionId,
|
|
6601
|
-
fullPath,
|
|
6602
|
-
fileMtime: effectiveMtime,
|
|
6603
|
-
firstPrompt: "",
|
|
6604
|
-
messageCount: 0,
|
|
6605
|
-
created: stat3.birthtime.toISOString(),
|
|
6606
|
-
modified: new Date(effectiveMtime).toISOString(),
|
|
6607
|
-
gitBranch: "",
|
|
6608
|
-
projectPath: projectPath2,
|
|
6609
|
-
isSidechain: false
|
|
6610
|
-
};
|
|
6611
|
-
seenSessionIds.add(sessionId);
|
|
6612
|
-
yield [entry, fullPath];
|
|
6613
|
-
} catch {
|
|
6614
|
-
continue;
|
|
6615
|
-
}
|
|
6616
|
-
}
|
|
6617
|
-
}
|
|
6618
|
-
}
|
|
6619
|
-
}
|
|
6620
5919
|
var init_session = __esm({
|
|
6621
5920
|
"../engine/dist/parsers/session.js"() {
|
|
6622
5921
|
"use strict";
|
|
6623
|
-
|
|
5922
|
+
init_banners();
|
|
6624
5923
|
init_claude2();
|
|
6625
5924
|
init_tool_paths();
|
|
6626
5925
|
init_project_dir_name();
|
|
@@ -7286,7 +6585,7 @@ var init_raw = __esm({
|
|
|
7286
6585
|
// ../engine/dist/transcript/shadow.js
|
|
7287
6586
|
import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
|
|
7288
6587
|
import { createHash as createHash2 } from "crypto";
|
|
7289
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as
|
|
6588
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync4 } from "fs";
|
|
7290
6589
|
import { dirname as dirname7, join as join8 } from "path";
|
|
7291
6590
|
function shadowRoot() {
|
|
7292
6591
|
return join8(getDataDir(), "shadow");
|
|
@@ -7494,7 +6793,7 @@ function liveFingerprint(backend, rawId) {
|
|
|
7494
6793
|
const loc = backend.findSession(rawId);
|
|
7495
6794
|
if (!loc?.path)
|
|
7496
6795
|
return "";
|
|
7497
|
-
const st =
|
|
6796
|
+
const st = statSync4(loc.path);
|
|
7498
6797
|
return `${st.mtimeMs}:${st.size}`;
|
|
7499
6798
|
} catch {
|
|
7500
6799
|
return "";
|
|
@@ -7512,7 +6811,7 @@ function seedShadow(sessionId, container) {
|
|
|
7512
6811
|
}
|
|
7513
6812
|
function shadowSizeOnDisk(tool, rawId) {
|
|
7514
6813
|
try {
|
|
7515
|
-
return
|
|
6814
|
+
return statSync4(shadowFileFor(tool, rawId)).size;
|
|
7516
6815
|
} catch {
|
|
7517
6816
|
return 0;
|
|
7518
6817
|
}
|
|
@@ -7530,7 +6829,7 @@ var init_shadow = __esm({
|
|
|
7530
6829
|
});
|
|
7531
6830
|
|
|
7532
6831
|
// ../engine/dist/core/live-session-scan.js
|
|
7533
|
-
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync4, statSync as
|
|
6832
|
+
import { existsSync as existsSync7, readdirSync as readdirSync6, readFileSync as readFileSync4, statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2 } from "fs";
|
|
7534
6833
|
import { join as join9, basename as basename5 } from "path";
|
|
7535
6834
|
function detectTool(sessionId) {
|
|
7536
6835
|
return getBackendForId(sessionId)?.id ?? "claude";
|
|
@@ -7622,20 +6921,33 @@ function resolveSessionContentGroups(sessionId) {
|
|
|
7622
6921
|
}
|
|
7623
6922
|
function withSessionReadCache(fn) {
|
|
7624
6923
|
readScopeDepth++;
|
|
6924
|
+
if (readScopeDepth === 1)
|
|
6925
|
+
derivedScope = /* @__PURE__ */ new Map();
|
|
7625
6926
|
try {
|
|
7626
6927
|
return fn();
|
|
7627
6928
|
} finally {
|
|
7628
|
-
if (--readScopeDepth === 0)
|
|
6929
|
+
if (--readScopeDepth === 0) {
|
|
7629
6930
|
readScope = null;
|
|
6931
|
+
derivedScope = null;
|
|
6932
|
+
}
|
|
7630
6933
|
}
|
|
7631
6934
|
}
|
|
6935
|
+
function memoInSessionScope(key2, compute) {
|
|
6936
|
+
if (!derivedScope)
|
|
6937
|
+
return compute();
|
|
6938
|
+
if (derivedScope.has(key2))
|
|
6939
|
+
return derivedScope.get(key2);
|
|
6940
|
+
const value = compute();
|
|
6941
|
+
derivedScope.set(key2, value);
|
|
6942
|
+
return value;
|
|
6943
|
+
}
|
|
7632
6944
|
function readSessionGroupText(group) {
|
|
7633
6945
|
let key2 = "";
|
|
7634
6946
|
if (readScopeDepth > 0) {
|
|
7635
6947
|
const parts = [];
|
|
7636
6948
|
for (const p of group.paths) {
|
|
7637
6949
|
try {
|
|
7638
|
-
const st =
|
|
6950
|
+
const st = statSync5(p);
|
|
7639
6951
|
parts.push(`${p}:${st.mtimeMs}:${st.size}`);
|
|
7640
6952
|
} catch {
|
|
7641
6953
|
parts.push(`${p}:missing`);
|
|
@@ -7655,7 +6967,7 @@ function readSessionGroupText(group) {
|
|
|
7655
6967
|
continue;
|
|
7656
6968
|
}
|
|
7657
6969
|
try {
|
|
7658
|
-
mtime = Math.max(mtime,
|
|
6970
|
+
mtime = Math.max(mtime, statSync5(p).mtimeMs);
|
|
7659
6971
|
} catch {
|
|
7660
6972
|
}
|
|
7661
6973
|
text = text ? mergeLineText(text, raw).text : raw;
|
|
@@ -7740,7 +7052,7 @@ function findCodexSessionFileIn(root, sessionId) {
|
|
|
7740
7052
|
}
|
|
7741
7053
|
return scanDir(root);
|
|
7742
7054
|
}
|
|
7743
|
-
var scanScopeDepth, indexCache, readScope, readScopeDepth, geminiCache, MAX_EVENT_LINE_BYTES;
|
|
7055
|
+
var scanScopeDepth, indexCache, readScope, readScopeDepth, derivedScope, geminiCache, MAX_EVENT_LINE_BYTES;
|
|
7744
7056
|
var init_live_session_scan = __esm({
|
|
7745
7057
|
"../engine/dist/core/live-session-scan.js"() {
|
|
7746
7058
|
"use strict";
|
|
@@ -7754,6 +7066,7 @@ var init_live_session_scan = __esm({
|
|
|
7754
7066
|
indexCache = null;
|
|
7755
7067
|
readScope = null;
|
|
7756
7068
|
readScopeDepth = 0;
|
|
7069
|
+
derivedScope = null;
|
|
7757
7070
|
geminiCache = null;
|
|
7758
7071
|
MAX_EVENT_LINE_BYTES = 8 * 1024 * 1024;
|
|
7759
7072
|
}
|
|
@@ -8031,6 +7344,28 @@ var init_session_git = __esm({
|
|
|
8031
7344
|
}
|
|
8032
7345
|
});
|
|
8033
7346
|
|
|
7347
|
+
// ../engine/dist/core/session-multi-tool.js
|
|
7348
|
+
function extractTurnsAny(sessionId, opts = {}) {
|
|
7349
|
+
const backend = getBackendForId(sessionId);
|
|
7350
|
+
if (!backend)
|
|
7351
|
+
return { sessionId, found: false, turns: [], startMs: 0, endMs: 0 };
|
|
7352
|
+
return memoInSessionScope(`turns:${sessionId}:${opts.maxTurns ?? ""}:${opts.assistantMax ?? ""}`, () => backend.extractTurns(sessionId, opts));
|
|
7353
|
+
}
|
|
7354
|
+
function replaySessionAny(sessionId) {
|
|
7355
|
+
const backend = getBackendForId(sessionId);
|
|
7356
|
+
if (!backend)
|
|
7357
|
+
return { sessionId, found: false, projectPath: "", files: [], totalLinesAdded: 0, totalLinesRemoved: 0 };
|
|
7358
|
+
return memoInSessionScope(`replay:${sessionId}`, () => backend.replay(sessionId));
|
|
7359
|
+
}
|
|
7360
|
+
var init_session_multi_tool = __esm({
|
|
7361
|
+
"../engine/dist/core/session-multi-tool.js"() {
|
|
7362
|
+
"use strict";
|
|
7363
|
+
init_tool_backend();
|
|
7364
|
+
init_live_session_scan();
|
|
7365
|
+
init_backends();
|
|
7366
|
+
}
|
|
7367
|
+
});
|
|
7368
|
+
|
|
8034
7369
|
// ../engine/dist/core/session-outcome.js
|
|
8035
7370
|
function extractDecisionsFromTurn(turn) {
|
|
8036
7371
|
if (turn.kind !== "assistant_text" || !turn.text)
|
|
@@ -8127,7 +7462,7 @@ function computeOutcome(sessionId, opts = {}) {
|
|
|
8127
7462
|
};
|
|
8128
7463
|
if (!backend)
|
|
8129
7464
|
return notFound;
|
|
8130
|
-
const turnsRes =
|
|
7465
|
+
const turnsRes = extractTurnsAny(sessionId, { assistantMax: 2e3 });
|
|
8131
7466
|
if (!turnsRes.found)
|
|
8132
7467
|
return notFound;
|
|
8133
7468
|
const decisions = [];
|
|
@@ -8166,7 +7501,7 @@ function computeOutcome(sessionId, opts = {}) {
|
|
|
8166
7501
|
totalLinesAdded = fast.totalLinesAdded;
|
|
8167
7502
|
totalLinesRemoved = fast.totalLinesRemoved;
|
|
8168
7503
|
} else {
|
|
8169
|
-
const replay =
|
|
7504
|
+
const replay = replaySessionAny(sessionId);
|
|
8170
7505
|
filesChanged = replay.files.map((f) => f.file);
|
|
8171
7506
|
totalLinesAdded = replay.totalLinesAdded;
|
|
8172
7507
|
totalLinesRemoved = replay.totalLinesRemoved;
|
|
@@ -8205,6 +7540,7 @@ var init_session_outcome = __esm({
|
|
|
8205
7540
|
init_session_sentiment();
|
|
8206
7541
|
init_session_git();
|
|
8207
7542
|
init_tool_backend();
|
|
7543
|
+
init_session_multi_tool();
|
|
8208
7544
|
init_backends();
|
|
8209
7545
|
DECISION_PATTERNS = [
|
|
8210
7546
|
/\b(?:I'?ll|I will|I'?m going to|Going to|Let me|We'?ll|We will|We should|Let'?s|I'?m about to|I'?m going to)\b[^\n.!?]*[.!?]/i,
|
|
@@ -8340,11 +7676,11 @@ var init_first_prompt = __esm({
|
|
|
8340
7676
|
});
|
|
8341
7677
|
|
|
8342
7678
|
// ../engine/dist/core/backends/tail-read.js
|
|
8343
|
-
import { openSync as openSync4, readSync as readSync4, closeSync as closeSync4, statSync as
|
|
7679
|
+
import { openSync as openSync4, readSync as readSync4, closeSync as closeSync4, statSync as statSync6 } from "node:fs";
|
|
8344
7680
|
function readTailFromOffset(path, offset) {
|
|
8345
7681
|
let size = 0;
|
|
8346
7682
|
try {
|
|
8347
|
-
size =
|
|
7683
|
+
size = statSync6(path).size;
|
|
8348
7684
|
} catch {
|
|
8349
7685
|
return { text: "", newOffset: offset };
|
|
8350
7686
|
}
|
|
@@ -8661,7 +7997,7 @@ var init_generic_engine = __esm({
|
|
|
8661
7997
|
});
|
|
8662
7998
|
|
|
8663
7999
|
// ../engine/dist/core/backends/claude.js
|
|
8664
|
-
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync5, statSync as
|
|
8000
|
+
import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync5, statSync as statSync7, openSync as openSync5, readSync as readSync5, closeSync as closeSync5 } from "fs";
|
|
8665
8001
|
import { join as join10, basename as basename8 } from "path";
|
|
8666
8002
|
function stripReminders(text) {
|
|
8667
8003
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -8674,6 +8010,7 @@ var UUID_RE, ClaudeBackend, claudeBackend;
|
|
|
8674
8010
|
var init_claude2 = __esm({
|
|
8675
8011
|
"../engine/dist/core/backends/claude.js"() {
|
|
8676
8012
|
"use strict";
|
|
8013
|
+
init_live_session_scan();
|
|
8677
8014
|
init_tool_paths();
|
|
8678
8015
|
init_live_session_scan();
|
|
8679
8016
|
init_session_outcome();
|
|
@@ -8790,7 +8127,7 @@ var init_claude2 = __esm({
|
|
|
8790
8127
|
let mtime = 0;
|
|
8791
8128
|
for (const c of copies) {
|
|
8792
8129
|
try {
|
|
8793
|
-
mtime = Math.max(mtime,
|
|
8130
|
+
mtime = Math.max(mtime, statSync7(c.path).mtimeMs);
|
|
8794
8131
|
} catch {
|
|
8795
8132
|
}
|
|
8796
8133
|
}
|
|
@@ -8866,7 +8203,7 @@ var init_claude2 = __esm({
|
|
|
8866
8203
|
const fullPath = join10(projPath, f);
|
|
8867
8204
|
let stat3;
|
|
8868
8205
|
try {
|
|
8869
|
-
stat3 =
|
|
8206
|
+
stat3 = statSync7(fullPath);
|
|
8870
8207
|
} catch {
|
|
8871
8208
|
continue;
|
|
8872
8209
|
}
|
|
@@ -8936,6 +8273,9 @@ var init_claude2 = __esm({
|
|
|
8936
8273
|
* splits show up alongside the parent.
|
|
8937
8274
|
*/
|
|
8938
8275
|
readEvents(rawId) {
|
|
8276
|
+
return memoInSessionScope(`events:claude:${rawId}`, () => this.#readEventsUncached(rawId));
|
|
8277
|
+
}
|
|
8278
|
+
#readEventsUncached(rawId) {
|
|
8939
8279
|
const groups = resolveSessionContentGroups(rawId);
|
|
8940
8280
|
if (groups.length === 0)
|
|
8941
8281
|
return [];
|
|
@@ -9084,7 +8424,7 @@ var init_claude2 = __esm({
|
|
|
9084
8424
|
const events = this.readEvents(rawId);
|
|
9085
8425
|
let fileMtime = 0;
|
|
9086
8426
|
try {
|
|
9087
|
-
fileMtime =
|
|
8427
|
+
fileMtime = statSync7(located.path).mtimeMs;
|
|
9088
8428
|
} catch {
|
|
9089
8429
|
}
|
|
9090
8430
|
return liveScanEditsFromEvents(events, this.fileToolMap, {
|
|
@@ -9139,13 +8479,13 @@ var init_claude2 = __esm({
|
|
|
9139
8479
|
continue;
|
|
9140
8480
|
const fp = join10(projPath, f);
|
|
9141
8481
|
try {
|
|
9142
|
-
const st =
|
|
8482
|
+
const st = statSync7(fp);
|
|
9143
8483
|
let mtime = st.mtimeMs;
|
|
9144
8484
|
const subDir = join10(projPath, f.slice(0, -6), "subagents");
|
|
9145
8485
|
if (existsSync10(subDir)) {
|
|
9146
8486
|
for (const sub of readdirSync7(subDir)) {
|
|
9147
8487
|
try {
|
|
9148
|
-
const subSt =
|
|
8488
|
+
const subSt = statSync7(join10(subDir, sub));
|
|
9149
8489
|
if (subSt.mtimeMs > mtime)
|
|
9150
8490
|
mtime = subSt.mtimeMs;
|
|
9151
8491
|
} catch {
|
|
@@ -9210,7 +8550,7 @@ var init_claude2 = __esm({
|
|
|
9210
8550
|
let total = 0;
|
|
9211
8551
|
for (const located of findSessionFiles(this.toRawId(prefixedId))) {
|
|
9212
8552
|
try {
|
|
9213
|
-
total +=
|
|
8553
|
+
total += statSync7(located.path).size;
|
|
9214
8554
|
} catch {
|
|
9215
8555
|
}
|
|
9216
8556
|
}
|
|
@@ -9823,7 +9163,7 @@ var init_opencode = __esm({
|
|
|
9823
9163
|
});
|
|
9824
9164
|
|
|
9825
9165
|
// ../engine/dist/core/backends/codex.js
|
|
9826
|
-
import { readdirSync as readdirSync8, readFileSync as readFileSync6, statSync as
|
|
9166
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync6, statSync as statSync8, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
9827
9167
|
import { basename as basename9, dirname as dirname10, join as join12 } from "path";
|
|
9828
9168
|
function parseShellWrites(cmd) {
|
|
9829
9169
|
const out = [];
|
|
@@ -10031,7 +9371,7 @@ var init_codex2 = __esm({
|
|
|
10031
9371
|
return null;
|
|
10032
9372
|
let mtime = 0;
|
|
10033
9373
|
try {
|
|
10034
|
-
mtime =
|
|
9374
|
+
mtime = statSync8(located.path).mtimeMs;
|
|
10035
9375
|
} catch {
|
|
10036
9376
|
}
|
|
10037
9377
|
return {
|
|
@@ -10051,7 +9391,7 @@ var init_codex2 = __esm({
|
|
|
10051
9391
|
for (const filePath of walkRollouts(root)) {
|
|
10052
9392
|
let stat3;
|
|
10053
9393
|
try {
|
|
10054
|
-
stat3 =
|
|
9394
|
+
stat3 = statSync8(filePath);
|
|
10055
9395
|
} catch {
|
|
10056
9396
|
continue;
|
|
10057
9397
|
}
|
|
@@ -10247,7 +9587,7 @@ var init_codex2 = __esm({
|
|
|
10247
9587
|
let mtime = 0;
|
|
10248
9588
|
try {
|
|
10249
9589
|
raw = readFileSync6(path, "utf-8");
|
|
10250
|
-
mtime =
|
|
9590
|
+
mtime = statSync8(path).mtimeMs;
|
|
10251
9591
|
} catch {
|
|
10252
9592
|
return [];
|
|
10253
9593
|
}
|
|
@@ -10347,7 +9687,7 @@ var init_codex2 = __esm({
|
|
|
10347
9687
|
const events = this.readEvents(this.toRawId(id));
|
|
10348
9688
|
let fileMtime = 0;
|
|
10349
9689
|
try {
|
|
10350
|
-
fileMtime =
|
|
9690
|
+
fileMtime = statSync8(located.path).mtimeMs;
|
|
10351
9691
|
} catch {
|
|
10352
9692
|
}
|
|
10353
9693
|
return liveScanEditsFromEvents(events, this.fileToolMap, {
|
|
@@ -10411,7 +9751,7 @@ var init_codex2 = __esm({
|
|
|
10411
9751
|
const p = join12(dir, entry.name);
|
|
10412
9752
|
let st;
|
|
10413
9753
|
try {
|
|
10414
|
-
st =
|
|
9754
|
+
st = statSync8(p);
|
|
10415
9755
|
} catch {
|
|
10416
9756
|
continue;
|
|
10417
9757
|
}
|
|
@@ -10478,7 +9818,7 @@ var init_codex2 = __esm({
|
|
|
10478
9818
|
let mtime = 0;
|
|
10479
9819
|
const push = (path, name) => {
|
|
10480
9820
|
try {
|
|
10481
|
-
const st =
|
|
9821
|
+
const st = statSync8(path);
|
|
10482
9822
|
files.push({ name, bytes: readFileSync6(path) });
|
|
10483
9823
|
if (st.mtimeMs > mtime)
|
|
10484
9824
|
mtime = st.mtimeMs;
|
|
@@ -10520,7 +9860,7 @@ var init_codex2 = __esm({
|
|
|
10520
9860
|
if (!loc)
|
|
10521
9861
|
return 0;
|
|
10522
9862
|
try {
|
|
10523
|
-
return
|
|
9863
|
+
return statSync8(loc.path).size;
|
|
10524
9864
|
} catch {
|
|
10525
9865
|
return 0;
|
|
10526
9866
|
}
|
|
@@ -10537,7 +9877,7 @@ var init_codex2 = __esm({
|
|
|
10537
9877
|
});
|
|
10538
9878
|
|
|
10539
9879
|
// ../engine/dist/core/backends/agy.js
|
|
10540
|
-
import { existsSync as existsSync12, readdirSync as readdirSync9, readFileSync as readFileSync7, statSync as
|
|
9880
|
+
import { existsSync as existsSync12, readdirSync as readdirSync9, readFileSync as readFileSync7, statSync as statSync9 } from "fs";
|
|
10541
9881
|
import { basename as basename10, dirname as dirname11, join as join13 } from "path";
|
|
10542
9882
|
function agyTranscriptPath(logsDir) {
|
|
10543
9883
|
const full = join13(logsDir, "transcript_full.jsonl");
|
|
@@ -10730,7 +10070,7 @@ var init_agy = __esm({
|
|
|
10730
10070
|
return null;
|
|
10731
10071
|
let mtime = 0;
|
|
10732
10072
|
try {
|
|
10733
|
-
mtime =
|
|
10073
|
+
mtime = statSync9(path).mtimeMs;
|
|
10734
10074
|
} catch {
|
|
10735
10075
|
}
|
|
10736
10076
|
const projectPath = resolveAgyProject(dirname11(path), this.homeDir());
|
|
@@ -10758,7 +10098,7 @@ var init_agy = __esm({
|
|
|
10758
10098
|
for (const rawId of sessionDirs) {
|
|
10759
10099
|
const sessionPath = join13(brainDir, rawId);
|
|
10760
10100
|
try {
|
|
10761
|
-
if (!
|
|
10101
|
+
if (!statSync9(sessionPath).isDirectory())
|
|
10762
10102
|
continue;
|
|
10763
10103
|
} catch {
|
|
10764
10104
|
continue;
|
|
@@ -10768,7 +10108,7 @@ var init_agy = __esm({
|
|
|
10768
10108
|
continue;
|
|
10769
10109
|
let stat3;
|
|
10770
10110
|
try {
|
|
10771
|
-
stat3 =
|
|
10111
|
+
stat3 = statSync9(filePath);
|
|
10772
10112
|
} catch {
|
|
10773
10113
|
continue;
|
|
10774
10114
|
}
|
|
@@ -11033,7 +10373,7 @@ var init_agy = __esm({
|
|
|
11033
10373
|
for (const rawId of sessionDirs) {
|
|
11034
10374
|
const sessionPath = join13(brainDir, rawId);
|
|
11035
10375
|
try {
|
|
11036
|
-
if (!
|
|
10376
|
+
if (!statSync9(sessionPath).isDirectory())
|
|
11037
10377
|
continue;
|
|
11038
10378
|
} catch {
|
|
11039
10379
|
continue;
|
|
@@ -11042,7 +10382,7 @@ var init_agy = __esm({
|
|
|
11042
10382
|
if (!filePath)
|
|
11043
10383
|
continue;
|
|
11044
10384
|
try {
|
|
11045
|
-
const st =
|
|
10385
|
+
const st = statSync9(filePath);
|
|
11046
10386
|
if (st.mtimeMs < opts.sinceMs)
|
|
11047
10387
|
continue;
|
|
11048
10388
|
candidates2.push({ rawId, mtime: st.mtimeMs });
|
|
@@ -11070,7 +10410,7 @@ var init_agy = __esm({
|
|
|
11070
10410
|
try {
|
|
11071
10411
|
return {
|
|
11072
10412
|
tool: "agy",
|
|
11073
|
-
mtime:
|
|
10413
|
+
mtime: statSync9(loc.path).mtimeMs,
|
|
11074
10414
|
files: [{ name: basename10(loc.path), bytes: readFileSync7(loc.path) }]
|
|
11075
10415
|
};
|
|
11076
10416
|
} catch {
|
|
@@ -11085,7 +10425,7 @@ var init_agy = __esm({
|
|
|
11085
10425
|
if (!loc)
|
|
11086
10426
|
return 0;
|
|
11087
10427
|
try {
|
|
11088
|
-
return
|
|
10428
|
+
return statSync9(loc.path).size;
|
|
11089
10429
|
} catch {
|
|
11090
10430
|
return 0;
|
|
11091
10431
|
}
|
|
@@ -11102,7 +10442,7 @@ var init_agy = __esm({
|
|
|
11102
10442
|
});
|
|
11103
10443
|
|
|
11104
10444
|
// ../engine/dist/core/backends/cursor-store.js
|
|
11105
|
-
import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync8, statSync as
|
|
10445
|
+
import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync8, statSync as statSync10 } from "fs";
|
|
11106
10446
|
import { join as join14 } from "path";
|
|
11107
10447
|
function cursorProjectSlug(absPath) {
|
|
11108
10448
|
return absPath.replace(/[^a-zA-Z0-9]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -11119,7 +10459,7 @@ function listChatsIn(chatsRoot) {
|
|
|
11119
10459
|
const hashPath3 = join14(chatsRoot, workspaceHash);
|
|
11120
10460
|
let chatIds;
|
|
11121
10461
|
try {
|
|
11122
|
-
if (!
|
|
10462
|
+
if (!statSync10(hashPath3).isDirectory())
|
|
11123
10463
|
continue;
|
|
11124
10464
|
chatIds = readdirSync10(hashPath3);
|
|
11125
10465
|
} catch {
|
|
@@ -11141,7 +10481,7 @@ function listChatsIn(chatsRoot) {
|
|
|
11141
10481
|
let created = meta.createdAtMs ?? 0;
|
|
11142
10482
|
if (!mtime || !created) {
|
|
11143
10483
|
try {
|
|
11144
|
-
const st =
|
|
10484
|
+
const st = statSync10(dbPath);
|
|
11145
10485
|
mtime = mtime || st.mtimeMs;
|
|
11146
10486
|
created = created || st.birthtimeMs || st.mtimeMs;
|
|
11147
10487
|
} catch {
|
|
@@ -11184,7 +10524,7 @@ function findChat(chatsRoots, chatId) {
|
|
|
11184
10524
|
let created = meta.createdAtMs ?? 0;
|
|
11185
10525
|
if (!mtime || !created) {
|
|
11186
10526
|
try {
|
|
11187
|
-
const st =
|
|
10527
|
+
const st = statSync10(dbPath);
|
|
11188
10528
|
mtime = mtime || st.mtimeMs;
|
|
11189
10529
|
created = created || st.birthtimeMs || st.mtimeMs;
|
|
11190
10530
|
} catch {
|
|
@@ -11487,7 +10827,7 @@ var init_cursor_store = __esm({
|
|
|
11487
10827
|
});
|
|
11488
10828
|
|
|
11489
10829
|
// ../engine/dist/core/backends/cursor-ide.js
|
|
11490
|
-
import { existsSync as existsSync14, readFileSync as readFileSync9, readdirSync as readdirSync11, statSync as
|
|
10830
|
+
import { existsSync as existsSync14, readFileSync as readFileSync9, readdirSync as readdirSync11, statSync as statSync11 } from "fs";
|
|
11491
10831
|
import { dirname as dirname12, join as join15 } from "path";
|
|
11492
10832
|
function jsonOf(value) {
|
|
11493
10833
|
if (value == null)
|
|
@@ -11557,7 +10897,7 @@ function workspaceIndex(workspaceRoots) {
|
|
|
11557
10897
|
for (const id of entries) {
|
|
11558
10898
|
const dir = join15(root, id);
|
|
11559
10899
|
try {
|
|
11560
|
-
if (!
|
|
10900
|
+
if (!statSync11(dir).isDirectory())
|
|
11561
10901
|
continue;
|
|
11562
10902
|
} catch {
|
|
11563
10903
|
continue;
|
|
@@ -11903,7 +11243,7 @@ var init_cursor_ide = __esm({
|
|
|
11903
11243
|
});
|
|
11904
11244
|
|
|
11905
11245
|
// ../engine/dist/core/backends/cursor.js
|
|
11906
|
-
import { existsSync as existsSync15, readFileSync as readFileSync10, statSync as
|
|
11246
|
+
import { existsSync as existsSync15, readFileSync as readFileSync10, statSync as statSync12 } from "fs";
|
|
11907
11247
|
import { join as join16 } from "path";
|
|
11908
11248
|
var PREFIX4, CursorBackend, cursorBackend;
|
|
11909
11249
|
var init_cursor = __esm({
|
|
@@ -11956,7 +11296,7 @@ var init_cursor = __esm({
|
|
|
11956
11296
|
if (r.surface === "cli") {
|
|
11957
11297
|
let mtime2 = r.chat.updatedAtMs;
|
|
11958
11298
|
try {
|
|
11959
|
-
mtime2 =
|
|
11299
|
+
mtime2 = statSync12(r.chat.dbPath).mtimeMs || mtime2;
|
|
11960
11300
|
} catch {
|
|
11961
11301
|
}
|
|
11962
11302
|
return {
|
|
@@ -11969,7 +11309,7 @@ var init_cursor = __esm({
|
|
|
11969
11309
|
}
|
|
11970
11310
|
let mtime = r.composer.updatedAtMs;
|
|
11971
11311
|
try {
|
|
11972
|
-
mtime =
|
|
11312
|
+
mtime = statSync12(r.composer.globalDbPath).mtimeMs || mtime;
|
|
11973
11313
|
} catch {
|
|
11974
11314
|
}
|
|
11975
11315
|
return {
|
|
@@ -12215,7 +11555,7 @@ var init_cursor = __esm({
|
|
|
12215
11555
|
if (existsSync15(metaPath)) {
|
|
12216
11556
|
files.push({ name: "meta.json", bytes: readFileSync10(metaPath) });
|
|
12217
11557
|
}
|
|
12218
|
-
return { tool: "cursor", mtime:
|
|
11558
|
+
return { tool: "cursor", mtime: statSync12(r.chat.dbPath).mtimeMs, files };
|
|
12219
11559
|
}
|
|
12220
11560
|
const events = readComposerEvents(r.composer);
|
|
12221
11561
|
if (events.length === 0)
|
|
@@ -12223,7 +11563,7 @@ var init_cursor = __esm({
|
|
|
12223
11563
|
const body = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
12224
11564
|
return {
|
|
12225
11565
|
tool: "cursor",
|
|
12226
|
-
mtime:
|
|
11566
|
+
mtime: statSync12(r.composer.globalDbPath).mtimeMs,
|
|
12227
11567
|
files: [{ name: `${r.composer.composerId}.jsonl`, bytes: Buffer.from(body, "utf8") }]
|
|
12228
11568
|
};
|
|
12229
11569
|
} catch {
|
|
@@ -12240,75 +11580,525 @@ var init_cursor = __esm({
|
|
|
12240
11580
|
return "";
|
|
12241
11581
|
}
|
|
12242
11582
|
}
|
|
12243
|
-
};
|
|
12244
|
-
cursorBackend = new CursorBackend();
|
|
11583
|
+
};
|
|
11584
|
+
cursorBackend = new CursorBackend();
|
|
11585
|
+
}
|
|
11586
|
+
});
|
|
11587
|
+
|
|
11588
|
+
// ../engine/dist/core/backends/index.js
|
|
11589
|
+
var backends_exports = {};
|
|
11590
|
+
__export(backends_exports, {
|
|
11591
|
+
AgyBackend: () => AgyBackend,
|
|
11592
|
+
ClaudeBackend: () => ClaudeBackend,
|
|
11593
|
+
CodexBackend: () => CodexBackend,
|
|
11594
|
+
CursorBackend: () => CursorBackend,
|
|
11595
|
+
OpencodeBackend: () => OpencodeBackend,
|
|
11596
|
+
agyBackend: () => agyBackend,
|
|
11597
|
+
bootstrapBackends: () => bootstrapBackends,
|
|
11598
|
+
claudeBackend: () => claudeBackend,
|
|
11599
|
+
codexBackend: () => codexBackend,
|
|
11600
|
+
cursorBackend: () => cursorBackend,
|
|
11601
|
+
getBackend: () => getBackend,
|
|
11602
|
+
getBackendForId: () => getBackendForId,
|
|
11603
|
+
listAllBackends: () => listAllBackends,
|
|
11604
|
+
listAvailableBackends: () => listAvailableBackends,
|
|
11605
|
+
opencodeBackend: () => opencodeBackend,
|
|
11606
|
+
registerBackend: () => registerBackend,
|
|
11607
|
+
tryGetBackend: () => tryGetBackend
|
|
11608
|
+
});
|
|
11609
|
+
function bootstrapBackends() {
|
|
11610
|
+
registerBackend(claudeBackend);
|
|
11611
|
+
registerBackend(opencodeBackend);
|
|
11612
|
+
registerBackend(codexBackend);
|
|
11613
|
+
registerBackend(agyBackend);
|
|
11614
|
+
registerBackend(cursorBackend);
|
|
11615
|
+
}
|
|
11616
|
+
var init_backends = __esm({
|
|
11617
|
+
"../engine/dist/core/backends/index.js"() {
|
|
11618
|
+
"use strict";
|
|
11619
|
+
init_tool_backend();
|
|
11620
|
+
init_claude2();
|
|
11621
|
+
init_opencode();
|
|
11622
|
+
init_codex2();
|
|
11623
|
+
init_agy();
|
|
11624
|
+
init_cursor();
|
|
11625
|
+
init_tool_backend();
|
|
11626
|
+
_setRegistryBootstrapper(bootstrapBackends);
|
|
11627
|
+
}
|
|
11628
|
+
});
|
|
11629
|
+
|
|
11630
|
+
// ../engine/dist/core/collector-health.js
|
|
11631
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "node:fs";
|
|
11632
|
+
import { join as join17, dirname as dirname13 } from "node:path";
|
|
11633
|
+
function applySyncOutcome(prior, outcome, now = Date.now()) {
|
|
11634
|
+
const t = { lastOkAt: prior?.lastOkAt ?? null, failures: prior?.failures ?? 0 };
|
|
11635
|
+
if (prior?.lastError !== void 0)
|
|
11636
|
+
t.lastError = prior.lastError;
|
|
11637
|
+
if (outcome.ok) {
|
|
11638
|
+
t.lastOkAt = now;
|
|
11639
|
+
t.failures = 0;
|
|
11640
|
+
delete t.lastError;
|
|
11641
|
+
return t;
|
|
11642
|
+
}
|
|
11643
|
+
if ((outcome.accepted ?? 0) > 0)
|
|
11644
|
+
t.lastOkAt = now;
|
|
11645
|
+
t.failures += 1;
|
|
11646
|
+
t.lastError = (outcome.error ?? "unknown error").slice(0, 160);
|
|
11647
|
+
return t;
|
|
11648
|
+
}
|
|
11649
|
+
function collectorHealthPath() {
|
|
11650
|
+
return healthPath();
|
|
11651
|
+
}
|
|
11652
|
+
function readCollectorHealth() {
|
|
11653
|
+
try {
|
|
11654
|
+
const h = JSON.parse(readFileSync11(healthPath(), "utf-8"));
|
|
11655
|
+
return h && h.v === 1 && typeof h.updatedAt === "number" ? h : null;
|
|
11656
|
+
} catch {
|
|
11657
|
+
return null;
|
|
11658
|
+
}
|
|
11659
|
+
}
|
|
11660
|
+
function writeCollectorHealth(h) {
|
|
11661
|
+
try {
|
|
11662
|
+
const p = healthPath();
|
|
11663
|
+
mkdirSync4(dirname13(p), { recursive: true });
|
|
11664
|
+
writeFileSync3(p, JSON.stringify(h));
|
|
11665
|
+
} catch {
|
|
11666
|
+
}
|
|
11667
|
+
}
|
|
11668
|
+
function updateCollectorHealth(patch) {
|
|
11669
|
+
const prior = readCollectorHealth();
|
|
11670
|
+
writeCollectorHealth({
|
|
11671
|
+
...prior,
|
|
11672
|
+
v: 1,
|
|
11673
|
+
updatedAt: Date.now(),
|
|
11674
|
+
startedAt: prior?.startedAt ?? Date.now(),
|
|
11675
|
+
restartsLastHour: prior?.restartsLastHour ?? 0,
|
|
11676
|
+
targets: prior?.targets ?? {},
|
|
11677
|
+
...patch
|
|
11678
|
+
});
|
|
11679
|
+
}
|
|
11680
|
+
function reportWalkProgress(p) {
|
|
11681
|
+
const now = Date.now();
|
|
11682
|
+
const boundary = p.complete || p.done === 0;
|
|
11683
|
+
if (!boundary && now - lastProgressWrite < PROGRESS_WRITE_INTERVAL_MS)
|
|
11684
|
+
return;
|
|
11685
|
+
lastProgressWrite = now;
|
|
11686
|
+
updateCollectorHealth({ progress: p });
|
|
11687
|
+
}
|
|
11688
|
+
var healthPath, PROGRESS_WRITE_INTERVAL_MS, lastProgressWrite, STALE_AFTER_MS;
|
|
11689
|
+
var init_collector_health = __esm({
|
|
11690
|
+
"../engine/dist/core/collector-health.js"() {
|
|
11691
|
+
"use strict";
|
|
11692
|
+
init_paths();
|
|
11693
|
+
healthPath = () => join17(getDataDir(), "collector-health.json");
|
|
11694
|
+
PROGRESS_WRITE_INTERVAL_MS = 2e3;
|
|
11695
|
+
lastProgressWrite = 0;
|
|
11696
|
+
STALE_AFTER_MS = 30 * 6e4;
|
|
11697
|
+
}
|
|
11698
|
+
});
|
|
11699
|
+
|
|
11700
|
+
// ../engine/dist/core/credentials-env.js
|
|
11701
|
+
function envCredentials(env = process.env) {
|
|
11702
|
+
const token = (env.CHAT_RECALL_TOKEN || "").trim();
|
|
11703
|
+
const server = (env.CHAT_RECALL_SERVER || "").trim();
|
|
11704
|
+
if (!token || !server)
|
|
11705
|
+
return null;
|
|
11706
|
+
if (!/^https?:\/\//i.test(server))
|
|
11707
|
+
return null;
|
|
11708
|
+
return { serverUrl: normalise(server), token };
|
|
11709
|
+
}
|
|
11710
|
+
var normalise;
|
|
11711
|
+
var init_credentials_env = __esm({
|
|
11712
|
+
"../engine/dist/core/credentials-env.js"() {
|
|
11713
|
+
"use strict";
|
|
11714
|
+
normalise = (u) => u.trim().replace(/\/+$/, "");
|
|
11715
|
+
}
|
|
11716
|
+
});
|
|
11717
|
+
|
|
11718
|
+
// ../engine/dist/core/secret-redactor.js
|
|
11719
|
+
import { statSync as statSync13 } from "fs";
|
|
11720
|
+
function secretOf(rule, m) {
|
|
11721
|
+
const raw = rule.secret != null ? m[rule.secret] : m[0];
|
|
11722
|
+
if (raw == null)
|
|
11723
|
+
return null;
|
|
11724
|
+
if (rule.where && !rule.where(raw))
|
|
11725
|
+
return null;
|
|
11726
|
+
return raw;
|
|
11727
|
+
}
|
|
11728
|
+
function looksLikeSecretToken(t) {
|
|
11729
|
+
if (t.length < 32)
|
|
11730
|
+
return false;
|
|
11731
|
+
if (/^[a-f0-9]+$/i.test(t))
|
|
11732
|
+
return true;
|
|
11733
|
+
return /[A-Z]/.test(t) && /[a-z]/.test(t) && /[0-9]/.test(t);
|
|
11734
|
+
}
|
|
11735
|
+
function findContextualSecrets(text) {
|
|
11736
|
+
if (!text)
|
|
11737
|
+
return [];
|
|
11738
|
+
const ranges = [];
|
|
11739
|
+
let m;
|
|
11740
|
+
SECRET_CONTEXT_RE.lastIndex = 0;
|
|
11741
|
+
while ((m = SECRET_CONTEXT_RE.exec(text)) !== null) {
|
|
11742
|
+
const winStart = m.index + m[0].length;
|
|
11743
|
+
const window = text.slice(winStart, winStart + 80);
|
|
11744
|
+
HIGH_ENTROPY_TOKEN_RE.lastIndex = 0;
|
|
11745
|
+
let tm;
|
|
11746
|
+
while ((tm = HIGH_ENTROPY_TOKEN_RE.exec(window)) !== null) {
|
|
11747
|
+
if (!looksLikeSecretToken(tm[0]))
|
|
11748
|
+
continue;
|
|
11749
|
+
if (/^[a-f0-9]+$/i.test(tm[0]) && /\b(?:commit|sha-?\d*|hash|digest|checksum|uuid|guid|etag|blob|ref)\b/i.test(window.slice(0, tm.index))) {
|
|
11750
|
+
continue;
|
|
11751
|
+
}
|
|
11752
|
+
ranges.push({ start: winStart + tm.index, end: winStart + tm.index + tm[0].length });
|
|
11753
|
+
break;
|
|
11754
|
+
}
|
|
11755
|
+
}
|
|
11756
|
+
ranges.sort((a, b) => a.start - b.start);
|
|
11757
|
+
const out = [];
|
|
11758
|
+
for (const r of ranges) {
|
|
11759
|
+
const last = out[out.length - 1];
|
|
11760
|
+
if (last && r.start < last.end) {
|
|
11761
|
+
last.end = Math.max(last.end, r.end);
|
|
11762
|
+
continue;
|
|
11763
|
+
}
|
|
11764
|
+
out.push({ ...r });
|
|
11765
|
+
}
|
|
11766
|
+
return out;
|
|
11767
|
+
}
|
|
11768
|
+
function isEnvRedactionRequested() {
|
|
11769
|
+
const v = process.env.CHAT_RECALL_REDACT_INDEX;
|
|
11770
|
+
if (v === void 0)
|
|
11771
|
+
return null;
|
|
11772
|
+
return v === "1" || v === "true" || v === "yes";
|
|
11773
|
+
}
|
|
11774
|
+
function settingsView() {
|
|
11775
|
+
let mtimeMs = -1;
|
|
11776
|
+
try {
|
|
11777
|
+
mtimeMs = statSync13(settingsFilePath()).mtimeMs;
|
|
11778
|
+
} catch {
|
|
11779
|
+
}
|
|
11780
|
+
if (cache && cache.mtimeMs === mtimeMs)
|
|
11781
|
+
return cache;
|
|
11782
|
+
let enabled = false;
|
|
11783
|
+
const extra = [];
|
|
11784
|
+
try {
|
|
11785
|
+
const s = loadSettings();
|
|
11786
|
+
enabled = !!s.privacy?.redactIndex;
|
|
11787
|
+
for (const r of s.privacy?.redactionRules ?? []) {
|
|
11788
|
+
try {
|
|
11789
|
+
extra.push({ label: r.label, pattern: new RegExp(r.pattern, "g") });
|
|
11790
|
+
} catch {
|
|
11791
|
+
}
|
|
11792
|
+
}
|
|
11793
|
+
} catch {
|
|
12245
11794
|
}
|
|
12246
|
-
}
|
|
12247
|
-
|
|
12248
|
-
// ../engine/dist/core/backends/index.js
|
|
12249
|
-
var backends_exports = {};
|
|
12250
|
-
__export(backends_exports, {
|
|
12251
|
-
AgyBackend: () => AgyBackend,
|
|
12252
|
-
ClaudeBackend: () => ClaudeBackend,
|
|
12253
|
-
CodexBackend: () => CodexBackend,
|
|
12254
|
-
CursorBackend: () => CursorBackend,
|
|
12255
|
-
OpencodeBackend: () => OpencodeBackend,
|
|
12256
|
-
agyBackend: () => agyBackend,
|
|
12257
|
-
bootstrapBackends: () => bootstrapBackends,
|
|
12258
|
-
claudeBackend: () => claudeBackend,
|
|
12259
|
-
codexBackend: () => codexBackend,
|
|
12260
|
-
cursorBackend: () => cursorBackend,
|
|
12261
|
-
getBackend: () => getBackend,
|
|
12262
|
-
getBackendForId: () => getBackendForId,
|
|
12263
|
-
listAllBackends: () => listAllBackends,
|
|
12264
|
-
listAvailableBackends: () => listAvailableBackends,
|
|
12265
|
-
opencodeBackend: () => opencodeBackend,
|
|
12266
|
-
registerBackend: () => registerBackend,
|
|
12267
|
-
tryGetBackend: () => tryGetBackend
|
|
12268
|
-
});
|
|
12269
|
-
function bootstrapBackends() {
|
|
12270
|
-
registerBackend(claudeBackend);
|
|
12271
|
-
registerBackend(opencodeBackend);
|
|
12272
|
-
registerBackend(codexBackend);
|
|
12273
|
-
registerBackend(agyBackend);
|
|
12274
|
-
registerBackend(cursorBackend);
|
|
11795
|
+
cache = { mtimeMs, enabled, rules: [...DEFAULT_REDACTION_RULES, ...extra] };
|
|
11796
|
+
return cache;
|
|
12275
11797
|
}
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
11798
|
+
function compileServerRule(spec) {
|
|
11799
|
+
const name = spec.name || "(unnamed)";
|
|
11800
|
+
if (!spec.regex)
|
|
11801
|
+
return { name, reason: "empty pattern" };
|
|
11802
|
+
if (spec.regex.length > MAX_PATTERN_LEN)
|
|
11803
|
+
return { name, reason: `pattern longer than ${MAX_PATTERN_LEN} chars` };
|
|
11804
|
+
let re;
|
|
11805
|
+
try {
|
|
11806
|
+
const flags = "g" + (spec.flags || "").replace(/[^ims]/g, "");
|
|
11807
|
+
re = new RegExp(spec.regex, flags);
|
|
11808
|
+
} catch (e) {
|
|
11809
|
+
return { name, reason: `invalid regex: ${e instanceof Error ? e.message : e}` };
|
|
12287
11810
|
}
|
|
12288
|
-
|
|
12289
|
-
|
|
12290
|
-
|
|
12291
|
-
|
|
12292
|
-
|
|
12293
|
-
|
|
12294
|
-
|
|
12295
|
-
return null;
|
|
12296
|
-
if (!/^https?:\/\//i.test(server))
|
|
12297
|
-
return null;
|
|
12298
|
-
return { serverUrl: normalise(server), token };
|
|
11811
|
+
if (re.test(""))
|
|
11812
|
+
return { name, reason: "matches the empty string (would redact everything)" };
|
|
11813
|
+
re.lastIndex = 0;
|
|
11814
|
+
if (re.test(CANARY))
|
|
11815
|
+
return { name, reason: "matches benign text \u2014 too broad" };
|
|
11816
|
+
re.lastIndex = 0;
|
|
11817
|
+
return { label: `${spec.source === "pack" ? "pack" : "tenant"}:${name}`, pattern: re };
|
|
12299
11818
|
}
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
11819
|
+
function installServerRulePack(pack) {
|
|
11820
|
+
const rejected = [];
|
|
11821
|
+
const rules = [];
|
|
11822
|
+
for (const spec of pack.rules || []) {
|
|
11823
|
+
if (rules.length >= MAX_PACK_RULES) {
|
|
11824
|
+
rejected.push({ name: spec.name || "(unnamed)", reason: `pack exceeds ${MAX_PACK_RULES} rules` });
|
|
11825
|
+
continue;
|
|
11826
|
+
}
|
|
11827
|
+
const out = compileServerRule(spec);
|
|
11828
|
+
if ("reason" in out)
|
|
11829
|
+
rejected.push(out);
|
|
11830
|
+
else
|
|
11831
|
+
rules.push(out);
|
|
11832
|
+
}
|
|
11833
|
+
const version = pack.version || "";
|
|
11834
|
+
serverPack = { version, rules };
|
|
11835
|
+
return { version, accepted: rules.length, rejected };
|
|
11836
|
+
}
|
|
11837
|
+
function serverRulePackVersion() {
|
|
11838
|
+
return serverPack ? serverPack.version || "unversioned" : null;
|
|
11839
|
+
}
|
|
11840
|
+
function activeRules() {
|
|
11841
|
+
const base2 = settingsView().rules;
|
|
11842
|
+
return serverPack && serverPack.rules.length > 0 ? [...base2, ...serverPack.rules] : base2;
|
|
11843
|
+
}
|
|
11844
|
+
function isRedactionEnabled() {
|
|
11845
|
+
const env = isEnvRedactionRequested();
|
|
11846
|
+
if (env !== null)
|
|
11847
|
+
return env;
|
|
11848
|
+
return settingsView().enabled;
|
|
11849
|
+
}
|
|
11850
|
+
function redactSecrets(text, opts = {}) {
|
|
11851
|
+
if (!opts.force && !isRedactionEnabled())
|
|
11852
|
+
return text;
|
|
11853
|
+
if (!text)
|
|
11854
|
+
return text;
|
|
11855
|
+
const rules = opts.rules || activeRules();
|
|
11856
|
+
let out = text;
|
|
11857
|
+
for (const r of rules) {
|
|
11858
|
+
out = out.replace(r.pattern, (...args) => {
|
|
11859
|
+
const whole = args[0];
|
|
11860
|
+
const m = args.slice(0, args.length);
|
|
11861
|
+
const secret = secretOf(r, m);
|
|
11862
|
+
if (secret == null)
|
|
11863
|
+
return whole;
|
|
11864
|
+
if (opts.count)
|
|
11865
|
+
opts.count.redactions++;
|
|
11866
|
+
return whole.slice(0, whole.length - secret.length) + `[REDACTED:${r.label}]`;
|
|
11867
|
+
});
|
|
11868
|
+
}
|
|
11869
|
+
const ctx = findContextualSecrets(out);
|
|
11870
|
+
for (let i = ctx.length - 1; i >= 0; i--) {
|
|
11871
|
+
const { start, end } = ctx[i];
|
|
11872
|
+
if (opts.count)
|
|
11873
|
+
opts.count.redactions++;
|
|
11874
|
+
out = out.slice(0, start) + "[REDACTED:secret-context]" + out.slice(end);
|
|
11875
|
+
}
|
|
11876
|
+
return out;
|
|
11877
|
+
}
|
|
11878
|
+
function maskSecret(s) {
|
|
11879
|
+
if (!s)
|
|
11880
|
+
return "";
|
|
11881
|
+
if (s.length <= 4)
|
|
11882
|
+
return "*".repeat(s.length);
|
|
11883
|
+
return "*".repeat(Math.min(s.length - 4, 60)) + s.slice(-4);
|
|
11884
|
+
}
|
|
11885
|
+
function globalRegexFor(pattern) {
|
|
11886
|
+
const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
|
|
11887
|
+
const key2 = pattern.source + "\0" + flags;
|
|
11888
|
+
let re = globalRegexCache.get(key2);
|
|
11889
|
+
if (!re) {
|
|
11890
|
+
re = new RegExp(pattern.source, flags);
|
|
11891
|
+
globalRegexCache.set(key2, re);
|
|
11892
|
+
}
|
|
11893
|
+
return re;
|
|
11894
|
+
}
|
|
11895
|
+
function makeLineResolver(text) {
|
|
11896
|
+
const starts = [];
|
|
11897
|
+
for (let i = text.indexOf("\n"); i !== -1; i = text.indexOf("\n", i + 1))
|
|
11898
|
+
starts.push(i);
|
|
11899
|
+
return (index) => {
|
|
11900
|
+
let lo = 0, hi = starts.length;
|
|
11901
|
+
while (lo < hi) {
|
|
11902
|
+
const mid = lo + hi >> 1;
|
|
11903
|
+
if (starts[mid] < index)
|
|
11904
|
+
lo = mid + 1;
|
|
11905
|
+
else
|
|
11906
|
+
hi = mid;
|
|
11907
|
+
}
|
|
11908
|
+
return lo + 1;
|
|
11909
|
+
};
|
|
11910
|
+
}
|
|
11911
|
+
function scanTextForFindings(text, opts = {}) {
|
|
11912
|
+
if (!text)
|
|
11913
|
+
return [];
|
|
11914
|
+
const rules = opts.rules || activeRules();
|
|
11915
|
+
const findings = [];
|
|
11916
|
+
const seenSpans = /* @__PURE__ */ new Set();
|
|
11917
|
+
const lineAt = makeLineResolver(text);
|
|
11918
|
+
for (const r of rules) {
|
|
11919
|
+
const re = globalRegexFor(r.pattern);
|
|
11920
|
+
re.lastIndex = 0;
|
|
11921
|
+
let m;
|
|
11922
|
+
while ((m = re.exec(text)) !== null) {
|
|
11923
|
+
const secret = secretOf(r, m);
|
|
11924
|
+
if (secret == null) {
|
|
11925
|
+
if (re.lastIndex === m.index)
|
|
11926
|
+
re.lastIndex++;
|
|
11927
|
+
continue;
|
|
11928
|
+
}
|
|
11929
|
+
const at = m.index + (m[0].length - secret.length);
|
|
11930
|
+
const span = `${at}:${secret.length}`;
|
|
11931
|
+
if (!seenSpans.has(span)) {
|
|
11932
|
+
seenSpans.add(span);
|
|
11933
|
+
findings.push({ rule: r.label, line: lineAt(at), preview: maskSecret(secret) });
|
|
11934
|
+
}
|
|
11935
|
+
if (re.lastIndex === m.index)
|
|
11936
|
+
re.lastIndex++;
|
|
11937
|
+
}
|
|
11938
|
+
}
|
|
11939
|
+
for (const { start, end } of findContextualSecrets(text)) {
|
|
11940
|
+
const line = lineAt(start);
|
|
11941
|
+
findings.push({ rule: "secret-context", line, preview: maskSecret(text.slice(start, end)) });
|
|
11942
|
+
}
|
|
11943
|
+
return findings;
|
|
11944
|
+
}
|
|
11945
|
+
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache;
|
|
11946
|
+
var init_secret_redactor = __esm({
|
|
11947
|
+
"../engine/dist/core/secret-redactor.js"() {
|
|
12303
11948
|
"use strict";
|
|
12304
|
-
|
|
11949
|
+
init_settings();
|
|
11950
|
+
DEFAULT_REDACTION_RULES = [
|
|
11951
|
+
// AWS access tokens. Prefix-anchored: AKIA, ASIA, ABIA (long-term,
|
|
11952
|
+
// STS, EC2). Always exactly 16 hex/alphanumeric after the prefix.
|
|
11953
|
+
// NOTE: this matches only the access-key-ID, NOT the secret key value —
|
|
11954
|
+
// the `env-secret` rule below covers AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN.
|
|
11955
|
+
{ label: "aws-access-token", pattern: /\b(?:AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}\b/g },
|
|
11956
|
+
// AWS STS session tokens. These are long base64 blobs with NO `NAME=` context
|
|
11957
|
+
// when pasted bare into prose/code, so `env-secret` misses them — but they
|
|
11958
|
+
// reliably start with one of a handful of base64 prefixes (the encoded
|
|
11959
|
+
// `{"...` JSON header). Prefix-anchored → low false-positive. This is the
|
|
11960
|
+
// bare-value form that leaked (`search('IQoJEXAMPLEfakeSESSIONtokenNOTreal01234567890abcDEF==...')`).
|
|
11961
|
+
{ label: "aws-session-token", pattern: /\b(?:IQoJ|FwoG|FwoH|FQoG|FQoH|FwoD)[A-Za-z0-9/+]{40,}={0,2}/g },
|
|
11962
|
+
// Env/shell-assignment secrets — a VAR whose name ends in KEY/SECRET/TOKEN/
|
|
11963
|
+
// PASSWORD/CREDENTIAL, then `=`/`:`, then the value. Zero-width lookbehind so
|
|
11964
|
+
// only the VALUE is redacted (the var name stays for context). This is the
|
|
11965
|
+
// dominant real-world leak vector (`export` dumps, .env files, `curl -H`,
|
|
11966
|
+
// tool output) and is exactly what leaked AWS_SECRET_ACCESS_KEY and
|
|
11967
|
+
// AWS_SESSION_TOKEN in cleartext while the access-key-ID rule above caught
|
|
11968
|
+
// only the (least-sensitive) ID.
|
|
11969
|
+
// Suffix list deliberately broad: DB_PASS (our own helm chart's name!),
|
|
11970
|
+
// NPM_AUTH, SENTRY_DSN, SESSION/COOKIE secrets and BEARER vars all leaked
|
|
11971
|
+
// past the original KEY/SECRET/TOKEN/PASSWORD-only list. Values under 12
|
|
11972
|
+
// chars don't redact, so flag-ish vars (BYPASS=true) stay readable.
|
|
11973
|
+
// Context CONSUMED, secret in group 1 — see RedactionRule.secret. As a
|
|
11974
|
+
// lookbehind this was the second most expensive rule in the collector.
|
|
11975
|
+
{ label: "env-secret", secret: 1, pattern: /\b[A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASSWORD|PASSWD|PASS|PWD|CREDENTIAL|AUTH|DSN|SESSION|COOKIE|BEARER|SIGNATURE)S?["']?[ \t]{0,3}[:=][ \t]{0,3}["']?([A-Za-z0-9/+_.~=:@-]{12,})/g },
|
|
11976
|
+
// Credentials embedded in a connection URL: scheme://user:PASSWORD@host.
|
|
11977
|
+
// Redacts only the password segment (keeps scheme/user/host for context).
|
|
11978
|
+
//
|
|
11979
|
+
// Scheme-agnostic on purpose. The old rule allowlisted eight DB schemes, so
|
|
11980
|
+
// `https://user:pass@host`, `ssh://`, `ftp://`, `smtp://` and every other
|
|
11981
|
+
// userinfo URL walked through in cleartext — and a `jdbc:postgresql://…`
|
|
11982
|
+
// prefix broke the \b anchor for the one family it did cover. Any scheme
|
|
11983
|
+
// followed by userinfo is a credential, so match the shape, not a list.
|
|
11984
|
+
{ label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/]{1,64}:([^@\s/]{1,256})(?=@)/g },
|
|
11985
|
+
// Bare AWS secret-access-key VALUE: EXACTLY 40 base64 chars, word-bounded,
|
|
11986
|
+
// containing upper+lower+digit. This is the gitleaks heuristic — the mixed-case
|
|
11987
|
+
// requirement excludes 40-char lowercase-hex git SHAs, and the exact-40 bound
|
|
11988
|
+
// excludes longer blobs/tokens. It catches the value when it appears bare in
|
|
11989
|
+
// prose with NO `NAME=` and NO nearby context word (e.g. inside a markdown
|
|
11990
|
+
// table or quoted in analysis) — the residual leak path the env-secret and
|
|
11991
|
+
// contextual rules both miss. Placed AFTER env-secret/url-password so the
|
|
11992
|
+
// keyed/URL forms keep their more-specific labels.
|
|
11993
|
+
// The three stacked lookaheads each re-scanned the same 40 characters, which
|
|
11994
|
+
// made this the MOST expensive rule of all 106 the collector runs (13.1% of a
|
|
11995
|
+
// 29.5 MB scan). The mixed-case-plus-digit test is now one JS pass.
|
|
11996
|
+
{
|
|
11997
|
+
label: "aws-secret-key",
|
|
11998
|
+
secret: 1,
|
|
11999
|
+
pattern: /(?<![A-Za-z0-9/+])([A-Za-z0-9/+]{40})(?![A-Za-z0-9/+])/g,
|
|
12000
|
+
where: (v) => /[a-z]/.test(v) && /[A-Z]/.test(v) && /[0-9]/.test(v)
|
|
12001
|
+
},
|
|
12002
|
+
// GitHub personal access tokens.
|
|
12003
|
+
{ label: "github-pat", pattern: /\bghp_[A-Za-z0-9]{36}\b/g },
|
|
12004
|
+
// GitHub fine-grained PATs.
|
|
12005
|
+
{ label: "github-fine", pattern: /\bgithub_pat_[A-Za-z0-9_]{82}\b/g },
|
|
12006
|
+
// GitHub OAuth.
|
|
12007
|
+
{ label: "github-oauth", pattern: /\bgho_[A-Za-z0-9]{36}\b/g },
|
|
12008
|
+
// GitHub app + refresh.
|
|
12009
|
+
{ label: "github-app", pattern: /\b(?:ghs|ghu|ghr)_[A-Za-z0-9]{36}\b/g },
|
|
12010
|
+
// Slack bot/user/app tokens.
|
|
12011
|
+
{ label: "slack-token", pattern: /\bxox[abopr]-[A-Za-z0-9-]{10,}\b/g },
|
|
12012
|
+
// Slack incoming webhook URL.
|
|
12013
|
+
{ label: "slack-webhook", pattern: /\bhttps:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+\b/g },
|
|
12014
|
+
// Stripe live + test keys.
|
|
12015
|
+
{ label: "stripe-key", pattern: /\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g },
|
|
12016
|
+
// Anthropic.
|
|
12017
|
+
{ label: "anthropic-key", pattern: /\bsk-ant-[a-zA-Z0-9_-]{40,}\b/g },
|
|
12018
|
+
// OpenAI. Two shapes, deliberately kept apart. The classic key is
|
|
12019
|
+
// `sk-` + base62 with NO hyphens; the modern scoped keys carry an explicit
|
|
12020
|
+
// proj/svcacct/admin segment first. Allowing hyphens after a bare `sk-`
|
|
12021
|
+
// (which is what admitted sk-proj- in the first place) also matches ordinary
|
|
12022
|
+
// kebab-case text — `sk-fix-the-login-redirect-bug`, `.sk-button-primary`,
|
|
12023
|
+
// `sk-2024-01-01-backup` — and this corpus is full of branch names and CSS
|
|
12024
|
+
// classes. Requiring the segment keeps sk-proj- coverage without that.
|
|
12025
|
+
{ label: "openai-key", pattern: /\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{20,}\b|\bsk-[A-Za-z0-9]{20,}\b/g },
|
|
12026
|
+
// Google API key (AIza…).
|
|
12027
|
+
{ label: "google-api-key", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
12028
|
+
// Generic JWT — three base64url segments.
|
|
12029
|
+
{ label: "jwt", pattern: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g },
|
|
12030
|
+
// Private key blocks (PEM). The label is a free word run rather than a fixed
|
|
12031
|
+
// list, so ENCRYPTED PRIVATE KEY and PGP PRIVATE KEY BLOCK are covered
|
|
12032
|
+
// without another enumeration, and \1 forces END to name the same kind as
|
|
12033
|
+
// BEGIN.
|
|
12034
|
+
//
|
|
12035
|
+
// The body is [^-], NOT [\s\S]*?. That is a performance boundary, not a
|
|
12036
|
+
// style choice. An unanchored prefix with an unbounded lazy gap re-scans to
|
|
12037
|
+
// end-of-input from every candidate start, so text carrying many BEGIN
|
|
12038
|
+
// markers and no matching END costs O(n^2): 500KB of that measured 810ms
|
|
12039
|
+
// here, and this runs synchronously on the server's event loop over
|
|
12040
|
+
// tenant-supplied text (services/secret-rescan.ts). A PEM body is base64
|
|
12041
|
+
// plus headers and contains no '-', so excluding it makes the scan stop at
|
|
12042
|
+
// the next delimiter instead of at EOF — same matches, linear cost.
|
|
12043
|
+
{ label: "private-key", pattern: /-----BEGIN ([A-Z0-9 ]{0,32})PRIVATE KEY(?: BLOCK)?-----[^-]{0,10000}?-----END \1PRIVATE KEY(?: BLOCK)?-----/g },
|
|
12044
|
+
// PuTTY keys are not PEM. Match the Private-Lines payload — the actual key
|
|
12045
|
+
// material — rather than spanning the whole file, which would need the same
|
|
12046
|
+
// unbounded gap the rule above just removed. Line-anchored and base64-only,
|
|
12047
|
+
// so it cannot run away.
|
|
12048
|
+
{ label: "putty-key", pattern: /^Private-Lines:[ \t]*\d{1,4}[\r\n]+(?:[A-Za-z0-9+/=]{8,120}[\r\n]+){1,400}/gm },
|
|
12049
|
+
// npm tokens (uuid-shaped — overlap with our UUID filter; intentional).
|
|
12050
|
+
{ label: "npm-token", pattern: /\bnpm_[A-Za-z0-9]{36}\b/g },
|
|
12051
|
+
// .npmrc auth lines: //registry.npmjs.org/:_authToken=VALUE (the key is not
|
|
12052
|
+
// ALL-CAPS, so the env-secret rule above never matched it). The leading `:`
|
|
12053
|
+
// is required — it is what makes this npmrc syntax rather than any shell var
|
|
12054
|
+
// ending in _AUTH, which env-secret already owns and labels better.
|
|
12055
|
+
// [^\s"'`]+ so the closing quote is not swallowed, and a ${VAR} placeholder
|
|
12056
|
+
// is left alone — redacting it destroys a config example and hides nothing.
|
|
12057
|
+
// The rule the perf profile caught the wedged daemon inside: 98.94% of samples.
|
|
12058
|
+
{ label: "npmrc-auth", secret: 1, pattern: /:_(?:authToken|password|auth)[ \t]*=[ \t]*(?!\$\{)([^\s"'`]{12,})/gi },
|
|
12059
|
+
// HTTP Authorization headers. env-secret requires an ALL-CAPS name, and
|
|
12060
|
+
// `Authorization` is mixed case, so both Bearer and Basic walked straight
|
|
12061
|
+
// through — including short opaque tokens the contextual pass also misses
|
|
12062
|
+
// (it needs 32+ chars AND mixed-case-plus-digit).
|
|
12063
|
+
// Same two guards as npmrc-auth: stop at a quote, and skip the obvious
|
|
12064
|
+
// placeholders that fill documentation (<YOUR_TOKEN>, ${TOKEN}, xxx…).
|
|
12065
|
+
{ label: "auth-header", secret: 1, pattern: /\bauthorization[ \t]*:[ \t]*(?:bearer|basic|token)[ \t]+(?![<$])([^\s"'`<]{8,})/gi },
|
|
12066
|
+
// Vendor tokens with unambiguous prefixes. Each is a fixed literal, so a
|
|
12067
|
+
// false positive is essentially impossible and the cost of listing is low.
|
|
12068
|
+
{ label: "gitlab-pat", pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
|
|
12069
|
+
{ label: "slack-app-token", pattern: /\bxapp-\d-[A-Z0-9]{8,}-\d{10,}-[a-f0-9]{32,}\b/g },
|
|
12070
|
+
{ label: "sendgrid-key", pattern: /\bSG\.[A-Za-z0-9_-]{20,24}\.[A-Za-z0-9_-]{40,50}\b/g },
|
|
12071
|
+
// (?<![-\w]) so `cache-key-<md5>` is not read as a mailgun key.
|
|
12072
|
+
{ label: "mailgun-key", pattern: /(?<![-\w])key-[a-f0-9]{32}\b/g },
|
|
12073
|
+
{ label: "digitalocean-pat", pattern: /\bdop_v1_[a-f0-9]{64}\b/g },
|
|
12074
|
+
{ label: "huggingface-token", pattern: /\bhf_[A-Za-z0-9]{30,}\b/g },
|
|
12075
|
+
{ label: "shopify-token", pattern: /\bshp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}\b/g },
|
|
12076
|
+
{ label: "pypi-token", pattern: /\bpypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}\b/g },
|
|
12077
|
+
// No twilio-sid rule: AC…/SK… are Twilio SIDs, which are public account and
|
|
12078
|
+
// key identifiers, not the auth token. Redacting them hid nothing and
|
|
12079
|
+
// collided with 32-hex etags and MD5 sums.
|
|
12080
|
+
// No discord-bot-token rule either: the shape (word.word.word) matched
|
|
12081
|
+
// ordinary dotted symbols such as a.b.ApplicationContextProviderImpl.
|
|
12082
|
+
{ label: "telegram-bot-token", pattern: /\b\d{8,10}:AA[A-Za-z0-9_-]{32,}\b/g },
|
|
12083
|
+
{ label: "doppler-token", pattern: /\bdp\.(?:pt|st|sa|ct)\.[A-Za-z0-9_-]{20,}\b/g },
|
|
12084
|
+
// Azure Storage SAS signature — the `sig=` parameter is the actual secret.
|
|
12085
|
+
{ label: "azure-sas", secret: 1, pattern: /[?&]sig=([A-Za-z0-9%/+=]{20,})/g }
|
|
12086
|
+
];
|
|
12087
|
+
SECRET_CONTEXT_RE = /\b(?:secret|password|passwd|credential|access[ _-]?key|private[ _-]?key|api[ _-]?key|auth(?:oriz\w*)?|bearer|token)\b/gi;
|
|
12088
|
+
HIGH_ENTROPY_TOKEN_RE = /[A-Za-z0-9/+_-]{32,}/g;
|
|
12089
|
+
cache = null;
|
|
12090
|
+
CANARY = "the quick brown fox jumps over the lazy dog 0123456789 commit 8ba1f109551bd432803012645ac136ddd475d0fb src/index.ts:42";
|
|
12091
|
+
MAX_PACK_RULES = 200;
|
|
12092
|
+
MAX_PATTERN_LEN = 512;
|
|
12093
|
+
serverPack = null;
|
|
12094
|
+
globalRegexCache = /* @__PURE__ */ new Map();
|
|
12305
12095
|
}
|
|
12306
12096
|
});
|
|
12307
12097
|
|
|
12308
12098
|
// ../engine/dist/core/source-discovery.js
|
|
12309
12099
|
import { createHash as createHash3 } from "crypto";
|
|
12310
12100
|
import { existsSync as existsSync16, readdirSync as readdirSync12, statSync as statSync14 } from "fs";
|
|
12311
|
-
import { join as
|
|
12101
|
+
import { join as join18 } from "path";
|
|
12312
12102
|
function sourceId(path) {
|
|
12313
12103
|
return "src_" + createHash3("sha256").update(path).digest("hex").slice(0, 12);
|
|
12314
12104
|
}
|
|
@@ -12347,7 +12137,7 @@ function countTranscripts(root, tool) {
|
|
|
12347
12137
|
return;
|
|
12348
12138
|
}
|
|
12349
12139
|
for (const e of entries) {
|
|
12350
|
-
const full =
|
|
12140
|
+
const full = join18(dir, e.name);
|
|
12351
12141
|
if (e.isDirectory()) {
|
|
12352
12142
|
walk(full, depth + 1);
|
|
12353
12143
|
continue;
|
|
@@ -12411,9 +12201,9 @@ var init_source_discovery = __esm({
|
|
|
12411
12201
|
|
|
12412
12202
|
// ../engine/dist/core/home-discovery.js
|
|
12413
12203
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
12414
|
-
import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as
|
|
12204
|
+
import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as readFileSync12, realpathSync as realpathSync2, statSync as statSync15 } from "fs";
|
|
12415
12205
|
import { homedir as homedir5, platform as osPlatform } from "os";
|
|
12416
|
-
import { join as
|
|
12206
|
+
import { join as join19 } from "path";
|
|
12417
12207
|
function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
12418
12208
|
const home = homedir5();
|
|
12419
12209
|
const roots = [home];
|
|
@@ -12426,23 +12216,23 @@ function candidateRoots(plat = osPlatform(), env = process.env) {
|
|
|
12426
12216
|
add(env.LOCALAPPDATA);
|
|
12427
12217
|
add(env.USERPROFILE);
|
|
12428
12218
|
} else if (plat === "darwin") {
|
|
12429
|
-
add(
|
|
12219
|
+
add(join19(home, "Library", "Application Support"));
|
|
12430
12220
|
add(env.XDG_CONFIG_HOME);
|
|
12431
12221
|
} else {
|
|
12432
|
-
add(env.XDG_CONFIG_HOME ||
|
|
12433
|
-
add(env.XDG_DATA_HOME ||
|
|
12222
|
+
add(env.XDG_CONFIG_HOME || join19(home, ".config"));
|
|
12223
|
+
add(env.XDG_DATA_HOME || join19(home, ".local", "share"));
|
|
12434
12224
|
}
|
|
12435
12225
|
return roots.filter((r) => existsSync17(r));
|
|
12436
12226
|
}
|
|
12437
12227
|
function identifyHome(dir) {
|
|
12438
|
-
const has = (...parts) => existsSync17(
|
|
12439
|
-
if (has("projects") && dirHasTranscript(
|
|
12228
|
+
const has = (...parts) => existsSync17(join19(dir, ...parts));
|
|
12229
|
+
if (has("projects") && dirHasTranscript(join19(dir, "projects"), (f) => f.endsWith(".jsonl"), 2))
|
|
12440
12230
|
return "claude";
|
|
12441
|
-
if (has("sessions") && dirHasTranscript(
|
|
12231
|
+
if (has("sessions") && dirHasTranscript(join19(dir, "sessions"), (f) => f.startsWith("rollout-") && f.endsWith(".jsonl"), 4))
|
|
12442
12232
|
return "codex";
|
|
12443
|
-
if (has("brain") && dirHasTranscript(
|
|
12233
|
+
if (has("brain") && dirHasTranscript(join19(dir, "brain"), (f) => f.endsWith(".jsonl"), 4))
|
|
12444
12234
|
return "agy";
|
|
12445
|
-
if (has("chats") && dirHasTranscript(
|
|
12235
|
+
if (has("chats") && dirHasTranscript(join19(dir, "chats"), (f) => f === "store.db", 3))
|
|
12446
12236
|
return "cursor";
|
|
12447
12237
|
if (has("opencode.db"))
|
|
12448
12238
|
return "opencode";
|
|
@@ -12462,7 +12252,7 @@ function dirHasTranscript(root, match, depth) {
|
|
|
12462
12252
|
continue;
|
|
12463
12253
|
if (e.isFile() && match(e.name))
|
|
12464
12254
|
return true;
|
|
12465
|
-
if (e.isDirectory() && dirHasTranscript(
|
|
12255
|
+
if (e.isDirectory() && dirHasTranscript(join19(root, e.name), match, depth - 1))
|
|
12466
12256
|
return true;
|
|
12467
12257
|
}
|
|
12468
12258
|
return false;
|
|
@@ -12492,12 +12282,12 @@ function countSessions(dir, tool) {
|
|
|
12492
12282
|
if (SKIP.has(e.name))
|
|
12493
12283
|
continue;
|
|
12494
12284
|
if (e.isDirectory())
|
|
12495
|
-
walk(
|
|
12285
|
+
walk(join19(d, e.name), depth - 1);
|
|
12496
12286
|
else if (s.match(e.name))
|
|
12497
12287
|
n++;
|
|
12498
12288
|
}
|
|
12499
12289
|
};
|
|
12500
|
-
walk(
|
|
12290
|
+
walk(join19(dir, s.sub), s.depth);
|
|
12501
12291
|
return n;
|
|
12502
12292
|
}
|
|
12503
12293
|
function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
@@ -12531,11 +12321,11 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
12531
12321
|
return out;
|
|
12532
12322
|
}
|
|
12533
12323
|
const home = homedir5();
|
|
12534
|
-
const rcs = [".bashrc", ".bash_profile", ".zshrc", ".zprofile", ".profile"].map((f) =>
|
|
12324
|
+
const rcs = [".bashrc", ".bash_profile", ".zshrc", ".zprofile", ".profile"].map((f) => join19(home, f)).concat([join19(home, ".config", "fish", "config.fish")]);
|
|
12535
12325
|
for (const rc of rcs) {
|
|
12536
12326
|
let text;
|
|
12537
12327
|
try {
|
|
12538
|
-
text =
|
|
12328
|
+
text = readFileSync12(rc, "utf-8");
|
|
12539
12329
|
} catch {
|
|
12540
12330
|
continue;
|
|
12541
12331
|
}
|
|
@@ -12546,7 +12336,7 @@ function declaredHomes(env = process.env, plat = osPlatform()) {
|
|
|
12546
12336
|
add(d);
|
|
12547
12337
|
}
|
|
12548
12338
|
}
|
|
12549
|
-
return out.map((p) => p.startsWith("~") ?
|
|
12339
|
+
return out.map((p) => p.startsWith("~") ? join19(home, p.slice(1)) : p);
|
|
12550
12340
|
}
|
|
12551
12341
|
function runningToolHomes(plat = osPlatform()) {
|
|
12552
12342
|
const out = [];
|
|
@@ -12560,7 +12350,7 @@ function runningToolHomes(plat = osPlatform()) {
|
|
|
12560
12350
|
for (const pid of pids) {
|
|
12561
12351
|
let env;
|
|
12562
12352
|
try {
|
|
12563
|
-
env =
|
|
12353
|
+
env = readFileSync12(`/proc/${pid}/environ`, "utf-8");
|
|
12564
12354
|
} catch {
|
|
12565
12355
|
continue;
|
|
12566
12356
|
}
|
|
@@ -12640,7 +12430,7 @@ function walkForHomes(dir, depth, visit) {
|
|
|
12640
12430
|
for (const e of entries) {
|
|
12641
12431
|
if (!e.isDirectory() || SKIP.has(e.name))
|
|
12642
12432
|
continue;
|
|
12643
|
-
const child =
|
|
12433
|
+
const child = join19(dir, e.name);
|
|
12644
12434
|
visit(child);
|
|
12645
12435
|
walkForHomes(child, depth - 1, visit);
|
|
12646
12436
|
}
|
|
@@ -12681,20 +12471,20 @@ var init_home_discovery = __esm({
|
|
|
12681
12471
|
|
|
12682
12472
|
// ../engine/dist/core/detector-install.js
|
|
12683
12473
|
import { createHash as createHash4 } from "crypto";
|
|
12684
|
-
import { existsSync as existsSync18, mkdirSync as
|
|
12685
|
-
import { join as
|
|
12474
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync5, mkdtempSync, chmodSync as chmodSync2, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync4, readFileSync as readFileSync13, statSync as statSync16, copyFileSync as copyFileSync2 } from "fs";
|
|
12475
|
+
import { join as join20 } from "path";
|
|
12686
12476
|
function managedDetectorPath(name) {
|
|
12687
|
-
return
|
|
12477
|
+
return join20(getDetectorBinDir(), name + exeSuffix());
|
|
12688
12478
|
}
|
|
12689
12479
|
function receiptPath(name) {
|
|
12690
|
-
return
|
|
12480
|
+
return join20(getDetectorBinDir(), `${name}.receipt.json`);
|
|
12691
12481
|
}
|
|
12692
12482
|
function sha256File(path) {
|
|
12693
|
-
return createHash4("sha256").update(
|
|
12483
|
+
return createHash4("sha256").update(readFileSync13(path)).digest("hex");
|
|
12694
12484
|
}
|
|
12695
12485
|
function readReceipt(name) {
|
|
12696
12486
|
try {
|
|
12697
|
-
return JSON.parse(
|
|
12487
|
+
return JSON.parse(readFileSync13(receiptPath(name), "utf-8"));
|
|
12698
12488
|
} catch {
|
|
12699
12489
|
return null;
|
|
12700
12490
|
}
|
|
@@ -12720,7 +12510,7 @@ function configuredDir() {
|
|
|
12720
12510
|
function resolveDetector(name) {
|
|
12721
12511
|
const dir = configuredDir();
|
|
12722
12512
|
if (dir) {
|
|
12723
|
-
const p2 =
|
|
12513
|
+
const p2 = join20(dir, name + exeSuffix());
|
|
12724
12514
|
if (existsSync18(p2))
|
|
12725
12515
|
return { path: p2, version: "operator-supplied", source: "configured" };
|
|
12726
12516
|
return { error: "not-installed" };
|
|
@@ -12785,9 +12575,9 @@ var init_detector_install = __esm({
|
|
|
12785
12575
|
|
|
12786
12576
|
// ../engine/dist/core/secret-scanner.js
|
|
12787
12577
|
import { spawnSync } from "child_process";
|
|
12788
|
-
import { existsSync as existsSync19, unlinkSync, readFileSync as
|
|
12578
|
+
import { existsSync as existsSync19, unlinkSync, readFileSync as readFileSync14, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "fs";
|
|
12789
12579
|
import { tmpdir } from "os";
|
|
12790
|
-
import { join as
|
|
12580
|
+
import { join as join21 } from "path";
|
|
12791
12581
|
function mask(s) {
|
|
12792
12582
|
if (!s)
|
|
12793
12583
|
return "";
|
|
@@ -12815,7 +12605,7 @@ function whichDetector(bin) {
|
|
|
12815
12605
|
return null;
|
|
12816
12606
|
}
|
|
12817
12607
|
function spawnScoped(binary, args, opts) {
|
|
12818
|
-
const scratch = mkdtempSync2(
|
|
12608
|
+
const scratch = mkdtempSync2(join21(tmpdir(), "cr-scan-tmp-"));
|
|
12819
12609
|
try {
|
|
12820
12610
|
return spawnSync(binary, args, {
|
|
12821
12611
|
...opts,
|
|
@@ -12846,7 +12636,7 @@ function runGitleaks(binary, filePath) {
|
|
|
12846
12636
|
return [];
|
|
12847
12637
|
let parsed = [];
|
|
12848
12638
|
try {
|
|
12849
|
-
parsed = JSON.parse(
|
|
12639
|
+
parsed = JSON.parse(readFileSync14(reportPath, "utf-8")) || [];
|
|
12850
12640
|
} catch {
|
|
12851
12641
|
}
|
|
12852
12642
|
try {
|
|
@@ -12910,7 +12700,7 @@ function runGitleaksDir(binary, dir) {
|
|
|
12910
12700
|
}
|
|
12911
12701
|
let parsed = [];
|
|
12912
12702
|
try {
|
|
12913
|
-
parsed = JSON.parse(
|
|
12703
|
+
parsed = JSON.parse(readFileSync14(reportPath, "utf-8")) || [];
|
|
12914
12704
|
} catch {
|
|
12915
12705
|
}
|
|
12916
12706
|
try {
|
|
@@ -13001,7 +12791,7 @@ function scanFileForSecrets(filePath, opts = {}) {
|
|
|
13001
12791
|
out.push({ detector: "trufflehog", ...f });
|
|
13002
12792
|
if (opts.tenantRules && opts.tenantRules.length > 0) {
|
|
13003
12793
|
try {
|
|
13004
|
-
const text =
|
|
12794
|
+
const text = readFileSync14(filePath, "utf-8");
|
|
13005
12795
|
out.push(...scanTenantRules(text, opts.tenantRules));
|
|
13006
12796
|
} catch {
|
|
13007
12797
|
}
|
|
@@ -13377,10 +13167,10 @@ var init_transcript = __esm({
|
|
|
13377
13167
|
// ../engine/dist/core/project-resolver.js
|
|
13378
13168
|
import { execSync } from "child_process";
|
|
13379
13169
|
import { createHash as createHash5 } from "crypto";
|
|
13380
|
-
import { existsSync as existsSync20, readFileSync as
|
|
13381
|
-
import { basename as basename11, dirname as
|
|
13170
|
+
import { existsSync as existsSync20, readFileSync as readFileSync15, realpathSync as realpathSync3, readdirSync as readdirSync14, statSync as statSync18 } from "fs";
|
|
13171
|
+
import { basename as basename11, dirname as dirname14, isAbsolute, join as join22, resolve, sep } from "path";
|
|
13382
13172
|
function getProjectsConfigPath() {
|
|
13383
|
-
return
|
|
13173
|
+
return join22(getDataDir(), "projects.json");
|
|
13384
13174
|
}
|
|
13385
13175
|
function loadProjectsConfig() {
|
|
13386
13176
|
if (cachedConfig && cachedConfig.mtime === Number.MAX_SAFE_INTEGER) {
|
|
@@ -13395,7 +13185,7 @@ function loadProjectsConfig() {
|
|
|
13395
13185
|
if (cachedConfig && cachedConfig.mtime === mtime)
|
|
13396
13186
|
return cachedConfig.cfg;
|
|
13397
13187
|
try {
|
|
13398
|
-
const raw =
|
|
13188
|
+
const raw = readFileSync15(path, "utf-8");
|
|
13399
13189
|
const cfg = JSON.parse(raw);
|
|
13400
13190
|
cachedConfig = { mtime, cfg };
|
|
13401
13191
|
return cfg;
|
|
@@ -13491,7 +13281,7 @@ function matchDeclaredProject(realPath, projects) {
|
|
|
13491
13281
|
function matchChild(realPath, parentRoot, children) {
|
|
13492
13282
|
const sorted = [...children].sort((a, b) => b.path.length - a.path.length);
|
|
13493
13283
|
for (const c of sorted) {
|
|
13494
|
-
const childRoot = safeRealpath(
|
|
13284
|
+
const childRoot = safeRealpath(join22(parentRoot, c.path));
|
|
13495
13285
|
if (isInside(realPath, childRoot))
|
|
13496
13286
|
return c;
|
|
13497
13287
|
}
|
|
@@ -13526,10 +13316,10 @@ function findGitToplevel(realPath) {
|
|
|
13526
13316
|
let cur = realPath;
|
|
13527
13317
|
let last = "";
|
|
13528
13318
|
while (cur && cur !== last) {
|
|
13529
|
-
if (existsSync20(
|
|
13319
|
+
if (existsSync20(join22(cur, ".git")))
|
|
13530
13320
|
return cur;
|
|
13531
13321
|
last = cur;
|
|
13532
|
-
cur =
|
|
13322
|
+
cur = dirname14(cur);
|
|
13533
13323
|
}
|
|
13534
13324
|
return null;
|
|
13535
13325
|
}
|
|
@@ -13593,7 +13383,7 @@ function resolveAutoWorkspace(realPath, minRepos) {
|
|
|
13593
13383
|
let last = "";
|
|
13594
13384
|
let depth = 0;
|
|
13595
13385
|
while (cur && cur !== last && depth < AUTO_WORKSPACE_MAX_DEPTH) {
|
|
13596
|
-
if (!existsSync20(
|
|
13386
|
+
if (!existsSync20(join22(cur, ".git"))) {
|
|
13597
13387
|
const cached = workspaceCache.get(cur);
|
|
13598
13388
|
let qualifies;
|
|
13599
13389
|
if (cached === void 0) {
|
|
@@ -13608,7 +13398,7 @@ function resolveAutoWorkspace(realPath, minRepos) {
|
|
|
13608
13398
|
}
|
|
13609
13399
|
}
|
|
13610
13400
|
last = cur;
|
|
13611
|
-
cur =
|
|
13401
|
+
cur = dirname14(cur);
|
|
13612
13402
|
depth++;
|
|
13613
13403
|
}
|
|
13614
13404
|
return null;
|
|
@@ -13624,12 +13414,12 @@ function countGitChildren(dir) {
|
|
|
13624
13414
|
for (const name of entries) {
|
|
13625
13415
|
if (name.startsWith("."))
|
|
13626
13416
|
continue;
|
|
13627
|
-
const child =
|
|
13417
|
+
const child = join22(dir, name);
|
|
13628
13418
|
try {
|
|
13629
13419
|
const st = statSync18(child);
|
|
13630
13420
|
if (!st.isDirectory())
|
|
13631
13421
|
continue;
|
|
13632
|
-
if (existsSync20(
|
|
13422
|
+
if (existsSync20(join22(child, ".git")))
|
|
13633
13423
|
count++;
|
|
13634
13424
|
} catch {
|
|
13635
13425
|
}
|
|
@@ -14335,115 +14125,10 @@ var init_source_registry = __esm({
|
|
|
14335
14125
|
}
|
|
14336
14126
|
});
|
|
14337
14127
|
|
|
14338
|
-
// ../engine/dist/parsers/session-source.js
|
|
14339
|
-
var SessionSource;
|
|
14340
|
-
var init_session_source = __esm({
|
|
14341
|
-
"../engine/dist/parsers/session-source.js"() {
|
|
14342
|
-
"use strict";
|
|
14343
|
-
init_session();
|
|
14344
|
-
init_chunker();
|
|
14345
|
-
init_settings();
|
|
14346
|
-
SessionSource = class {
|
|
14347
|
-
sourceType = "session";
|
|
14348
|
-
claudeDir;
|
|
14349
|
-
constructor(claudeDir) {
|
|
14350
|
-
this.claudeDir = claudeDir;
|
|
14351
|
-
}
|
|
14352
|
-
async *discover() {
|
|
14353
|
-
if (!isSourceEnabled("claude", "sessions"))
|
|
14354
|
-
return;
|
|
14355
|
-
for (const [entry, sessionPath] of getAllSessions(this.claudeDir)) {
|
|
14356
|
-
yield this.entryToItem(entry, sessionPath);
|
|
14357
|
-
}
|
|
14358
|
-
}
|
|
14359
|
-
async parse(item) {
|
|
14360
|
-
const content = await parseSessionFile(item.filePath);
|
|
14361
|
-
const entry = this.itemToEntry(item);
|
|
14362
|
-
const sessionChunks = chunkSession(entry, content);
|
|
14363
|
-
item.extra = {
|
|
14364
|
-
...item.extra || {},
|
|
14365
|
-
...content.metadata
|
|
14366
|
-
};
|
|
14367
|
-
return sessionChunks.map((sc) => ({
|
|
14368
|
-
chunkId: sc.chunkId,
|
|
14369
|
-
itemId: sc.sessionId,
|
|
14370
|
-
sourceType: "session",
|
|
14371
|
-
// Empty title is preferable to "Session abc12345" placeholder text:
|
|
14372
|
-
// the latter pollutes search results and gets surfaced in the UI as
|
|
14373
|
-
// a misleading heading. Downstream renderers fall back to
|
|
14374
|
-
// project path / time when title is empty.
|
|
14375
|
-
title: sc.firstPrompt.slice(0, 100),
|
|
14376
|
-
text: sc.text,
|
|
14377
|
-
chunkType: sc.chunkType,
|
|
14378
|
-
projectPath: sc.projectPath,
|
|
14379
|
-
filePath: sc.sourceFile,
|
|
14380
|
-
mtime: sc.mtime
|
|
14381
|
-
}));
|
|
14382
|
-
}
|
|
14383
|
-
async extractLinks(item) {
|
|
14384
|
-
if (item.filePath) {
|
|
14385
|
-
try {
|
|
14386
|
-
const { detectForkPredecessor: detectForkPredecessor2 } = await Promise.resolve().then(() => (init_raw(), raw_exports));
|
|
14387
|
-
const predecessor = detectForkPredecessor2(item.filePath);
|
|
14388
|
-
if (predecessor) {
|
|
14389
|
-
return [{
|
|
14390
|
-
sourceType: "session",
|
|
14391
|
-
sourceId: item.id,
|
|
14392
|
-
targetType: "session",
|
|
14393
|
-
targetId: predecessor,
|
|
14394
|
-
linkType: "forked_from",
|
|
14395
|
-
confidence: 1
|
|
14396
|
-
}];
|
|
14397
|
-
}
|
|
14398
|
-
} catch {
|
|
14399
|
-
}
|
|
14400
|
-
}
|
|
14401
|
-
return [];
|
|
14402
|
-
}
|
|
14403
|
-
entryToItem(entry, sessionPath) {
|
|
14404
|
-
return {
|
|
14405
|
-
id: entry.sessionId,
|
|
14406
|
-
sourceType: "session",
|
|
14407
|
-
// Empty title when there's no first prompt — the UI then knows to
|
|
14408
|
-
// fall back to summary or project path instead of rendering the
|
|
14409
|
-
// useless "Session abc12345" placeholder as a heading.
|
|
14410
|
-
title: entry.firstPrompt ? entry.firstPrompt.replace(/\n/g, " ").trim().slice(0, 100) : "",
|
|
14411
|
-
projectPath: entry.projectPath,
|
|
14412
|
-
filePath: sessionPath,
|
|
14413
|
-
mtime: entry.fileMtime,
|
|
14414
|
-
contentPreview: entry.firstPrompt?.slice(0, 200),
|
|
14415
|
-
extra: {
|
|
14416
|
-
messageCount: entry.messageCount,
|
|
14417
|
-
gitBranch: entry.gitBranch,
|
|
14418
|
-
created: entry.created,
|
|
14419
|
-
modified: entry.modified,
|
|
14420
|
-
isSidechain: entry.isSidechain
|
|
14421
|
-
}
|
|
14422
|
-
};
|
|
14423
|
-
}
|
|
14424
|
-
itemToEntry(item) {
|
|
14425
|
-
const extra = item.extra || {};
|
|
14426
|
-
return {
|
|
14427
|
-
sessionId: item.id,
|
|
14428
|
-
fullPath: item.filePath,
|
|
14429
|
-
fileMtime: item.mtime,
|
|
14430
|
-
firstPrompt: item.contentPreview || "",
|
|
14431
|
-
messageCount: extra.messageCount || 0,
|
|
14432
|
-
created: extra.created || "",
|
|
14433
|
-
modified: extra.modified || "",
|
|
14434
|
-
gitBranch: extra.gitBranch || "",
|
|
14435
|
-
projectPath: item.projectPath,
|
|
14436
|
-
isSidechain: extra.isSidechain || false
|
|
14437
|
-
};
|
|
14438
|
-
}
|
|
14439
|
-
};
|
|
14440
|
-
}
|
|
14441
|
-
});
|
|
14442
|
-
|
|
14443
14128
|
// ../engine/dist/core/utils.js
|
|
14444
14129
|
import { existsSync as existsSync21, readdirSync as readdirSync15 } from "fs";
|
|
14445
14130
|
import { homedir as homedir6 } from "os";
|
|
14446
|
-
import { join as
|
|
14131
|
+
import { join as join23 } from "path";
|
|
14447
14132
|
function splitByHeaders(markdown) {
|
|
14448
14133
|
const lines = markdown.split("\n");
|
|
14449
14134
|
const sections = [];
|
|
@@ -14486,17 +14171,17 @@ function getClaudeDirs() {
|
|
|
14486
14171
|
for (const d of process.env.CLAUDE_DIRS.split(",")) {
|
|
14487
14172
|
const trimmed = d.trim();
|
|
14488
14173
|
if (trimmed) {
|
|
14489
|
-
add(trimmed.startsWith("~/") ?
|
|
14174
|
+
add(trimmed.startsWith("~/") ? join23(home, trimmed.slice(2)) : trimmed);
|
|
14490
14175
|
}
|
|
14491
14176
|
}
|
|
14492
14177
|
}
|
|
14493
|
-
add(
|
|
14178
|
+
add(join23(home, ".claude"));
|
|
14494
14179
|
try {
|
|
14495
14180
|
const entries = readdirSync15(home, { withFileTypes: true });
|
|
14496
14181
|
for (const entry of entries) {
|
|
14497
14182
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
14498
|
-
const candidate =
|
|
14499
|
-
if (existsSync21(
|
|
14183
|
+
const candidate = join23(home, entry.name);
|
|
14184
|
+
if (existsSync21(join23(candidate, "projects"))) {
|
|
14500
14185
|
add(candidate);
|
|
14501
14186
|
}
|
|
14502
14187
|
}
|
|
@@ -14508,12 +14193,12 @@ function getClaudeDirs() {
|
|
|
14508
14193
|
function discoverSubdirs(subdir) {
|
|
14509
14194
|
const result = [];
|
|
14510
14195
|
for (const claudeDir of getClaudeDirs()) {
|
|
14511
|
-
const path =
|
|
14196
|
+
const path = join23(claudeDir, subdir);
|
|
14512
14197
|
if (existsSync21(path)) {
|
|
14513
14198
|
result.push(path);
|
|
14514
14199
|
}
|
|
14515
14200
|
}
|
|
14516
|
-
return result.length > 0 ? result : [
|
|
14201
|
+
return result.length > 0 ? result : [join23(homedir6(), ".claude", subdir)];
|
|
14517
14202
|
}
|
|
14518
14203
|
var init_utils = __esm({
|
|
14519
14204
|
"../engine/dist/core/utils.js"() {
|
|
@@ -14522,9 +14207,9 @@ var init_utils = __esm({
|
|
|
14522
14207
|
});
|
|
14523
14208
|
|
|
14524
14209
|
// ../engine/dist/parsers/plan-source.js
|
|
14525
|
-
import { existsSync as existsSync22, readdirSync as readdirSync16, readFileSync as
|
|
14210
|
+
import { existsSync as existsSync22, readdirSync as readdirSync16, readFileSync as readFileSync16, statSync as statSync20 } from "fs";
|
|
14526
14211
|
import { homedir as homedir7 } from "os";
|
|
14527
|
-
import { join as
|
|
14212
|
+
import { join as join24, basename as basename12 } from "path";
|
|
14528
14213
|
function parseFrontmatter(content) {
|
|
14529
14214
|
if (!content.startsWith("---"))
|
|
14530
14215
|
return { body: content };
|
|
@@ -14619,12 +14304,12 @@ var init_plan_source = __esm({
|
|
|
14619
14304
|
if (seenClaude.has(file))
|
|
14620
14305
|
continue;
|
|
14621
14306
|
seenClaude.add(file);
|
|
14622
|
-
const filePath =
|
|
14307
|
+
const filePath = join24(plansDir, file);
|
|
14623
14308
|
try {
|
|
14624
14309
|
const stat3 = statSync20(filePath);
|
|
14625
14310
|
const planName = basename12(file, ".md");
|
|
14626
14311
|
const isAgentPlan = planName.includes("-agent-");
|
|
14627
|
-
const content =
|
|
14312
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
14628
14313
|
const fm = parseFrontmatter(content);
|
|
14629
14314
|
const body = fm.body;
|
|
14630
14315
|
const firstLine = body.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || planName;
|
|
@@ -14663,10 +14348,10 @@ var init_plan_source = __esm({
|
|
|
14663
14348
|
return;
|
|
14664
14349
|
}
|
|
14665
14350
|
for (const file of files) {
|
|
14666
|
-
const filePath =
|
|
14351
|
+
const filePath = join24(plansDir, file);
|
|
14667
14352
|
try {
|
|
14668
14353
|
const stat3 = statSync20(filePath);
|
|
14669
|
-
const content =
|
|
14354
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
14670
14355
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14671
14356
|
const planName = `${opencodeBackend.idPrefix}plan_${basename12(file, ".md")}`;
|
|
14672
14357
|
const projectPath = this.extractProjectPath(content);
|
|
@@ -14694,7 +14379,7 @@ var init_plan_source = __esm({
|
|
|
14694
14379
|
for (const match of content.matchAll(fullPathPattern)) {
|
|
14695
14380
|
let path = (match[1] || "").trim();
|
|
14696
14381
|
if (path.startsWith("~/")) {
|
|
14697
|
-
path =
|
|
14382
|
+
path = join24(homedir7(), path.slice(2));
|
|
14698
14383
|
}
|
|
14699
14384
|
for (const projectDir of knownProjects) {
|
|
14700
14385
|
if (path.startsWith(projectDir)) {
|
|
@@ -14743,7 +14428,7 @@ var init_plan_source = __esm({
|
|
|
14743
14428
|
async parse(item) {
|
|
14744
14429
|
if (!existsSync22(item.filePath))
|
|
14745
14430
|
return [];
|
|
14746
|
-
const content =
|
|
14431
|
+
const content = readFileSync16(item.filePath, "utf-8");
|
|
14747
14432
|
const chunks = [];
|
|
14748
14433
|
const { body } = parseFrontmatter(content);
|
|
14749
14434
|
const sections = splitByHeaders(body);
|
|
@@ -14779,9 +14464,9 @@ var init_plan_source = __esm({
|
|
|
14779
14464
|
const map = /* @__PURE__ */ new Map();
|
|
14780
14465
|
const root = claudeBackend.projectsDir();
|
|
14781
14466
|
for (const proj of safeReaddir(root)) {
|
|
14782
|
-
const projPath =
|
|
14467
|
+
const projPath = join24(root, proj);
|
|
14783
14468
|
for (const sessionEntry of safeReaddir(projPath)) {
|
|
14784
|
-
const subDir =
|
|
14469
|
+
const subDir = join24(projPath, sessionEntry, "subagents");
|
|
14785
14470
|
if (!existsSync22(subDir))
|
|
14786
14471
|
continue;
|
|
14787
14472
|
for (const f of safeReaddir(subDir)) {
|
|
@@ -14856,7 +14541,7 @@ var init_plan_source = __esm({
|
|
|
14856
14541
|
return links;
|
|
14857
14542
|
}
|
|
14858
14543
|
async *discoverAgyPlans() {
|
|
14859
|
-
const brainDir =
|
|
14544
|
+
const brainDir = join24(agyBackend.homeDir(), "brain");
|
|
14860
14545
|
if (!existsSync22(brainDir))
|
|
14861
14546
|
return;
|
|
14862
14547
|
let sessionDirs;
|
|
@@ -14866,7 +14551,7 @@ var init_plan_source = __esm({
|
|
|
14866
14551
|
return;
|
|
14867
14552
|
}
|
|
14868
14553
|
for (const rawId of sessionDirs) {
|
|
14869
|
-
const sessionPath =
|
|
14554
|
+
const sessionPath = join24(brainDir, rawId);
|
|
14870
14555
|
try {
|
|
14871
14556
|
if (!statSync20(sessionPath).isDirectory())
|
|
14872
14557
|
continue;
|
|
@@ -14880,10 +14565,10 @@ var init_plan_source = __esm({
|
|
|
14880
14565
|
continue;
|
|
14881
14566
|
}
|
|
14882
14567
|
for (const file of files) {
|
|
14883
|
-
const filePath =
|
|
14568
|
+
const filePath = join24(sessionPath, file);
|
|
14884
14569
|
try {
|
|
14885
14570
|
const stat3 = statSync20(filePath);
|
|
14886
|
-
const content =
|
|
14571
|
+
const content = readFileSync16(filePath, "utf-8");
|
|
14887
14572
|
const firstLine = content.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").trim() || file;
|
|
14888
14573
|
const sessionLoc = agyBackend.findSession(rawId);
|
|
14889
14574
|
const projectPath = sessionLoc?.projectPath || this.extractProjectPath(content);
|
|
@@ -14912,8 +14597,8 @@ var init_plan_source = __esm({
|
|
|
14912
14597
|
});
|
|
14913
14598
|
|
|
14914
14599
|
// ../engine/dist/parsers/task-source.js
|
|
14915
|
-
import { existsSync as existsSync23, readdirSync as readdirSync17, readFileSync as
|
|
14916
|
-
import { join as
|
|
14600
|
+
import { existsSync as existsSync23, readdirSync as readdirSync17, readFileSync as readFileSync17, statSync as statSync21 } from "fs";
|
|
14601
|
+
import { join as join25 } from "path";
|
|
14917
14602
|
var MAX_CHUNK_CHARS2, TaskSource;
|
|
14918
14603
|
var init_task_source = __esm({
|
|
14919
14604
|
"../engine/dist/parsers/task-source.js"() {
|
|
@@ -14951,7 +14636,7 @@ var init_task_source = __esm({
|
|
|
14951
14636
|
return;
|
|
14952
14637
|
}
|
|
14953
14638
|
for (const file of files) {
|
|
14954
|
-
const filePath =
|
|
14639
|
+
const filePath = join25(todosDir, file);
|
|
14955
14640
|
let stat3;
|
|
14956
14641
|
try {
|
|
14957
14642
|
stat3 = statSync21(filePath);
|
|
@@ -14962,7 +14647,7 @@ var init_task_source = __esm({
|
|
|
14962
14647
|
continue;
|
|
14963
14648
|
let parsed;
|
|
14964
14649
|
try {
|
|
14965
|
-
const raw =
|
|
14650
|
+
const raw = readFileSync17(filePath, "utf-8");
|
|
14966
14651
|
parsed = JSON.parse(raw);
|
|
14967
14652
|
if (!Array.isArray(parsed) || parsed.length === 0)
|
|
14968
14653
|
continue;
|
|
@@ -15000,7 +14685,7 @@ var init_task_source = __esm({
|
|
|
15000
14685
|
if (!entry.isDirectory())
|
|
15001
14686
|
continue;
|
|
15002
14687
|
const sessionUuid = entry.name;
|
|
15003
|
-
const taskDir =
|
|
14688
|
+
const taskDir = join25(tasksDir, sessionUuid);
|
|
15004
14689
|
try {
|
|
15005
14690
|
const stat3 = statSync21(taskDir);
|
|
15006
14691
|
const taskFiles = readdirSync17(taskDir).filter((f) => f.endsWith(".json"));
|
|
@@ -15075,7 +14760,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
15075
14760
|
text,
|
|
15076
14761
|
chunkType: "task_detail",
|
|
15077
14762
|
projectPath: item.projectPath,
|
|
15078
|
-
filePath:
|
|
14763
|
+
filePath: join25(taskDir, `${task.id}.json`),
|
|
15079
14764
|
mtime: item.mtime
|
|
15080
14765
|
});
|
|
15081
14766
|
}
|
|
@@ -15100,7 +14785,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
15100
14785
|
return [];
|
|
15101
14786
|
let parsed;
|
|
15102
14787
|
try {
|
|
15103
|
-
parsed = JSON.parse(
|
|
14788
|
+
parsed = JSON.parse(readFileSync17(item.filePath, "utf-8"));
|
|
15104
14789
|
} catch {
|
|
15105
14790
|
return [];
|
|
15106
14791
|
}
|
|
@@ -15132,7 +14817,7 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
15132
14817
|
});
|
|
15133
14818
|
for (const file of sorted) {
|
|
15134
14819
|
try {
|
|
15135
|
-
const content =
|
|
14820
|
+
const content = readFileSync17(join25(taskDir, file), "utf-8");
|
|
15136
14821
|
const task = JSON.parse(content);
|
|
15137
14822
|
if (task.subject) {
|
|
15138
14823
|
tasks.push(task);
|
|
@@ -15148,9 +14833,9 @@ ${task.description}`.slice(0, MAX_CHUNK_CHARS2);
|
|
|
15148
14833
|
});
|
|
15149
14834
|
|
|
15150
14835
|
// ../engine/dist/parsers/claude-md-source.js
|
|
15151
|
-
import { existsSync as existsSync24, readFileSync as
|
|
14836
|
+
import { existsSync as existsSync24, readFileSync as readFileSync18, readdirSync as readdirSync18, statSync as statSync22 } from "fs";
|
|
15152
14837
|
import { homedir as homedir8 } from "os";
|
|
15153
|
-
import { join as
|
|
14838
|
+
import { join as join26, basename as basename13, dirname as dirname15 } from "path";
|
|
15154
14839
|
import { createHash as createHash6 } from "crypto";
|
|
15155
14840
|
function discoverProjectDirs(claudeDir) {
|
|
15156
14841
|
const dirs = [];
|
|
@@ -15176,7 +14861,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
15176
14861
|
}
|
|
15177
14862
|
};
|
|
15178
14863
|
if (claudeDir) {
|
|
15179
|
-
scanProjectsDir(
|
|
14864
|
+
scanProjectsDir(join26(claudeDir, "projects"));
|
|
15180
14865
|
return dirs;
|
|
15181
14866
|
}
|
|
15182
14867
|
const home = homedir8();
|
|
@@ -15184,7 +14869,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
15184
14869
|
try {
|
|
15185
14870
|
for (const entry of readdirSync18(home, { withFileTypes: true })) {
|
|
15186
14871
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
15187
|
-
scanProjectsDir(
|
|
14872
|
+
scanProjectsDir(join26(home, entry.name, "projects"));
|
|
15188
14873
|
}
|
|
15189
14874
|
}
|
|
15190
14875
|
} catch {
|
|
@@ -15192,7 +14877,7 @@ function discoverProjectDirs(claudeDir) {
|
|
|
15192
14877
|
const gemProjects = agyBackend.sharedProjectsJson();
|
|
15193
14878
|
if (existsSync24(gemProjects)) {
|
|
15194
14879
|
try {
|
|
15195
|
-
const data = JSON.parse(
|
|
14880
|
+
const data = JSON.parse(readFileSync18(gemProjects, "utf-8"));
|
|
15196
14881
|
for (const path of Object.keys(data.projects || {}))
|
|
15197
14882
|
addProject(path);
|
|
15198
14883
|
} catch {
|
|
@@ -15248,7 +14933,7 @@ var init_claude_md_source = __esm({
|
|
|
15248
14933
|
const seen = /* @__PURE__ */ new Set();
|
|
15249
14934
|
const seenKey = (path, tool) => `${tool}:${path}`;
|
|
15250
14935
|
for (const note of NOTE_FILES) {
|
|
15251
|
-
const p =
|
|
14936
|
+
const p = join26(homedir8(), note.filename);
|
|
15252
14937
|
const key2 = seenKey(p, note.tool);
|
|
15253
14938
|
if (existsSync24(p) && !seen.has(key2)) {
|
|
15254
14939
|
seen.add(key2);
|
|
@@ -15260,7 +14945,7 @@ var init_claude_md_source = __esm({
|
|
|
15260
14945
|
const projectDirs = discoverProjectDirs(this.claudeDir);
|
|
15261
14946
|
for (const projectDir of projectDirs) {
|
|
15262
14947
|
for (const note of NOTE_FILES) {
|
|
15263
|
-
const p =
|
|
14948
|
+
const p = join26(projectDir, note.filename);
|
|
15264
14949
|
const key2 = seenKey(p, note.tool);
|
|
15265
14950
|
if (existsSync24(p) && !seen.has(key2)) {
|
|
15266
14951
|
seen.add(key2);
|
|
@@ -15274,7 +14959,7 @@ var init_claude_md_source = __esm({
|
|
|
15274
14959
|
if (!existsSync24(searchDir))
|
|
15275
14960
|
continue;
|
|
15276
14961
|
for (const note of NOTE_FILES) {
|
|
15277
|
-
const directPath =
|
|
14962
|
+
const directPath = join26(searchDir, note.filename);
|
|
15278
14963
|
const key2 = seenKey(directPath, note.tool);
|
|
15279
14964
|
if (existsSync24(directPath) && !seen.has(key2)) {
|
|
15280
14965
|
seen.add(key2);
|
|
@@ -15289,7 +14974,7 @@ var init_claude_md_source = __esm({
|
|
|
15289
14974
|
if (!entry.isDirectory())
|
|
15290
14975
|
continue;
|
|
15291
14976
|
for (const note of NOTE_FILES) {
|
|
15292
|
-
const p =
|
|
14977
|
+
const p = join26(searchDir, entry.name, note.filename);
|
|
15293
14978
|
const key2 = seenKey(p, note.tool);
|
|
15294
14979
|
if (existsSync24(p) && !seen.has(key2)) {
|
|
15295
14980
|
seen.add(key2);
|
|
@@ -15307,7 +14992,7 @@ var init_claude_md_source = __esm({
|
|
|
15307
14992
|
async parse(item) {
|
|
15308
14993
|
if (!existsSync24(item.filePath))
|
|
15309
14994
|
return [];
|
|
15310
|
-
const content =
|
|
14995
|
+
const content = readFileSync18(item.filePath, "utf-8");
|
|
15311
14996
|
const chunks = [];
|
|
15312
14997
|
const sections = splitByHeaders(content);
|
|
15313
14998
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -15346,10 +15031,10 @@ var init_claude_md_source = __esm({
|
|
|
15346
15031
|
fileToItem(filePath, filename, tool) {
|
|
15347
15032
|
try {
|
|
15348
15033
|
const stat3 = statSync22(filePath);
|
|
15349
|
-
const projectDir =
|
|
15034
|
+
const projectDir = dirname15(filePath);
|
|
15350
15035
|
const projectName = basename13(projectDir);
|
|
15351
15036
|
const projectPath = projectDir;
|
|
15352
|
-
const content =
|
|
15037
|
+
const content = readFileSync18(filePath, "utf-8");
|
|
15353
15038
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim()?.slice(0, 200) || `${filename} for ${projectName}`;
|
|
15354
15039
|
const id = tool === "claude" ? projectName : `${projectName}_${tool}`;
|
|
15355
15040
|
return {
|
|
@@ -15374,9 +15059,9 @@ var init_claude_md_source = __esm({
|
|
|
15374
15059
|
});
|
|
15375
15060
|
|
|
15376
15061
|
// ../engine/dist/parsers/agent-memory-source.js
|
|
15377
|
-
import { existsSync as existsSync25, readFileSync as
|
|
15062
|
+
import { existsSync as existsSync25, readFileSync as readFileSync19, readdirSync as readdirSync19, statSync as statSync23 } from "fs";
|
|
15378
15063
|
import { homedir as homedir9 } from "os";
|
|
15379
|
-
import { join as
|
|
15064
|
+
import { join as join27, basename as basename14 } from "path";
|
|
15380
15065
|
function parseFrontmatter2(content) {
|
|
15381
15066
|
const fm = {};
|
|
15382
15067
|
let body = content;
|
|
@@ -15418,7 +15103,7 @@ function discoverMemoryDirs() {
|
|
|
15418
15103
|
try {
|
|
15419
15104
|
for (const entry of readdirSync19(home, { withFileTypes: true })) {
|
|
15420
15105
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
15421
|
-
claudeRoots.push(
|
|
15106
|
+
claudeRoots.push(join27(home, entry.name, "projects"));
|
|
15422
15107
|
}
|
|
15423
15108
|
}
|
|
15424
15109
|
} catch {
|
|
@@ -15430,7 +15115,7 @@ function discoverMemoryDirs() {
|
|
|
15430
15115
|
for (const entry of readdirSync19(projectsDir, { withFileTypes: true })) {
|
|
15431
15116
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
15432
15117
|
continue;
|
|
15433
|
-
add(
|
|
15118
|
+
add(join27(projectsDir, entry.name, "memory"), entry.name);
|
|
15434
15119
|
}
|
|
15435
15120
|
} catch {
|
|
15436
15121
|
}
|
|
@@ -15459,7 +15144,7 @@ var init_agent_memory_source = __esm({
|
|
|
15459
15144
|
for (const entry of readdirSync19(memoryDir, { withFileTypes: true })) {
|
|
15460
15145
|
if (!entry.isFile() || !entry.name.endsWith(".md"))
|
|
15461
15146
|
continue;
|
|
15462
|
-
const filePath =
|
|
15147
|
+
const filePath = join27(memoryDir, entry.name);
|
|
15463
15148
|
if (seen.has(filePath))
|
|
15464
15149
|
continue;
|
|
15465
15150
|
seen.add(filePath);
|
|
@@ -15475,7 +15160,7 @@ var init_agent_memory_source = __esm({
|
|
|
15475
15160
|
async parse(item) {
|
|
15476
15161
|
if (!existsSync25(item.filePath))
|
|
15477
15162
|
return [];
|
|
15478
|
-
const content =
|
|
15163
|
+
const content = readFileSync19(item.filePath, "utf-8");
|
|
15479
15164
|
const { body } = parseFrontmatter2(content);
|
|
15480
15165
|
const chunks = [];
|
|
15481
15166
|
const sections = splitByHeaders(body);
|
|
@@ -15528,7 +15213,7 @@ var init_agent_memory_source = __esm({
|
|
|
15528
15213
|
fileToItem(filePath, filename, projectPath, _projectHash) {
|
|
15529
15214
|
try {
|
|
15530
15215
|
const stat3 = statSync23(filePath);
|
|
15531
|
-
const content =
|
|
15216
|
+
const content = readFileSync19(filePath, "utf-8");
|
|
15532
15217
|
const { fm } = parseFrontmatter2(content);
|
|
15533
15218
|
const stem = filename.replace(/\.md$/, "");
|
|
15534
15219
|
const idBase = fm.name || stem;
|
|
@@ -15563,7 +15248,7 @@ import { existsSync as existsSync26, readdirSync as readdirSync20, statSync as s
|
|
|
15563
15248
|
import { createReadStream as createReadStream3 } from "fs";
|
|
15564
15249
|
import { createInterface as createInterface2 } from "readline";
|
|
15565
15250
|
import { homedir as homedir10 } from "os";
|
|
15566
|
-
import { join as
|
|
15251
|
+
import { join as join28 } from "path";
|
|
15567
15252
|
var MAX_CHUNK_CHARS5, HistorySource;
|
|
15568
15253
|
var init_history_source = __esm({
|
|
15569
15254
|
"../engine/dist/parsers/history-source.js"() {
|
|
@@ -15588,12 +15273,12 @@ var init_history_source = __esm({
|
|
|
15588
15273
|
try {
|
|
15589
15274
|
for (const entry of readdirSync20(home, { withFileTypes: true })) {
|
|
15590
15275
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
15591
|
-
tryAdd(
|
|
15276
|
+
tryAdd(join28(home, entry.name, "history.jsonl"));
|
|
15592
15277
|
}
|
|
15593
15278
|
}
|
|
15594
15279
|
} catch {
|
|
15595
15280
|
}
|
|
15596
|
-
this.historyPaths = paths.length > 0 ? paths : [
|
|
15281
|
+
this.historyPaths = paths.length > 0 ? paths : [join28(home, ".claude", "history.jsonl")];
|
|
15597
15282
|
}
|
|
15598
15283
|
}
|
|
15599
15284
|
async *discover() {
|
|
@@ -15743,9 +15428,9 @@ var init_history_source = __esm({
|
|
|
15743
15428
|
});
|
|
15744
15429
|
|
|
15745
15430
|
// ../engine/dist/parsers/paste-source.js
|
|
15746
|
-
import { existsSync as existsSync27, readdirSync as readdirSync21, readFileSync as
|
|
15431
|
+
import { existsSync as existsSync27, readdirSync as readdirSync21, readFileSync as readFileSync20, statSync as statSync25 } from "fs";
|
|
15747
15432
|
import { homedir as homedir11 } from "os";
|
|
15748
|
-
import { join as
|
|
15433
|
+
import { join as join29, basename as basename15 } from "path";
|
|
15749
15434
|
var MAX_CHUNK_CHARS6, MAX_FILE_SIZE, PasteSource;
|
|
15750
15435
|
var init_paste_source = __esm({
|
|
15751
15436
|
"../engine/dist/parsers/paste-source.js"() {
|
|
@@ -15771,7 +15456,7 @@ var init_paste_source = __esm({
|
|
|
15771
15456
|
try {
|
|
15772
15457
|
for (const entry of readdirSync21(home, { withFileTypes: true })) {
|
|
15773
15458
|
if (entry.isDirectory() && entry.name.startsWith(".claude-") && entry.name !== ".claude-code") {
|
|
15774
|
-
tryAdd(
|
|
15459
|
+
tryAdd(join29(home, entry.name, "paste-cache"));
|
|
15775
15460
|
}
|
|
15776
15461
|
}
|
|
15777
15462
|
} catch {
|
|
@@ -15791,7 +15476,7 @@ var init_paste_source = __esm({
|
|
|
15791
15476
|
if (seen.has(file))
|
|
15792
15477
|
continue;
|
|
15793
15478
|
seen.add(file);
|
|
15794
|
-
const filePath =
|
|
15479
|
+
const filePath = join29(cacheDir, file);
|
|
15795
15480
|
try {
|
|
15796
15481
|
const stat3 = statSync25(filePath);
|
|
15797
15482
|
if (stat3.size > MAX_FILE_SIZE)
|
|
@@ -15799,7 +15484,7 @@ var init_paste_source = __esm({
|
|
|
15799
15484
|
if (stat3.size < 10)
|
|
15800
15485
|
continue;
|
|
15801
15486
|
const hash = basename15(file, ".txt");
|
|
15802
|
-
const content =
|
|
15487
|
+
const content = readFileSync20(filePath, "utf-8");
|
|
15803
15488
|
const firstLine = content.split("\n").find((l) => l.trim().length > 5)?.trim()?.slice(0, 100) || `Paste ${hash.slice(0, 8)}`;
|
|
15804
15489
|
yield {
|
|
15805
15490
|
id: hash,
|
|
@@ -15820,7 +15505,7 @@ var init_paste_source = __esm({
|
|
|
15820
15505
|
async parse(item) {
|
|
15821
15506
|
if (!existsSync27(item.filePath))
|
|
15822
15507
|
return [];
|
|
15823
|
-
const content =
|
|
15508
|
+
const content = readFileSync20(item.filePath, "utf-8");
|
|
15824
15509
|
if (content.trim().length < 20)
|
|
15825
15510
|
return [];
|
|
15826
15511
|
return [{
|
|
@@ -15843,8 +15528,8 @@ var init_paste_source = __esm({
|
|
|
15843
15528
|
});
|
|
15844
15529
|
|
|
15845
15530
|
// ../engine/dist/parsers/antigravity-brain-source.js
|
|
15846
|
-
import { existsSync as existsSync28, readdirSync as readdirSync22, readFileSync as
|
|
15847
|
-
import { join as
|
|
15531
|
+
import { existsSync as existsSync28, readdirSync as readdirSync22, readFileSync as readFileSync21, statSync as statSync26 } from "fs";
|
|
15532
|
+
import { join as join30 } from "path";
|
|
15848
15533
|
var MAX_CHUNK_CHARS7, AntigravityBrainSource;
|
|
15849
15534
|
var init_antigravity_brain_source = __esm({
|
|
15850
15535
|
"../engine/dist/parsers/antigravity-brain-source.js"() {
|
|
@@ -15868,22 +15553,22 @@ var init_antigravity_brain_source = __esm({
|
|
|
15868
15553
|
for (const entry of sessions) {
|
|
15869
15554
|
if (!entry.isDirectory())
|
|
15870
15555
|
continue;
|
|
15871
|
-
const sessionDir =
|
|
15556
|
+
const sessionDir = join30(this.brainDir, entry.name);
|
|
15872
15557
|
const files = readdirSync22(sessionDir).filter((f) => f.endsWith(".md") && !f.includes(".resolved") && !f.includes(".metadata"));
|
|
15873
15558
|
if (files.length === 0)
|
|
15874
15559
|
continue;
|
|
15875
15560
|
for (const file of files) {
|
|
15876
|
-
const filePath =
|
|
15561
|
+
const filePath = join30(sessionDir, file);
|
|
15877
15562
|
try {
|
|
15878
15563
|
const stat3 = statSync26(filePath);
|
|
15879
|
-
const content =
|
|
15564
|
+
const content = readFileSync21(filePath, "utf-8");
|
|
15880
15565
|
const firstLine = content.split("\n").find((l) => l.trim() && !l.startsWith("#"))?.trim() || "";
|
|
15881
15566
|
const heading = content.split("\n").find((l) => l.startsWith("#"))?.replace(/^#+\s*/, "").trim() || file;
|
|
15882
15567
|
const metaPath = `${filePath}.metadata.json`;
|
|
15883
15568
|
let metaSummary = "";
|
|
15884
15569
|
if (existsSync28(metaPath)) {
|
|
15885
15570
|
try {
|
|
15886
|
-
const meta = JSON.parse(
|
|
15571
|
+
const meta = JSON.parse(readFileSync21(metaPath, "utf-8"));
|
|
15887
15572
|
metaSummary = meta.summary || "";
|
|
15888
15573
|
} catch {
|
|
15889
15574
|
}
|
|
@@ -15914,7 +15599,7 @@ var init_antigravity_brain_source = __esm({
|
|
|
15914
15599
|
async parse(item) {
|
|
15915
15600
|
if (!existsSync28(item.filePath))
|
|
15916
15601
|
return [];
|
|
15917
|
-
const content =
|
|
15602
|
+
const content = readFileSync21(item.filePath, "utf-8");
|
|
15918
15603
|
const chunks = [];
|
|
15919
15604
|
const sections = splitByHeaders(content);
|
|
15920
15605
|
for (let i = 0; i < sections.length; i++) {
|
|
@@ -16257,8 +15942,8 @@ var init_opencode_todo_source = __esm({
|
|
|
16257
15942
|
});
|
|
16258
15943
|
|
|
16259
15944
|
// ../engine/dist/parsers/codex-session-source.js
|
|
16260
|
-
import { existsSync as existsSync31, readdirSync as readdirSync23, readFileSync as
|
|
16261
|
-
import { join as
|
|
15945
|
+
import { existsSync as existsSync31, readdirSync as readdirSync23, readFileSync as readFileSync22, statSync as statSync27 } from "fs";
|
|
15946
|
+
import { join as join31, basename as basename16 } from "path";
|
|
16262
15947
|
function getCodexSessionsDir() {
|
|
16263
15948
|
return codexBackend.sessionsDir();
|
|
16264
15949
|
}
|
|
@@ -16285,7 +15970,7 @@ function extractReasoningText(event) {
|
|
|
16285
15970
|
return "";
|
|
16286
15971
|
}
|
|
16287
15972
|
function readJsonlLines(filePath) {
|
|
16288
|
-
const text =
|
|
15973
|
+
const text = readFileSync22(filePath, "utf-8");
|
|
16289
15974
|
const lines = text.split("\n");
|
|
16290
15975
|
const events = [];
|
|
16291
15976
|
for (const line of lines) {
|
|
@@ -16320,7 +16005,7 @@ var init_codex_session_source = __esm({
|
|
|
16320
16005
|
for (const filePath of jsonlFiles) {
|
|
16321
16006
|
try {
|
|
16322
16007
|
const stat3 = statSync27(filePath);
|
|
16323
|
-
const lines =
|
|
16008
|
+
const lines = readFileSync22(filePath, "utf-8").split("\n");
|
|
16324
16009
|
const firstLine = lines.find((l) => l.trim());
|
|
16325
16010
|
if (!firstLine)
|
|
16326
16011
|
continue;
|
|
@@ -16479,7 +16164,7 @@ var init_codex_session_source = __esm({
|
|
|
16479
16164
|
if (!existsSync31(dir))
|
|
16480
16165
|
return results;
|
|
16481
16166
|
for (const entry of readdirSync23(dir, { withFileTypes: true })) {
|
|
16482
|
-
const fullPath =
|
|
16167
|
+
const fullPath = join31(dir, entry.name);
|
|
16483
16168
|
if (entry.isDirectory()) {
|
|
16484
16169
|
results.push(...this.collectJsonlFiles(fullPath));
|
|
16485
16170
|
} else if (entry.isFile() && entry.name.startsWith("rollout-") && entry.name.endsWith(".jsonl")) {
|
|
@@ -16493,8 +16178,8 @@ var init_codex_session_source = __esm({
|
|
|
16493
16178
|
});
|
|
16494
16179
|
|
|
16495
16180
|
// ../engine/dist/parsers/diary-source.js
|
|
16496
|
-
import { existsSync as existsSync32, mkdirSync as
|
|
16497
|
-
import { join as
|
|
16181
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync6, readdirSync as readdirSync24, readFileSync as readFileSync23, writeFileSync as writeFileSync5, statSync as statSync28 } from "fs";
|
|
16182
|
+
import { join as join32, basename as basename17 } from "path";
|
|
16498
16183
|
var MAX_CHUNK_CHARS10, DiarySource;
|
|
16499
16184
|
var init_diary_source = __esm({
|
|
16500
16185
|
"../engine/dist/parsers/diary-source.js"() {
|
|
@@ -16513,13 +16198,13 @@ var init_diary_source = __esm({
|
|
|
16513
16198
|
return;
|
|
16514
16199
|
const agents = readdirSync24(this.diaryDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
16515
16200
|
for (const agentDir of agents) {
|
|
16516
|
-
const agentPath2 =
|
|
16201
|
+
const agentPath2 = join32(this.diaryDir, agentDir.name);
|
|
16517
16202
|
const files = readdirSync24(agentPath2).filter((f) => f.endsWith(".json"));
|
|
16518
16203
|
for (const file of files) {
|
|
16519
|
-
const filePath =
|
|
16204
|
+
const filePath = join32(agentPath2, file);
|
|
16520
16205
|
try {
|
|
16521
16206
|
const stat3 = statSync28(filePath);
|
|
16522
|
-
const raw =
|
|
16207
|
+
const raw = readFileSync23(filePath, "utf-8");
|
|
16523
16208
|
const entry = JSON.parse(raw);
|
|
16524
16209
|
const entryId = basename17(file, ".json");
|
|
16525
16210
|
const title = `[${entry.agent}] ${entry.topic}: ${entry.content.slice(0, 80)}`;
|
|
@@ -16546,7 +16231,7 @@ var init_diary_source = __esm({
|
|
|
16546
16231
|
async parse(item) {
|
|
16547
16232
|
if (!existsSync32(item.filePath))
|
|
16548
16233
|
return [];
|
|
16549
|
-
const raw =
|
|
16234
|
+
const raw = readFileSync23(item.filePath, "utf-8");
|
|
16550
16235
|
const entry = JSON.parse(raw);
|
|
16551
16236
|
if (!entry.content || entry.content.trim().length < 10)
|
|
16552
16237
|
return [];
|
|
@@ -16583,18 +16268,18 @@ var init_diary_source = __esm({
|
|
|
16583
16268
|
*/
|
|
16584
16269
|
static write(entry, diaryDir) {
|
|
16585
16270
|
const dir = diaryDir || getDiaryDir();
|
|
16586
|
-
const agentDir =
|
|
16271
|
+
const agentDir = join32(dir, entry.agent.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
16587
16272
|
if (!existsSync32(agentDir)) {
|
|
16588
|
-
|
|
16273
|
+
mkdirSync6(agentDir, { recursive: true });
|
|
16589
16274
|
}
|
|
16590
16275
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
16591
16276
|
const entryId = `diary_${entry.agent.toLowerCase()}_${ts}`;
|
|
16592
|
-
const filePath =
|
|
16277
|
+
const filePath = join32(agentDir, `${entryId}.json`);
|
|
16593
16278
|
const full = {
|
|
16594
16279
|
...entry,
|
|
16595
16280
|
timestamp: entry.timestamp || (/* @__PURE__ */ new Date()).toISOString()
|
|
16596
16281
|
};
|
|
16597
|
-
|
|
16282
|
+
writeFileSync5(filePath, JSON.stringify(full, null, 2), "utf-8");
|
|
16598
16283
|
return entryId;
|
|
16599
16284
|
}
|
|
16600
16285
|
/**
|
|
@@ -16602,14 +16287,14 @@ var init_diary_source = __esm({
|
|
|
16602
16287
|
*/
|
|
16603
16288
|
static read(agentName, lastN = 10, diaryDir) {
|
|
16604
16289
|
const dir = diaryDir || getDiaryDir();
|
|
16605
|
-
const agentDir =
|
|
16290
|
+
const agentDir = join32(dir, agentName.toLowerCase().replace(/[^a-z0-9_-]/g, "_"));
|
|
16606
16291
|
if (!existsSync32(agentDir))
|
|
16607
16292
|
return [];
|
|
16608
16293
|
const files = readdirSync24(agentDir).filter((f) => f.endsWith(".json")).sort().reverse().slice(0, lastN);
|
|
16609
16294
|
const entries = [];
|
|
16610
16295
|
for (const file of files) {
|
|
16611
16296
|
try {
|
|
16612
|
-
const raw =
|
|
16297
|
+
const raw = readFileSync23(join32(agentDir, file), "utf-8");
|
|
16613
16298
|
entries.push(JSON.parse(raw));
|
|
16614
16299
|
} catch {
|
|
16615
16300
|
continue;
|
|
@@ -16654,9 +16339,9 @@ var init_redact_inline = __esm({
|
|
|
16654
16339
|
});
|
|
16655
16340
|
|
|
16656
16341
|
// ../engine/dist/parsers/skills-source.js
|
|
16657
|
-
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as
|
|
16342
|
+
import { existsSync as existsSync33, readdirSync as readdirSync25, readFileSync as readFileSync24, statSync as statSync29 } from "fs";
|
|
16658
16343
|
import { homedir as homedir12 } from "os";
|
|
16659
|
-
import { join as
|
|
16344
|
+
import { join as join33 } from "path";
|
|
16660
16345
|
function rebuildBody(content) {
|
|
16661
16346
|
const { text, redacted } = redactInlineSecrets(content);
|
|
16662
16347
|
const out = {};
|
|
@@ -16674,25 +16359,25 @@ function resolveRoots() {
|
|
|
16674
16359
|
const home = homedir12();
|
|
16675
16360
|
const all = [];
|
|
16676
16361
|
if (isSourceEnabled("shared", "skills")) {
|
|
16677
|
-
all.push({ path:
|
|
16362
|
+
all.push({ path: join33(home, ".agents", "skills"), tool: "shared" });
|
|
16678
16363
|
}
|
|
16679
16364
|
if (isSourceEnabled("claude", "skills")) {
|
|
16680
16365
|
all.push({ path: claudeBackend.skillsDir(), tool: "claude" });
|
|
16681
16366
|
}
|
|
16682
16367
|
if (isSourceEnabled("agy", "skills")) {
|
|
16683
|
-
all.push({ path:
|
|
16368
|
+
all.push({ path: join33(agyBackend.homeDir(), "skills"), tool: "agy" });
|
|
16684
16369
|
all.push({ path: agyBackend.sharedSkillsDir(), tool: "agy" });
|
|
16685
16370
|
}
|
|
16686
16371
|
if (isSourceEnabled("opencode", "skills")) {
|
|
16687
|
-
all.push({ path:
|
|
16372
|
+
all.push({ path: join33(home, ".config", "opencode", "skills"), tool: "opencode" }, { path: join33(home, ".config", "opencode", "skill"), tool: "opencode" }, { path: join33(home, ".opencode", "skill"), tool: "opencode" }, { path: join33(home, ".opencode", "skills"), tool: "opencode" });
|
|
16688
16373
|
}
|
|
16689
16374
|
if (isSourceEnabled("codex", "skills")) {
|
|
16690
16375
|
all.push({ path: codexBackend.skillsDir(), tool: "codex", skipChildren: [".system"] });
|
|
16691
16376
|
all.push({ path: codexBackend.skillsSystemDir(), tool: "codex", readonly: true });
|
|
16692
16377
|
}
|
|
16693
16378
|
if (isSourceEnabled("cursor", "skills")) {
|
|
16694
|
-
all.push({ path:
|
|
16695
|
-
all.push({ path:
|
|
16379
|
+
all.push({ path: join33(cursorHomeDir(), "skills"), tool: "cursor" });
|
|
16380
|
+
all.push({ path: join33(cursorHomeDir(), "skills-cursor"), tool: "cursor", readonly: true });
|
|
16696
16381
|
}
|
|
16697
16382
|
return all.filter((r) => existsSync33(r.path));
|
|
16698
16383
|
}
|
|
@@ -16737,7 +16422,7 @@ var init_skills_source = __esm({
|
|
|
16737
16422
|
const codexPluginsDir = codexBackend.pluginsDir();
|
|
16738
16423
|
if (existsSync33(codexPluginsDir)) {
|
|
16739
16424
|
for (const pluginName of readdirSync25(codexPluginsDir)) {
|
|
16740
|
-
const skillsDir =
|
|
16425
|
+
const skillsDir = join33(codexPluginsDir, pluginName, "skills");
|
|
16741
16426
|
if (!existsSync33(skillsDir))
|
|
16742
16427
|
continue;
|
|
16743
16428
|
yield* this.fromSkillRoot({ path: skillsDir, tool: "codex" }, pluginName);
|
|
@@ -16754,7 +16439,7 @@ var init_skills_source = __esm({
|
|
|
16754
16439
|
for (const name of entries) {
|
|
16755
16440
|
if (root.skipChildren?.includes(name))
|
|
16756
16441
|
continue;
|
|
16757
|
-
const skillDir =
|
|
16442
|
+
const skillDir = join33(root.path, name);
|
|
16758
16443
|
let st;
|
|
16759
16444
|
try {
|
|
16760
16445
|
st = statSync29(skillDir);
|
|
@@ -16763,12 +16448,12 @@ var init_skills_source = __esm({
|
|
|
16763
16448
|
}
|
|
16764
16449
|
if (!st.isDirectory())
|
|
16765
16450
|
continue;
|
|
16766
|
-
const skillMd =
|
|
16451
|
+
const skillMd = join33(skillDir, "SKILL.md");
|
|
16767
16452
|
if (!existsSync33(skillMd))
|
|
16768
16453
|
continue;
|
|
16769
16454
|
let content;
|
|
16770
16455
|
try {
|
|
16771
|
-
content =
|
|
16456
|
+
content = readFileSync24(skillMd, "utf-8");
|
|
16772
16457
|
} catch {
|
|
16773
16458
|
continue;
|
|
16774
16459
|
}
|
|
@@ -16782,7 +16467,7 @@ var init_skills_source = __esm({
|
|
|
16782
16467
|
const subdirs = {};
|
|
16783
16468
|
try {
|
|
16784
16469
|
for (const sub of readdirSync25(skillDir)) {
|
|
16785
|
-
const subPath =
|
|
16470
|
+
const subPath = join33(skillDir, sub);
|
|
16786
16471
|
try {
|
|
16787
16472
|
const ss = statSync29(subPath);
|
|
16788
16473
|
if (ss.isDirectory()) {
|
|
@@ -16831,7 +16516,7 @@ var init_skills_source = __esm({
|
|
|
16831
16516
|
async parse(item) {
|
|
16832
16517
|
if (!existsSync33(item.filePath))
|
|
16833
16518
|
return [];
|
|
16834
|
-
const content =
|
|
16519
|
+
const content = readFileSync24(item.filePath, "utf-8");
|
|
16835
16520
|
if (!content.trim())
|
|
16836
16521
|
return [];
|
|
16837
16522
|
return [{
|
|
@@ -16854,14 +16539,14 @@ var init_skills_source = __esm({
|
|
|
16854
16539
|
});
|
|
16855
16540
|
|
|
16856
16541
|
// ../engine/dist/parsers/mcps-source.js
|
|
16857
|
-
import { existsSync as existsSync34, readdirSync as readdirSync26, readFileSync as
|
|
16542
|
+
import { existsSync as existsSync34, readdirSync as readdirSync26, readFileSync as readFileSync25, statSync as statSync30 } from "fs";
|
|
16858
16543
|
import { homedir as homedir13 } from "os";
|
|
16859
|
-
import { join as
|
|
16544
|
+
import { join as join34 } from "path";
|
|
16860
16545
|
function readJson(path) {
|
|
16861
16546
|
if (!existsSync34(path))
|
|
16862
16547
|
return null;
|
|
16863
16548
|
try {
|
|
16864
|
-
const raw =
|
|
16549
|
+
const raw = readFileSync25(path, "utf-8");
|
|
16865
16550
|
const stripped = path.endsWith(".jsonc") ? raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,(\s*[}\]])/g, "$1") : raw;
|
|
16866
16551
|
return JSON.parse(stripped);
|
|
16867
16552
|
} catch {
|
|
@@ -16922,23 +16607,23 @@ var init_mcps_source = __esm({
|
|
|
16922
16607
|
if (!isSourceEnabled("common", "mcps"))
|
|
16923
16608
|
return;
|
|
16924
16609
|
const home = homedir13();
|
|
16925
|
-
yield* this.fromObject(readJson(
|
|
16610
|
+
yield* this.fromObject(readJson(join34(home, ".mcp.json"))?.mcpServers, {
|
|
16926
16611
|
tool: "claude",
|
|
16927
|
-
filePath:
|
|
16612
|
+
filePath: join34(home, ".mcp.json"),
|
|
16928
16613
|
scope: "global"
|
|
16929
16614
|
});
|
|
16930
|
-
yield* this.fromObject(readJson(
|
|
16615
|
+
yield* this.fromObject(readJson(join34(home, ".claude.json"))?.mcpServers, {
|
|
16931
16616
|
tool: "claude",
|
|
16932
|
-
filePath:
|
|
16617
|
+
filePath: join34(home, ".claude.json"),
|
|
16933
16618
|
scope: "user"
|
|
16934
16619
|
});
|
|
16935
16620
|
for (const path of [
|
|
16936
|
-
|
|
16937
|
-
|
|
16938
|
-
|
|
16939
|
-
|
|
16940
|
-
|
|
16941
|
-
|
|
16621
|
+
join34(home, ".config", "opencode", "opencode.json"),
|
|
16622
|
+
join34(home, ".config", "opencode", "opencode.jsonc"),
|
|
16623
|
+
join34(home, ".config", "opencode", "config.json"),
|
|
16624
|
+
join34(home, ".opencode", "opencode.json"),
|
|
16625
|
+
join34(home, ".opencode", "opencode.jsonc"),
|
|
16626
|
+
join34(home, ".opencode", "config.json")
|
|
16942
16627
|
]) {
|
|
16943
16628
|
yield* this.fromObject(readJson(path)?.mcp, {
|
|
16944
16629
|
tool: "opencode",
|
|
@@ -16953,13 +16638,13 @@ var init_mcps_source = __esm({
|
|
|
16953
16638
|
filePath: geminiSettings,
|
|
16954
16639
|
scope: "user"
|
|
16955
16640
|
});
|
|
16956
|
-
const cursorMcp =
|
|
16641
|
+
const cursorMcp = join34(cursorHomeDir(), "mcp.json");
|
|
16957
16642
|
yield* this.fromObject(readJson(cursorMcp)?.mcpServers, {
|
|
16958
16643
|
tool: "cursor",
|
|
16959
16644
|
filePath: cursorMcp,
|
|
16960
16645
|
scope: "user"
|
|
16961
16646
|
});
|
|
16962
|
-
const agyMcp =
|
|
16647
|
+
const agyMcp = join34(home, ".gemini", "config", "mcp_config.json");
|
|
16963
16648
|
yield* this.fromObject(readJson(agyMcp)?.mcpServers, {
|
|
16964
16649
|
tool: "agy",
|
|
16965
16650
|
filePath: agyMcp,
|
|
@@ -16969,7 +16654,7 @@ var init_mcps_source = __esm({
|
|
|
16969
16654
|
const pluginsDir = codexBackend.pluginsDir();
|
|
16970
16655
|
if (existsSync34(pluginsDir)) {
|
|
16971
16656
|
for (const plugin of readdirSync26(pluginsDir)) {
|
|
16972
|
-
const mcpPath =
|
|
16657
|
+
const mcpPath = join34(pluginsDir, plugin, ".mcp.json");
|
|
16973
16658
|
yield* this.fromObject(readJson(mcpPath)?.mcpServers, {
|
|
16974
16659
|
tool: "codex",
|
|
16975
16660
|
filePath: mcpPath,
|
|
@@ -17023,7 +16708,7 @@ var init_mcps_source = __esm({
|
|
|
17023
16708
|
return;
|
|
17024
16709
|
let content;
|
|
17025
16710
|
try {
|
|
17026
|
-
content =
|
|
16711
|
+
content = readFileSync25(path, "utf-8");
|
|
17027
16712
|
} catch {
|
|
17028
16713
|
return;
|
|
17029
16714
|
}
|
|
@@ -17192,8 +16877,8 @@ var init_toolkit_format = __esm({
|
|
|
17192
16877
|
});
|
|
17193
16878
|
|
|
17194
16879
|
// ../engine/dist/parsers/slash-commands-source.js
|
|
17195
|
-
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as
|
|
17196
|
-
import { join as
|
|
16880
|
+
import { existsSync as existsSync35, readdirSync as readdirSync27, readFileSync as readFileSync26, statSync as statSync31 } from "fs";
|
|
16881
|
+
import { join as join35, basename as basename18 } from "path";
|
|
17197
16882
|
function rebuildBody2(content) {
|
|
17198
16883
|
const { text, redacted } = redactInlineSecrets(content);
|
|
17199
16884
|
const out = {};
|
|
@@ -17251,7 +16936,7 @@ var init_slash_commands_source = __esm({
|
|
|
17251
16936
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17252
16937
|
continue;
|
|
17253
16938
|
const projectPath = resolveProjectDirName(entry.name);
|
|
17254
|
-
const cmdDir =
|
|
16939
|
+
const cmdDir = join35(projectPath, ".claude", "commands");
|
|
17255
16940
|
if (existsSync35(cmdDir))
|
|
17256
16941
|
roots.push({ path: cmdDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
17257
16942
|
}
|
|
@@ -17260,7 +16945,7 @@ var init_slash_commands_source = __esm({
|
|
|
17260
16945
|
}
|
|
17261
16946
|
}
|
|
17262
16947
|
if (isSourceEnabled("agy", "commands")) {
|
|
17263
|
-
roots.push({ path:
|
|
16948
|
+
roots.push({ path: join35(agyBackend.homeDir(), "commands"), tool: "agy", scope: "user", projectPath: "", format: "toml" });
|
|
17264
16949
|
roots.push({ path: agyBackend.sharedCommandsDir(), tool: "agy", scope: "user", projectPath: "", format: "toml" });
|
|
17265
16950
|
}
|
|
17266
16951
|
if (isSourceEnabled("opencode", "commands")) {
|
|
@@ -17270,7 +16955,7 @@ var init_slash_commands_source = __esm({
|
|
|
17270
16955
|
roots.push({ path: codexBackend.promptsDir(), tool: "codex", scope: "user", projectPath: "", format: "md" });
|
|
17271
16956
|
}
|
|
17272
16957
|
if (isSourceEnabled("cursor", "commands")) {
|
|
17273
|
-
roots.push({ path:
|
|
16958
|
+
roots.push({ path: join35(cursorHomeDir(), "commands"), tool: "cursor", scope: "user", projectPath: "", format: "md" });
|
|
17274
16959
|
}
|
|
17275
16960
|
return roots;
|
|
17276
16961
|
}
|
|
@@ -17284,10 +16969,10 @@ var init_slash_commands_source = __esm({
|
|
|
17284
16969
|
continue;
|
|
17285
16970
|
}
|
|
17286
16971
|
for (const file of files) {
|
|
17287
|
-
const filePath =
|
|
16972
|
+
const filePath = join35(root.path, file);
|
|
17288
16973
|
try {
|
|
17289
16974
|
const stat3 = statSync31(filePath);
|
|
17290
|
-
const content =
|
|
16975
|
+
const content = readFileSync26(filePath, "utf-8");
|
|
17291
16976
|
const parsed = parseCommand(content, basename18(file, ext), root.format);
|
|
17292
16977
|
yield {
|
|
17293
16978
|
id: `${root.tool}_cmd_${root.scope}_${parsed.name}`,
|
|
@@ -17316,7 +17001,7 @@ var init_slash_commands_source = __esm({
|
|
|
17316
17001
|
async parse(item) {
|
|
17317
17002
|
if (!existsSync35(item.filePath))
|
|
17318
17003
|
return [];
|
|
17319
|
-
const content =
|
|
17004
|
+
const content = readFileSync26(item.filePath, "utf-8");
|
|
17320
17005
|
if (!content.trim())
|
|
17321
17006
|
return [];
|
|
17322
17007
|
return [{
|
|
@@ -17339,8 +17024,8 @@ var init_slash_commands_source = __esm({
|
|
|
17339
17024
|
});
|
|
17340
17025
|
|
|
17341
17026
|
// ../engine/dist/parsers/subagents-source.js
|
|
17342
|
-
import { existsSync as existsSync36, readdirSync as readdirSync28, readFileSync as
|
|
17343
|
-
import { join as
|
|
17027
|
+
import { existsSync as existsSync36, readdirSync as readdirSync28, readFileSync as readFileSync27, statSync as statSync32 } from "fs";
|
|
17028
|
+
import { join as join36, basename as basename19 } from "path";
|
|
17344
17029
|
function rebuildBody3(content) {
|
|
17345
17030
|
const { text, redacted } = redactInlineSecrets(content);
|
|
17346
17031
|
const out = {};
|
|
@@ -17400,7 +17085,7 @@ var init_subagents_source = __esm({
|
|
|
17400
17085
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17401
17086
|
continue;
|
|
17402
17087
|
const projectPath = resolveProjectDirName(entry.name);
|
|
17403
|
-
const agentDir =
|
|
17088
|
+
const agentDir = join36(projectPath, ".claude", "agents");
|
|
17404
17089
|
if (existsSync36(agentDir))
|
|
17405
17090
|
roots.push({ path: agentDir, tool: "claude", scope: "project", projectPath, format: "md" });
|
|
17406
17091
|
}
|
|
@@ -17409,7 +17094,7 @@ var init_subagents_source = __esm({
|
|
|
17409
17094
|
}
|
|
17410
17095
|
}
|
|
17411
17096
|
if (isSourceEnabled("agy", "agents")) {
|
|
17412
|
-
roots.push({ path:
|
|
17097
|
+
roots.push({ path: join36(agyBackend.homeDir(), "agents"), tool: "agy", scope: "user", projectPath: "", format: "md" });
|
|
17413
17098
|
roots.push({ path: agyBackend.sharedAgentsDir(), tool: "agy", scope: "user", projectPath: "", format: "md" });
|
|
17414
17099
|
}
|
|
17415
17100
|
if (isSourceEnabled("opencode", "agents")) {
|
|
@@ -17419,7 +17104,7 @@ var init_subagents_source = __esm({
|
|
|
17419
17104
|
roots.push({ path: codexBackend.agentsDir(), tool: "codex", scope: "user", projectPath: "", format: "toml" });
|
|
17420
17105
|
}
|
|
17421
17106
|
if (isSourceEnabled("cursor", "agents")) {
|
|
17422
|
-
roots.push({ path:
|
|
17107
|
+
roots.push({ path: join36(cursorHomeDir(), "agents"), tool: "cursor", scope: "user", projectPath: "", format: "md" });
|
|
17423
17108
|
}
|
|
17424
17109
|
return roots;
|
|
17425
17110
|
}
|
|
@@ -17433,10 +17118,10 @@ var init_subagents_source = __esm({
|
|
|
17433
17118
|
continue;
|
|
17434
17119
|
}
|
|
17435
17120
|
for (const file of files) {
|
|
17436
|
-
const filePath =
|
|
17121
|
+
const filePath = join36(root.path, file);
|
|
17437
17122
|
try {
|
|
17438
17123
|
const stat3 = statSync32(filePath);
|
|
17439
|
-
const content =
|
|
17124
|
+
const content = readFileSync27(filePath, "utf-8");
|
|
17440
17125
|
const parsed = parseAgent(content, basename19(file, ext), root.format);
|
|
17441
17126
|
yield {
|
|
17442
17127
|
id: `${root.tool}_agent_${root.scope}_${parsed.name}`,
|
|
@@ -17466,7 +17151,7 @@ var init_subagents_source = __esm({
|
|
|
17466
17151
|
async parse(item) {
|
|
17467
17152
|
if (!existsSync36(item.filePath))
|
|
17468
17153
|
return [];
|
|
17469
|
-
const content =
|
|
17154
|
+
const content = readFileSync27(item.filePath, "utf-8");
|
|
17470
17155
|
if (!content.trim())
|
|
17471
17156
|
return [];
|
|
17472
17157
|
return [{
|
|
@@ -17489,13 +17174,13 @@ var init_subagents_source = __esm({
|
|
|
17489
17174
|
});
|
|
17490
17175
|
|
|
17491
17176
|
// ../engine/dist/parsers/hooks-source.js
|
|
17492
|
-
import { existsSync as existsSync37, readFileSync as
|
|
17493
|
-
import { join as
|
|
17177
|
+
import { existsSync as existsSync37, readFileSync as readFileSync28, readdirSync as readdirSync29, statSync as statSync33 } from "fs";
|
|
17178
|
+
import { join as join37 } from "path";
|
|
17494
17179
|
function readJson2(path) {
|
|
17495
17180
|
if (!existsSync37(path))
|
|
17496
17181
|
return null;
|
|
17497
17182
|
try {
|
|
17498
|
-
return JSON.parse(
|
|
17183
|
+
return JSON.parse(readFileSync28(path, "utf-8"));
|
|
17499
17184
|
} catch {
|
|
17500
17185
|
return null;
|
|
17501
17186
|
}
|
|
@@ -17520,7 +17205,7 @@ var init_hooks_source = __esm({
|
|
|
17520
17205
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
17521
17206
|
continue;
|
|
17522
17207
|
const projectPath = resolveProjectDirName(entry.name);
|
|
17523
|
-
const settingsPath2 =
|
|
17208
|
+
const settingsPath2 = join37(projectPath, ".claude", "settings.json");
|
|
17524
17209
|
if (existsSync37(settingsPath2)) {
|
|
17525
17210
|
yield* this.fromSettings(settingsPath2, "project", projectPath);
|
|
17526
17211
|
}
|
|
@@ -17612,14 +17297,14 @@ var init_hooks_source = __esm({
|
|
|
17612
17297
|
});
|
|
17613
17298
|
|
|
17614
17299
|
// ../engine/dist/parsers/plugins-source.js
|
|
17615
|
-
import { existsSync as existsSync38, readFileSync as
|
|
17300
|
+
import { existsSync as existsSync38, readFileSync as readFileSync29, readdirSync as readdirSync30, statSync as statSync34 } from "fs";
|
|
17616
17301
|
import { homedir as homedir14 } from "os";
|
|
17617
|
-
import { join as
|
|
17302
|
+
import { join as join38 } from "path";
|
|
17618
17303
|
function readJson3(path) {
|
|
17619
17304
|
if (!existsSync38(path))
|
|
17620
17305
|
return null;
|
|
17621
17306
|
try {
|
|
17622
|
-
return JSON.parse(
|
|
17307
|
+
return JSON.parse(readFileSync29(path, "utf-8"));
|
|
17623
17308
|
} catch {
|
|
17624
17309
|
return null;
|
|
17625
17310
|
}
|
|
@@ -17679,7 +17364,7 @@ var init_plugins_source = __esm({
|
|
|
17679
17364
|
entries = [];
|
|
17680
17365
|
}
|
|
17681
17366
|
for (const name of entries) {
|
|
17682
|
-
const dir =
|
|
17367
|
+
const dir = join38(gemRoot, name);
|
|
17683
17368
|
let st;
|
|
17684
17369
|
try {
|
|
17685
17370
|
st = statSync34(dir);
|
|
@@ -17688,7 +17373,7 @@ var init_plugins_source = __esm({
|
|
|
17688
17373
|
}
|
|
17689
17374
|
if (!st.isDirectory())
|
|
17690
17375
|
continue;
|
|
17691
|
-
const manifestPath =
|
|
17376
|
+
const manifestPath = join38(dir, "gemini-extension.json");
|
|
17692
17377
|
const manifest = readJson3(manifestPath);
|
|
17693
17378
|
if (!manifest || typeof manifest !== "object")
|
|
17694
17379
|
continue;
|
|
@@ -17727,7 +17412,7 @@ var init_plugins_source = __esm({
|
|
|
17727
17412
|
entries = [];
|
|
17728
17413
|
}
|
|
17729
17414
|
for (const name of entries) {
|
|
17730
|
-
const pluginDir =
|
|
17415
|
+
const pluginDir = join38(codexPluginsRoot, name);
|
|
17731
17416
|
let st;
|
|
17732
17417
|
try {
|
|
17733
17418
|
st = statSync34(pluginDir);
|
|
@@ -17736,11 +17421,11 @@ var init_plugins_source = __esm({
|
|
|
17736
17421
|
}
|
|
17737
17422
|
if (!st.isDirectory())
|
|
17738
17423
|
continue;
|
|
17739
|
-
const appJson = readJson3(
|
|
17740
|
-
const pluginJson = readJson3(
|
|
17424
|
+
const appJson = readJson3(join38(pluginDir, ".codex-plugin", ".app.json"));
|
|
17425
|
+
const pluginJson = readJson3(join38(pluginDir, ".codex-plugin", "plugin.json"));
|
|
17741
17426
|
const manifest = pluginJson || appJson || {};
|
|
17742
17427
|
let mcpServers = [];
|
|
17743
|
-
const mcpJson = readJson3(
|
|
17428
|
+
const mcpJson = readJson3(join38(pluginDir, ".mcp.json"));
|
|
17744
17429
|
if (mcpJson?.mcpServers)
|
|
17745
17430
|
mcpServers = Object.keys(mcpJson.mcpServers);
|
|
17746
17431
|
yield {
|
|
@@ -17748,7 +17433,7 @@ var init_plugins_source = __esm({
|
|
|
17748
17433
|
sourceType: "plugin",
|
|
17749
17434
|
title: manifest.name || name,
|
|
17750
17435
|
projectPath: "",
|
|
17751
|
-
filePath:
|
|
17436
|
+
filePath: join38(pluginDir, ".codex-plugin"),
|
|
17752
17437
|
mtime: st.mtimeMs,
|
|
17753
17438
|
contentPreview: (manifest.description || "").slice(0, 300),
|
|
17754
17439
|
extra: {
|
|
@@ -17796,7 +17481,6 @@ var init_plugins_source = __esm({
|
|
|
17796
17481
|
|
|
17797
17482
|
// ../engine/dist/parsers/all-sources.js
|
|
17798
17483
|
function buildSourceRegistry(registry = new SourceRegistry()) {
|
|
17799
|
-
registry.register(new SessionSource());
|
|
17800
17484
|
registry.register(new PlanSource());
|
|
17801
17485
|
registry.register(new TaskSource());
|
|
17802
17486
|
registry.register(new ClaudeMdSource());
|
|
@@ -17820,7 +17504,6 @@ var init_all_sources = __esm({
|
|
|
17820
17504
|
"../engine/dist/parsers/all-sources.js"() {
|
|
17821
17505
|
"use strict";
|
|
17822
17506
|
init_source_registry();
|
|
17823
|
-
init_session_source();
|
|
17824
17507
|
init_plan_source();
|
|
17825
17508
|
init_task_source();
|
|
17826
17509
|
init_claude_md_source();
|
|
@@ -17908,8 +17591,8 @@ __export(sync_ledger_exports, {
|
|
|
17908
17591
|
syncMode: () => syncMode,
|
|
17909
17592
|
unackedCursorAttemptCount: () => unackedCursorAttemptCount
|
|
17910
17593
|
});
|
|
17911
|
-
import { readFileSync as
|
|
17912
|
-
import { join as
|
|
17594
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync6, renameSync as renameSync4, mkdirSync as mkdirSync7 } from "node:fs";
|
|
17595
|
+
import { join as join39, dirname as dirname16 } from "node:path";
|
|
17913
17596
|
function toRow(entry) {
|
|
17914
17597
|
if (entry === void 0) return void 0;
|
|
17915
17598
|
return typeof entry === "number" ? { m: entry, v: 0 } : entry;
|
|
@@ -17920,7 +17603,7 @@ function ledgerFilePath() {
|
|
|
17920
17603
|
function load() {
|
|
17921
17604
|
if (cache3) return cache3;
|
|
17922
17605
|
try {
|
|
17923
|
-
const parsed = JSON.parse(
|
|
17606
|
+
const parsed = JSON.parse(readFileSync30(ledgerPath(), "utf-8"));
|
|
17924
17607
|
cache3 = parsed && typeof parsed === "object" ? parsed : {};
|
|
17925
17608
|
} catch {
|
|
17926
17609
|
cache3 = {};
|
|
@@ -17929,9 +17612,9 @@ function load() {
|
|
|
17929
17612
|
}
|
|
17930
17613
|
function persistNow(data) {
|
|
17931
17614
|
const path = ledgerPath();
|
|
17932
|
-
|
|
17615
|
+
mkdirSync7(dirname16(path), { recursive: true });
|
|
17933
17616
|
const tmp = `${path}.tmp`;
|
|
17934
|
-
|
|
17617
|
+
writeFileSync6(tmp, JSON.stringify(data));
|
|
17935
17618
|
renameSync4(tmp, path);
|
|
17936
17619
|
pendingWrite = false;
|
|
17937
17620
|
}
|
|
@@ -17966,10 +17649,10 @@ function pruneLedgerTargets(configuredServers) {
|
|
|
17966
17649
|
try {
|
|
17967
17650
|
let prior = {};
|
|
17968
17651
|
try {
|
|
17969
|
-
prior = JSON.parse(
|
|
17652
|
+
prior = JSON.parse(readFileSync30(side, "utf-8"));
|
|
17970
17653
|
} catch {
|
|
17971
17654
|
}
|
|
17972
|
-
|
|
17655
|
+
writeFileSync6(side, JSON.stringify({ ...prior, ...orphans }));
|
|
17973
17656
|
} catch {
|
|
17974
17657
|
for (const n of names) data[n] = orphans[n];
|
|
17975
17658
|
return 0;
|
|
@@ -17990,7 +17673,7 @@ function flushLedger() {
|
|
|
17990
17673
|
function loadItemVersionsAll() {
|
|
17991
17674
|
if (itemVersionsCache) return itemVersionsCache;
|
|
17992
17675
|
try {
|
|
17993
|
-
const parsed = JSON.parse(
|
|
17676
|
+
const parsed = JSON.parse(readFileSync30(itemVersionsPath(), "utf-8"));
|
|
17994
17677
|
itemVersionsCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
17995
17678
|
} catch {
|
|
17996
17679
|
itemVersionsCache = {};
|
|
@@ -18004,9 +17687,9 @@ function saveItemVersions(server, versions) {
|
|
|
18004
17687
|
const all = loadItemVersionsAll();
|
|
18005
17688
|
all[server] = { ...all[server] || {}, ...versions };
|
|
18006
17689
|
const path = itemVersionsPath();
|
|
18007
|
-
|
|
17690
|
+
mkdirSync7(dirname16(path), { recursive: true });
|
|
18008
17691
|
const tmp = `${path}.tmp`;
|
|
18009
|
-
|
|
17692
|
+
writeFileSync6(tmp, JSON.stringify(all));
|
|
18010
17693
|
renameSync4(tmp, path);
|
|
18011
17694
|
}
|
|
18012
17695
|
function getSyncedMtimes(server) {
|
|
@@ -18084,7 +17767,7 @@ function markFieldCoverage(server, field, rows) {
|
|
|
18084
17767
|
function loadReconcile() {
|
|
18085
17768
|
if (reconcileCache) return reconcileCache;
|
|
18086
17769
|
try {
|
|
18087
|
-
const parsed = JSON.parse(
|
|
17770
|
+
const parsed = JSON.parse(readFileSync30(reconcilePath(), "utf-8"));
|
|
18088
17771
|
reconcileCache = parsed && typeof parsed === "object" ? parsed : {};
|
|
18089
17772
|
} catch {
|
|
18090
17773
|
reconcileCache = {};
|
|
@@ -18093,9 +17776,9 @@ function loadReconcile() {
|
|
|
18093
17776
|
}
|
|
18094
17777
|
function persistReconcile(data) {
|
|
18095
17778
|
const path = reconcilePath();
|
|
18096
|
-
|
|
17779
|
+
mkdirSync7(dirname16(path), { recursive: true });
|
|
18097
17780
|
const tmp = `${path}.tmp`;
|
|
18098
|
-
|
|
17781
|
+
writeFileSync6(tmp, JSON.stringify(data));
|
|
18099
17782
|
renameSync4(tmp, path);
|
|
18100
17783
|
}
|
|
18101
17784
|
function stateFor(server) {
|
|
@@ -18153,15 +17836,15 @@ var init_sync_ledger = __esm({
|
|
|
18153
17836
|
"use strict";
|
|
18154
17837
|
init_paths();
|
|
18155
17838
|
init_extractor_version();
|
|
18156
|
-
ledgerPath = () =>
|
|
17839
|
+
ledgerPath = () => join39(getDataDir(), "sync-ledger.json");
|
|
18157
17840
|
cache3 = null;
|
|
18158
17841
|
LEDGER_FLUSH_MS = 2e3;
|
|
18159
17842
|
pendingWrite = false;
|
|
18160
17843
|
flushTimer = null;
|
|
18161
|
-
itemVersionsPath = () =>
|
|
17844
|
+
itemVersionsPath = () => join39(getDataDir(), "item-versions.json");
|
|
18162
17845
|
itemVersionsCache = null;
|
|
18163
17846
|
unackedCursorAttempts = 0;
|
|
18164
|
-
reconcilePath = () =>
|
|
17847
|
+
reconcilePath = () => join39(getDataDir(), "sync-field-reconcile.json");
|
|
18165
17848
|
reconcileCache = null;
|
|
18166
17849
|
}
|
|
18167
17850
|
});
|
|
@@ -18192,11 +17875,11 @@ var init_sync_fields = __esm({
|
|
|
18192
17875
|
});
|
|
18193
17876
|
|
|
18194
17877
|
// ../engine/dist/core/index-lock.js
|
|
18195
|
-
import { existsSync as existsSync39, mkdirSync as
|
|
18196
|
-
import { dirname as
|
|
17878
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync8, openSync as openSync7, writeFileSync as writeFileSync7, readFileSync as readFileSync31, rmSync as rmSync4, statSync as statSync35, closeSync as closeSync7 } from "fs";
|
|
17879
|
+
import { dirname as dirname17, join as join40 } from "path";
|
|
18197
17880
|
function acquireIndexLock(opts) {
|
|
18198
17881
|
const lockPath = lockFilePath();
|
|
18199
|
-
|
|
17882
|
+
mkdirSync8(dirname17(lockPath), { recursive: true });
|
|
18200
17883
|
if (existsSync39(lockPath)) {
|
|
18201
17884
|
if (!stealStaleLock(lockPath, opts.staleAfterMs ?? 10 * 6e4)) {
|
|
18202
17885
|
return null;
|
|
@@ -18212,7 +17895,7 @@ function acquireIndexLock(opts) {
|
|
|
18212
17895
|
}
|
|
18213
17896
|
const holder = { pid: process.pid, kind: opts.kind, startedAt: Date.now() };
|
|
18214
17897
|
try {
|
|
18215
|
-
|
|
17898
|
+
writeFileSync7(fd, JSON.stringify(holder));
|
|
18216
17899
|
} finally {
|
|
18217
17900
|
closeSync7(fd);
|
|
18218
17901
|
}
|
|
@@ -18224,7 +17907,7 @@ function acquireIndexLock(opts) {
|
|
|
18224
17907
|
return;
|
|
18225
17908
|
released = true;
|
|
18226
17909
|
try {
|
|
18227
|
-
const current = JSON.parse(
|
|
17910
|
+
const current = JSON.parse(readFileSync31(lockPath, "utf-8"));
|
|
18228
17911
|
if (current.pid !== holder.pid || current.startedAt !== holder.startedAt)
|
|
18229
17912
|
return;
|
|
18230
17913
|
} catch {
|
|
@@ -18238,7 +17921,7 @@ function acquireIndexLock(opts) {
|
|
|
18238
17921
|
};
|
|
18239
17922
|
}
|
|
18240
17923
|
function lockFilePath() {
|
|
18241
|
-
return
|
|
17924
|
+
return join40(getIndexDir(), ".compact.lock");
|
|
18242
17925
|
}
|
|
18243
17926
|
function stealStaleLock(lockPath, staleAfterMs) {
|
|
18244
17927
|
try {
|
|
@@ -18246,7 +17929,7 @@ function stealStaleLock(lockPath, staleAfterMs) {
|
|
|
18246
17929
|
const age = Date.now() - s.mtimeMs;
|
|
18247
17930
|
let payload;
|
|
18248
17931
|
try {
|
|
18249
|
-
payload = JSON.parse(
|
|
17932
|
+
payload = JSON.parse(readFileSync31(lockPath, "utf-8"));
|
|
18250
17933
|
} catch {
|
|
18251
17934
|
rmSync4(lockPath, { force: true });
|
|
18252
17935
|
return true;
|
|
@@ -18284,7 +17967,7 @@ var init_index_lock = __esm({
|
|
|
18284
17967
|
});
|
|
18285
17968
|
|
|
18286
17969
|
// src/http.ts
|
|
18287
|
-
import { readFileSync as
|
|
17970
|
+
import { readFileSync as readFileSync32 } from "node:fs";
|
|
18288
17971
|
function clientHeaders() {
|
|
18289
17972
|
return {
|
|
18290
17973
|
"x-chat-recall-cli": CLI_VERSION,
|
|
@@ -18302,10 +17985,10 @@ var init_http = __esm({
|
|
|
18302
17985
|
"use strict";
|
|
18303
17986
|
CLI_VERSION = "0.0.0";
|
|
18304
17987
|
try {
|
|
18305
|
-
CLI_VERSION = JSON.parse(
|
|
17988
|
+
CLI_VERSION = JSON.parse(readFileSync32(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
18306
17989
|
} catch {
|
|
18307
17990
|
try {
|
|
18308
|
-
if (true) CLI_VERSION = "0.
|
|
17991
|
+
if (true) CLI_VERSION = "0.7.0";
|
|
18309
17992
|
} catch {
|
|
18310
17993
|
}
|
|
18311
17994
|
}
|
|
@@ -18330,27 +18013,6 @@ var init_redact_deep = __esm({
|
|
|
18330
18013
|
}
|
|
18331
18014
|
});
|
|
18332
18015
|
|
|
18333
|
-
// ../engine/dist/core/session-multi-tool.js
|
|
18334
|
-
function extractTurnsAny(sessionId, opts = {}) {
|
|
18335
|
-
const backend = getBackendForId(sessionId);
|
|
18336
|
-
if (!backend)
|
|
18337
|
-
return { sessionId, found: false, turns: [], startMs: 0, endMs: 0 };
|
|
18338
|
-
return backend.extractTurns(sessionId, opts);
|
|
18339
|
-
}
|
|
18340
|
-
function replaySessionAny(sessionId) {
|
|
18341
|
-
const backend = getBackendForId(sessionId);
|
|
18342
|
-
if (!backend)
|
|
18343
|
-
return { sessionId, found: false, projectPath: "", files: [], totalLinesAdded: 0, totalLinesRemoved: 0 };
|
|
18344
|
-
return backend.replay(sessionId);
|
|
18345
|
-
}
|
|
18346
|
-
var init_session_multi_tool = __esm({
|
|
18347
|
-
"../engine/dist/core/session-multi-tool.js"() {
|
|
18348
|
-
"use strict";
|
|
18349
|
-
init_tool_backend();
|
|
18350
|
-
init_backends();
|
|
18351
|
-
}
|
|
18352
|
-
});
|
|
18353
|
-
|
|
18354
18016
|
// src/derived.ts
|
|
18355
18017
|
function collectDerivedRows(ref, mtime, count, maxRowBytes) {
|
|
18356
18018
|
const id = ref.prefixedId;
|
|
@@ -18821,7 +18483,7 @@ var init_telemetry = __esm({
|
|
|
18821
18483
|
init_sync_client();
|
|
18822
18484
|
cliVersion = () => {
|
|
18823
18485
|
try {
|
|
18824
|
-
return true ? "0.
|
|
18486
|
+
return true ? "0.7.0" : "dev";
|
|
18825
18487
|
} catch {
|
|
18826
18488
|
return "dev";
|
|
18827
18489
|
}
|
|
@@ -18831,60 +18493,6 @@ var init_telemetry = __esm({
|
|
|
18831
18493
|
}
|
|
18832
18494
|
});
|
|
18833
18495
|
|
|
18834
|
-
// ../engine/dist/core/collector-health.js
|
|
18835
|
-
import { readFileSync as readFileSync32, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8 } from "node:fs";
|
|
18836
|
-
import { join as join40, dirname as dirname17 } from "node:path";
|
|
18837
|
-
function collectorHealthPath() {
|
|
18838
|
-
return healthPath();
|
|
18839
|
-
}
|
|
18840
|
-
function readCollectorHealth() {
|
|
18841
|
-
try {
|
|
18842
|
-
const h = JSON.parse(readFileSync32(healthPath(), "utf-8"));
|
|
18843
|
-
return h && h.v === 1 && typeof h.updatedAt === "number" ? h : null;
|
|
18844
|
-
} catch {
|
|
18845
|
-
return null;
|
|
18846
|
-
}
|
|
18847
|
-
}
|
|
18848
|
-
function writeCollectorHealth(h) {
|
|
18849
|
-
try {
|
|
18850
|
-
const p = healthPath();
|
|
18851
|
-
mkdirSync8(dirname17(p), { recursive: true });
|
|
18852
|
-
writeFileSync7(p, JSON.stringify(h));
|
|
18853
|
-
} catch {
|
|
18854
|
-
}
|
|
18855
|
-
}
|
|
18856
|
-
function updateCollectorHealth(patch) {
|
|
18857
|
-
const prior = readCollectorHealth();
|
|
18858
|
-
writeCollectorHealth({
|
|
18859
|
-
...prior,
|
|
18860
|
-
v: 1,
|
|
18861
|
-
updatedAt: Date.now(),
|
|
18862
|
-
startedAt: prior?.startedAt ?? Date.now(),
|
|
18863
|
-
restartsLastHour: prior?.restartsLastHour ?? 0,
|
|
18864
|
-
targets: prior?.targets ?? {},
|
|
18865
|
-
...patch
|
|
18866
|
-
});
|
|
18867
|
-
}
|
|
18868
|
-
function reportWalkProgress(p) {
|
|
18869
|
-
const now = Date.now();
|
|
18870
|
-
const boundary = p.complete || p.done === 0;
|
|
18871
|
-
if (!boundary && now - lastProgressWrite < PROGRESS_WRITE_INTERVAL_MS)
|
|
18872
|
-
return;
|
|
18873
|
-
lastProgressWrite = now;
|
|
18874
|
-
updateCollectorHealth({ progress: p });
|
|
18875
|
-
}
|
|
18876
|
-
var healthPath, PROGRESS_WRITE_INTERVAL_MS, lastProgressWrite, STALE_AFTER_MS;
|
|
18877
|
-
var init_collector_health = __esm({
|
|
18878
|
-
"../engine/dist/core/collector-health.js"() {
|
|
18879
|
-
"use strict";
|
|
18880
|
-
init_paths();
|
|
18881
|
-
healthPath = () => join40(getDataDir(), "collector-health.json");
|
|
18882
|
-
PROGRESS_WRITE_INTERVAL_MS = 2e3;
|
|
18883
|
-
lastProgressWrite = 0;
|
|
18884
|
-
STALE_AFTER_MS = 30 * 6e4;
|
|
18885
|
-
}
|
|
18886
|
-
});
|
|
18887
|
-
|
|
18888
18496
|
// src/server-probe.ts
|
|
18889
18497
|
var server_probe_exports = {};
|
|
18890
18498
|
__export(server_probe_exports, {
|
|
@@ -19571,10 +19179,11 @@ async function syncSessions(opts = {}) {
|
|
|
19571
19179
|
};
|
|
19572
19180
|
continue;
|
|
19573
19181
|
}
|
|
19182
|
+
acceptedUploads.set(cred.serverUrl, 0);
|
|
19574
19183
|
try {
|
|
19575
19184
|
const r = await syncToTarget(cred, opts);
|
|
19576
19185
|
noteTargetSuccess(cred.serverUrl);
|
|
19577
|
-
perTarget[cred.serverUrl] = { ok: true };
|
|
19186
|
+
perTarget[cred.serverUrl] = { ok: true, accepted: acceptedUploads.get(cred.serverUrl) ?? 0 };
|
|
19578
19187
|
agg = agg ? {
|
|
19579
19188
|
uploaded: agg.uploaded + r.uploaded,
|
|
19580
19189
|
skipped: agg.skipped + r.skipped,
|
|
@@ -19591,7 +19200,7 @@ async function syncSessions(opts = {}) {
|
|
|
19591
19200
|
} catch (e) {
|
|
19592
19201
|
const msg = e instanceof Error ? e.message : String(e);
|
|
19593
19202
|
errors.push(`${cred.serverUrl}: ${msg}`);
|
|
19594
|
-
perTarget[cred.serverUrl] = { ok: false, error: msg };
|
|
19203
|
+
perTarget[cred.serverUrl] = { ok: false, error: msg, accepted: acceptedUploads.get(cred.serverUrl) ?? 0 };
|
|
19595
19204
|
const next = noteTargetFailure(cred.serverUrl, msg);
|
|
19596
19205
|
const notice = breakerNotice(cred.serverUrl, next);
|
|
19597
19206
|
if (notice) console.error(`[sync] ${notice}`);
|
|
@@ -19830,7 +19439,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19830
19439
|
return [];
|
|
19831
19440
|
}
|
|
19832
19441
|
});
|
|
19833
|
-
const MAX_BATCH_BYTES = 4 * 1024 * 1024;
|
|
19442
|
+
const MAX_BATCH_BYTES = Number(process.env.CHAT_RECALL_MAX_BATCH_BYTES) || (isLocalHost(cred.serverUrl) ? 4 * 1024 * 1024 : 1024 * 1024);
|
|
19834
19443
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
19835
19444
|
const explicitThrottle = typeof opts.throttleMs === "number" && opts.throttleMs > 0;
|
|
19836
19445
|
const throttleMs = explicitThrottle ? opts.throttleMs : 0;
|
|
@@ -19865,6 +19474,7 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19865
19474
|
signal: ac.signal
|
|
19866
19475
|
});
|
|
19867
19476
|
if (res.ok) {
|
|
19477
|
+
acceptedUploads.set(cred.serverUrl, (acceptedUploads.get(cred.serverUrl) ?? 0) + 1);
|
|
19868
19478
|
const body2 = await res.json().catch(() => ({}));
|
|
19869
19479
|
if (typeof body2.telemetry === "boolean") {
|
|
19870
19480
|
setTelemetryEligible(base2, body2.telemetry);
|
|
@@ -19915,7 +19525,8 @@ async function syncToTargetInScope(cred, opts = {}) {
|
|
|
19915
19525
|
if (attempt >= RETRY_DELAYS_MS.length) throw new Error(`sync failed after ${attempt + 1} attempts: HTTP ${res.status} ${text}`);
|
|
19916
19526
|
const retryAfterS = Number(res.headers.get("retry-after"));
|
|
19917
19527
|
const waitMs = res.status === 429 && retryAfterS > 0 ? retryAfterS * 1e3 : RETRY_DELAYS_MS[attempt];
|
|
19918
|
-
|
|
19528
|
+
const why = res.status === 524 ? ` \u2014 the proxy cut the request at its time limit; the batch is too big for one request` : "";
|
|
19529
|
+
console.error(`[sync] HTTP ${res.status} from ${base2}${why} \u2014 backing off ${Math.round(waitMs / 1e3)}s (attempt ${attempt + 1})`);
|
|
19919
19530
|
await sleep(waitMs);
|
|
19920
19531
|
continue;
|
|
19921
19532
|
} catch (err) {
|
|
@@ -20774,7 +20385,7 @@ async function syncIncremental(opts = {}) {
|
|
|
20774
20385
|
lock.release();
|
|
20775
20386
|
}
|
|
20776
20387
|
}
|
|
20777
|
-
var ownVersion, ERROR_CLASS, STANDING_FAILURE, walkProgressForUpload, lastServerPackSpec, credPath, _securityConfigCache, SECURITY_CONFIG_TTL_MS, _syncConfigCache, EMPTY_SYNC_CONFIG, SYNC_RULES_REFUSAL, hashPath, MAX_DERIVED_ROW_BYTES, isLocalHost, CAPS_TTL_MS, capsOk, advertisedIngestConc, advertisedGzipBody, FULL_BUILD_MAX_BYTES, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
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, FULL_BUILD_TAIL_BYTES, BATCH_SCAN_MAX_BYTES;
|
|
20778
20389
|
var init_sync_client = __esm({
|
|
20779
20390
|
"src/sync-client.ts"() {
|
|
20780
20391
|
"use strict";
|
|
@@ -20819,7 +20430,7 @@ var init_sync_client = __esm({
|
|
|
20819
20430
|
ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
20820
20431
|
} catch {
|
|
20821
20432
|
try {
|
|
20822
|
-
if (true) ownVersion = "0.
|
|
20433
|
+
if (true) ownVersion = "0.7.0";
|
|
20823
20434
|
} catch {
|
|
20824
20435
|
}
|
|
20825
20436
|
}
|
|
@@ -20838,6 +20449,7 @@ var init_sync_client = __esm({
|
|
|
20838
20449
|
EMPTY_SYNC_CONFIG = { excludeTools: [], excludeProjects: [], excludeSources: [], approveSources: [] };
|
|
20839
20450
|
SYNC_RULES_REFUSAL = /* @__PURE__ */ Symbol.for("chat-recall.syncRulesRefusal");
|
|
20840
20451
|
hashPath = (p) => p ? "p_" + createHash8("sha256").update(p).digest("hex").slice(0, 12) : "";
|
|
20452
|
+
acceptedUploads = /* @__PURE__ */ new Map();
|
|
20841
20453
|
MAX_DERIVED_ROW_BYTES = 2 * 1024 * 1024;
|
|
20842
20454
|
isLocalHost = isPrivateHost;
|
|
20843
20455
|
CAPS_TTL_MS = 60 * 6e4;
|
|
@@ -23582,6 +23194,7 @@ var init_service_installer = __esm({
|
|
|
23582
23194
|
// auto-indexer/indexer.ts
|
|
23583
23195
|
init_backends();
|
|
23584
23196
|
init_paths();
|
|
23197
|
+
init_collector_health();
|
|
23585
23198
|
init_settings();
|
|
23586
23199
|
init_sync_client();
|
|
23587
23200
|
init_http();
|
|
@@ -23903,7 +23516,7 @@ try {
|
|
|
23903
23516
|
ownVersion2 = JSON.parse(readFileSync39(join48(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
23904
23517
|
} catch {
|
|
23905
23518
|
try {
|
|
23906
|
-
if (true) ownVersion2 = "0.
|
|
23519
|
+
if (true) ownVersion2 = "0.7.0";
|
|
23907
23520
|
} catch {
|
|
23908
23521
|
}
|
|
23909
23522
|
}
|
|
@@ -24251,7 +23864,7 @@ async function runCollectorMigration(opts) {
|
|
|
24251
23864
|
init_sync_ledger();
|
|
24252
23865
|
init_collector_health();
|
|
24253
23866
|
import { existsSync as existsSync49, readFileSync as readFileSync45, statSync as statSync44 } from "fs";
|
|
24254
|
-
var CLI_VERSION3 = true ? "0.
|
|
23867
|
+
var CLI_VERSION3 = true ? "0.7.0" : "0.0.0";
|
|
24255
23868
|
var DEBOUNCE_MS = 5e3;
|
|
24256
23869
|
var CLAUDE_DIR = claudeBackend.projectsDir();
|
|
24257
23870
|
var PLANS_DIR = claudeBackend.plansDir();
|
|
@@ -24288,7 +23901,7 @@ async function shipToServer(trigger) {
|
|
|
24288
23901
|
);
|
|
24289
23902
|
}
|
|
24290
23903
|
for (const [server, outcome] of Object.entries(result.perTarget ?? {})) {
|
|
24291
|
-
noteSyncOutcome(server, outcome.ok, outcome.error);
|
|
23904
|
+
noteSyncOutcome(server, outcome.ok, outcome.error, outcome.accepted ?? 0);
|
|
24292
23905
|
}
|
|
24293
23906
|
} catch (err) {
|
|
24294
23907
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -24556,6 +24169,9 @@ setTimeout(() => {
|
|
|
24556
24169
|
setInterval(() => {
|
|
24557
24170
|
ticks.request("housekeeping", TICK_PRIORITY.housekeeping, shadowPruneTick);
|
|
24558
24171
|
}, SHADOW_PRUNE_MS).unref();
|
|
24172
|
+
function _targetHealth() {
|
|
24173
|
+
return targetHealth;
|
|
24174
|
+
}
|
|
24559
24175
|
function syncTargetUrls() {
|
|
24560
24176
|
try {
|
|
24561
24177
|
return loadAllCredentials().map((c) => c.serverUrl);
|
|
@@ -24563,17 +24179,8 @@ function syncTargetUrls() {
|
|
|
24563
24179
|
return [];
|
|
24564
24180
|
}
|
|
24565
24181
|
}
|
|
24566
|
-
function noteSyncOutcome(server, ok, err) {
|
|
24567
|
-
|
|
24568
|
-
if (ok) {
|
|
24569
|
-
t.lastOkAt = Date.now();
|
|
24570
|
-
t.failures = 0;
|
|
24571
|
-
delete t.lastError;
|
|
24572
|
-
} else {
|
|
24573
|
-
t.failures += 1;
|
|
24574
|
-
t.lastError = (err ?? "unknown error").slice(0, 160);
|
|
24575
|
-
}
|
|
24576
|
-
targetHealth[server] = t;
|
|
24182
|
+
function noteSyncOutcome(server, ok, err, accepted = 0) {
|
|
24183
|
+
targetHealth[server] = applySyncOutcome(targetHealth[server], { ok, accepted, error: err });
|
|
24577
24184
|
publishHealth();
|
|
24578
24185
|
}
|
|
24579
24186
|
publishHealth();
|
|
@@ -24834,3 +24441,7 @@ process.on("exit", () => {
|
|
|
24834
24441
|
} catch {
|
|
24835
24442
|
}
|
|
24836
24443
|
});
|
|
24444
|
+
export {
|
|
24445
|
+
_targetHealth,
|
|
24446
|
+
noteSyncOutcome
|
|
24447
|
+
};
|