chat-recall 0.6.9 → 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 +785 -1185
- 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 +2392 -2317
- package/dist/scan-worker.js +4 -5
- package/dist/watch.js +598 -1026
- package/package.json +1 -1
- package/skills/chat-recall/SKILL.md +2 -1
- package/skills/chat-recall-memory/SKILL.md +15 -0
package/dist/cli.js
CHANGED
|
@@ -4549,6 +4549,25 @@ var init_paths = __esm({
|
|
|
4549
4549
|
}
|
|
4550
4550
|
});
|
|
4551
4551
|
|
|
4552
|
+
// ../engine/dist/parsers/banners.js
|
|
4553
|
+
function stripInjectedBanners(text) {
|
|
4554
|
+
let result = text;
|
|
4555
|
+
for (const re of INJECTED_BANNERS)
|
|
4556
|
+
result = result.replace(re, " ");
|
|
4557
|
+
return result;
|
|
4558
|
+
}
|
|
4559
|
+
var INJECTED_BANNERS;
|
|
4560
|
+
var init_banners = __esm({
|
|
4561
|
+
"../engine/dist/parsers/banners.js"() {
|
|
4562
|
+
"use strict";
|
|
4563
|
+
INJECTED_BANNERS = [
|
|
4564
|
+
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
4565
|
+
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
4566
|
+
/API Error:[^\n]{0,120}/g
|
|
4567
|
+
];
|
|
4568
|
+
}
|
|
4569
|
+
});
|
|
4570
|
+
|
|
4552
4571
|
// ../engine/dist/core/project-path-match.js
|
|
4553
4572
|
function canonicalProjectPath(p) {
|
|
4554
4573
|
return (p || "").trim().replace(/\\/g, "/").replace(/[-_]/g, "/").replace(/\/{2,}/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -5083,753 +5102,134 @@ var init_settings = __esm({
|
|
|
5083
5102
|
}
|
|
5084
5103
|
});
|
|
5085
5104
|
|
|
5086
|
-
// ../engine/dist/core/
|
|
5087
|
-
var
|
|
5088
|
-
__export(
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
isFilePathRedactionEnabled: () => isFilePathRedactionEnabled,
|
|
5097
|
-
isRedactionEnabled: () => isRedactionEnabled,
|
|
5098
|
-
isToolOutputRedactionEnabled: () => isToolOutputRedactionEnabled,
|
|
5099
|
-
redactFilePaths: () => redactFilePaths,
|
|
5100
|
-
redactSecrets: () => redactSecrets,
|
|
5101
|
-
redactToolResultBody: () => redactToolResultBody,
|
|
5102
|
-
scanTextForFindings: () => scanTextForFindings,
|
|
5103
|
-
serverRulePackVersion: () => serverRulePackVersion,
|
|
5104
|
-
validateRedactionRule: () => validateRedactionRule
|
|
5105
|
+
// ../engine/dist/core/home-approval.js
|
|
5106
|
+
var home_approval_exports = {};
|
|
5107
|
+
__export(home_approval_exports, {
|
|
5108
|
+
approveHome: () => approveHome,
|
|
5109
|
+
declineHome: () => declineHome,
|
|
5110
|
+
grandfatherLegacyHomes: () => grandfatherLegacyHomes,
|
|
5111
|
+
homeDecision: () => homeDecision,
|
|
5112
|
+
isHomeSynced: () => isHomeSynced,
|
|
5113
|
+
normalizeHomePath: () => normalizeHomePath,
|
|
5114
|
+
resetHomeDecision: () => resetHomeDecision
|
|
5105
5115
|
});
|
|
5106
|
-
import {
|
|
5107
|
-
import {
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
return
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
function looksLikeSecretToken(t) {
|
|
5117
|
-
if (t.length < 32)
|
|
5118
|
-
return false;
|
|
5119
|
-
if (/^[a-f0-9]+$/i.test(t))
|
|
5120
|
-
return true;
|
|
5121
|
-
return /[A-Z]/.test(t) && /[a-z]/.test(t) && /[0-9]/.test(t);
|
|
5122
|
-
}
|
|
5123
|
-
function findContextualSecrets(text) {
|
|
5124
|
-
if (!text)
|
|
5125
|
-
return [];
|
|
5126
|
-
const ranges = [];
|
|
5127
|
-
let m;
|
|
5128
|
-
SECRET_CONTEXT_RE.lastIndex = 0;
|
|
5129
|
-
while ((m = SECRET_CONTEXT_RE.exec(text)) !== null) {
|
|
5130
|
-
const winStart = m.index + m[0].length;
|
|
5131
|
-
const window = text.slice(winStart, winStart + 80);
|
|
5132
|
-
HIGH_ENTROPY_TOKEN_RE.lastIndex = 0;
|
|
5133
|
-
let tm;
|
|
5134
|
-
while ((tm = HIGH_ENTROPY_TOKEN_RE.exec(window)) !== null) {
|
|
5135
|
-
if (!looksLikeSecretToken(tm[0]))
|
|
5136
|
-
continue;
|
|
5137
|
-
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))) {
|
|
5138
|
-
continue;
|
|
5139
|
-
}
|
|
5140
|
-
ranges.push({ start: winStart + tm.index, end: winStart + tm.index + tm[0].length });
|
|
5141
|
-
break;
|
|
5142
|
-
}
|
|
5116
|
+
import { existsSync as existsSync3, readdirSync as readdirSync2, realpathSync } from "fs";
|
|
5117
|
+
import { homedir as homedir2 } from "os";
|
|
5118
|
+
import { join as join3, dirname as dirname3 } from "path";
|
|
5119
|
+
function normalizeHomePath(p) {
|
|
5120
|
+
const expanded = p.startsWith("~") ? join3(homedir2(), p.slice(1)) : p;
|
|
5121
|
+
const trimmed = expanded.replace(/[/\\]+$/, "");
|
|
5122
|
+
try {
|
|
5123
|
+
return realpathSync(trimmed);
|
|
5124
|
+
} catch {
|
|
5125
|
+
return trimmed;
|
|
5143
5126
|
}
|
|
5144
|
-
|
|
5127
|
+
}
|
|
5128
|
+
function legacyAutoSyncedHomes() {
|
|
5129
|
+
const home = homedir2();
|
|
5145
5130
|
const out = [];
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5131
|
+
const add = (dir, marker) => {
|
|
5132
|
+
if (!existsSync3(join3(dir, marker)))
|
|
5133
|
+
return;
|
|
5134
|
+
const n = normalizeHomePath(dir);
|
|
5135
|
+
if (!out.includes(n))
|
|
5136
|
+
out.push(n);
|
|
5137
|
+
};
|
|
5138
|
+
const bases = [
|
|
5139
|
+
{ base: join3(home, ".claude"), marker: "projects" },
|
|
5140
|
+
{ base: join3(home, ".gemini"), marker: "tmp" },
|
|
5141
|
+
{ base: join3(home, ".codex"), marker: "sessions" },
|
|
5142
|
+
{ base: join3(home, ".gemini", "antigravity-cli"), marker: "brain" },
|
|
5143
|
+
{ base: join3(home, ".local", "share", "opencode"), marker: "opencode.db" },
|
|
5144
|
+
{ base: join3(home, ".cursor"), marker: "chats" }
|
|
5145
|
+
];
|
|
5146
|
+
for (const { base: base3, marker } of bases) {
|
|
5147
|
+
add(base3, marker);
|
|
5148
|
+
const parent = dirname3(base3);
|
|
5149
|
+
const leaf = base3.slice(parent.length + 1);
|
|
5150
|
+
try {
|
|
5151
|
+
for (const e of readdirSync2(parent, { withFileTypes: true })) {
|
|
5152
|
+
if (!e.isDirectory())
|
|
5153
|
+
continue;
|
|
5154
|
+
if (e.name === leaf || !e.name.startsWith(leaf + "-"))
|
|
5155
|
+
continue;
|
|
5156
|
+
if (e.name === ".claude-code")
|
|
5157
|
+
continue;
|
|
5158
|
+
add(join3(parent, e.name), marker);
|
|
5159
|
+
}
|
|
5160
|
+
} catch {
|
|
5151
5161
|
}
|
|
5152
|
-
out.push({ ...r });
|
|
5153
5162
|
}
|
|
5154
5163
|
return out;
|
|
5155
5164
|
}
|
|
5156
|
-
function
|
|
5157
|
-
|
|
5158
|
-
if (v === void 0)
|
|
5159
|
-
return null;
|
|
5160
|
-
return v === "1" || v === "true" || v === "yes";
|
|
5161
|
-
}
|
|
5162
|
-
function settingsView() {
|
|
5163
|
-
let mtimeMs = -1;
|
|
5165
|
+
function grandfatherLegacyHomes() {
|
|
5166
|
+
let s;
|
|
5164
5167
|
try {
|
|
5165
|
-
|
|
5168
|
+
s = loadSettings();
|
|
5166
5169
|
} catch {
|
|
5170
|
+
return { seeded: [] };
|
|
5167
5171
|
}
|
|
5168
|
-
if (
|
|
5169
|
-
return
|
|
5170
|
-
|
|
5171
|
-
const
|
|
5172
|
-
|
|
5173
|
-
|
|
5174
|
-
|
|
5175
|
-
|
|
5176
|
-
|
|
5177
|
-
extra.push({ label: r.label, pattern: new RegExp(r.pattern, "g") });
|
|
5178
|
-
} catch {
|
|
5179
|
-
}
|
|
5172
|
+
if (s.sources.homesGrandfathered)
|
|
5173
|
+
return { seeded: [] };
|
|
5174
|
+
const legacy = legacyAutoSyncedHomes();
|
|
5175
|
+
const approved = new Set((s.sources.approvedHomes ?? []).map(normalizeHomePath));
|
|
5176
|
+
const seeded = [];
|
|
5177
|
+
for (const p of legacy) {
|
|
5178
|
+
if (!approved.has(p)) {
|
|
5179
|
+
approved.add(p);
|
|
5180
|
+
seeded.push(p);
|
|
5180
5181
|
}
|
|
5182
|
+
}
|
|
5183
|
+
s.sources.approvedHomes = [...approved];
|
|
5184
|
+
s.sources.homesGrandfathered = true;
|
|
5185
|
+
try {
|
|
5186
|
+
saveSettings(s);
|
|
5181
5187
|
} catch {
|
|
5188
|
+
return { seeded: [] };
|
|
5182
5189
|
}
|
|
5183
|
-
|
|
5184
|
-
return cache;
|
|
5190
|
+
return { seeded };
|
|
5185
5191
|
}
|
|
5186
|
-
function
|
|
5187
|
-
const
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
if (spec.regex.length > MAX_PATTERN_LEN)
|
|
5191
|
-
return { name, reason: `pattern longer than ${MAX_PATTERN_LEN} chars` };
|
|
5192
|
-
let re;
|
|
5192
|
+
function primaryHomes() {
|
|
5193
|
+
const home = homedir2();
|
|
5194
|
+
const env = process.env;
|
|
5195
|
+
let s;
|
|
5193
5196
|
try {
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
return { name, reason: `invalid regex: ${e instanceof Error ? e.message : e}` };
|
|
5197
|
+
s = loadSettings().sources;
|
|
5198
|
+
} catch {
|
|
5199
|
+
s = void 0;
|
|
5198
5200
|
}
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
return "reason" in out ? { ok: false, reason: out.reason } : { ok: true };
|
|
5201
|
+
const opencodeDb = env.CHAT_RECALL_OPENCODE_DB || s?.opencodeDbPath || join3(home, ".local", "share", "opencode", "opencode.db");
|
|
5202
|
+
const candidates2 = [
|
|
5203
|
+
env.CHAT_RECALL_CLAUDE_HOME || s?.claudeHome || join3(home, ".claude"),
|
|
5204
|
+
env.CHAT_RECALL_GEMINI_HOME || s?.geminiHome || join3(home, ".gemini"),
|
|
5205
|
+
env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join3(home, ".codex"),
|
|
5206
|
+
env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
|
|
5207
|
+
env.CHAT_RECALL_CURSOR_HOME || s?.cursorHome || join3(home, ".cursor"),
|
|
5208
|
+
dirOf(opencodeDb)
|
|
5209
|
+
];
|
|
5210
|
+
return candidates2.map(normalizeHomePath);
|
|
5210
5211
|
}
|
|
5211
|
-
function
|
|
5212
|
-
const
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
if ("reason" in out)
|
|
5221
|
-
rejected.push(out);
|
|
5222
|
-
else
|
|
5223
|
-
rules.push(out);
|
|
5212
|
+
function homeDecision(path) {
|
|
5213
|
+
const p = normalizeHomePath(path);
|
|
5214
|
+
if (primaryHomes().includes(p))
|
|
5215
|
+
return "primary";
|
|
5216
|
+
let s;
|
|
5217
|
+
try {
|
|
5218
|
+
s = loadSettings().sources;
|
|
5219
|
+
} catch {
|
|
5220
|
+
return "pending";
|
|
5224
5221
|
}
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
function _clearServerRulePack() {
|
|
5233
|
-
serverPack = null;
|
|
5222
|
+
if ((s.declinedHomes ?? []).map(normalizeHomePath).includes(p))
|
|
5223
|
+
return "declined";
|
|
5224
|
+
if ((s.approvedHomes ?? []).map(normalizeHomePath).includes(p))
|
|
5225
|
+
return "approved";
|
|
5226
|
+
if ((s.extraClaudeHomes ?? []).map(normalizeHomePath).includes(p))
|
|
5227
|
+
return "approved";
|
|
5228
|
+
return "pending";
|
|
5234
5229
|
}
|
|
5235
|
-
function
|
|
5236
|
-
const
|
|
5237
|
-
return
|
|
5238
|
-
}
|
|
5239
|
-
function isRedactionEnabled() {
|
|
5240
|
-
const env = isEnvRedactionRequested();
|
|
5241
|
-
if (env !== null)
|
|
5242
|
-
return env;
|
|
5243
|
-
return settingsView().enabled;
|
|
5244
|
-
}
|
|
5245
|
-
function _resetRedactorCache() {
|
|
5246
|
-
cache = null;
|
|
5247
|
-
}
|
|
5248
|
-
function redactSecrets(text, opts = {}) {
|
|
5249
|
-
if (!opts.force && !isRedactionEnabled())
|
|
5250
|
-
return text;
|
|
5251
|
-
if (!text)
|
|
5252
|
-
return text;
|
|
5253
|
-
const rules = opts.rules || activeRules();
|
|
5254
|
-
let out = text;
|
|
5255
|
-
for (const r of rules) {
|
|
5256
|
-
out = out.replace(r.pattern, (...args) => {
|
|
5257
|
-
const whole = args[0];
|
|
5258
|
-
const m = args.slice(0, args.length);
|
|
5259
|
-
const secret = secretOf(r, m);
|
|
5260
|
-
if (secret == null)
|
|
5261
|
-
return whole;
|
|
5262
|
-
if (opts.count)
|
|
5263
|
-
opts.count.redactions++;
|
|
5264
|
-
return whole.slice(0, whole.length - secret.length) + `[REDACTED:${r.label}]`;
|
|
5265
|
-
});
|
|
5266
|
-
}
|
|
5267
|
-
const ctx = findContextualSecrets(out);
|
|
5268
|
-
for (let i = ctx.length - 1; i >= 0; i--) {
|
|
5269
|
-
const { start, end } = ctx[i];
|
|
5270
|
-
if (opts.count)
|
|
5271
|
-
opts.count.redactions++;
|
|
5272
|
-
out = out.slice(0, start) + "[REDACTED:secret-context]" + out.slice(end);
|
|
5273
|
-
}
|
|
5274
|
-
return out;
|
|
5275
|
-
}
|
|
5276
|
-
function maskSecret(s) {
|
|
5277
|
-
if (!s)
|
|
5278
|
-
return "";
|
|
5279
|
-
if (s.length <= 4)
|
|
5280
|
-
return "*".repeat(s.length);
|
|
5281
|
-
return "*".repeat(Math.min(s.length - 4, 60)) + s.slice(-4);
|
|
5282
|
-
}
|
|
5283
|
-
function globalRegexFor(pattern) {
|
|
5284
|
-
const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
|
|
5285
|
-
const key2 = pattern.source + "\0" + flags;
|
|
5286
|
-
let re = globalRegexCache.get(key2);
|
|
5287
|
-
if (!re) {
|
|
5288
|
-
re = new RegExp(pattern.source, flags);
|
|
5289
|
-
globalRegexCache.set(key2, re);
|
|
5290
|
-
}
|
|
5291
|
-
return re;
|
|
5292
|
-
}
|
|
5293
|
-
function makeLineResolver(text) {
|
|
5294
|
-
const starts = [];
|
|
5295
|
-
for (let i = text.indexOf("\n"); i !== -1; i = text.indexOf("\n", i + 1))
|
|
5296
|
-
starts.push(i);
|
|
5297
|
-
return (index) => {
|
|
5298
|
-
let lo = 0, hi = starts.length;
|
|
5299
|
-
while (lo < hi) {
|
|
5300
|
-
const mid = lo + hi >> 1;
|
|
5301
|
-
if (starts[mid] < index)
|
|
5302
|
-
lo = mid + 1;
|
|
5303
|
-
else
|
|
5304
|
-
hi = mid;
|
|
5305
|
-
}
|
|
5306
|
-
return lo + 1;
|
|
5307
|
-
};
|
|
5308
|
-
}
|
|
5309
|
-
function scanTextForFindings(text, opts = {}) {
|
|
5310
|
-
if (!text)
|
|
5311
|
-
return [];
|
|
5312
|
-
const rules = opts.rules || activeRules();
|
|
5313
|
-
const findings = [];
|
|
5314
|
-
const seenSpans = /* @__PURE__ */ new Set();
|
|
5315
|
-
const lineAt = makeLineResolver(text);
|
|
5316
|
-
for (const r of rules) {
|
|
5317
|
-
const re = globalRegexFor(r.pattern);
|
|
5318
|
-
re.lastIndex = 0;
|
|
5319
|
-
let m;
|
|
5320
|
-
while ((m = re.exec(text)) !== null) {
|
|
5321
|
-
const secret = secretOf(r, m);
|
|
5322
|
-
if (secret == null) {
|
|
5323
|
-
if (re.lastIndex === m.index)
|
|
5324
|
-
re.lastIndex++;
|
|
5325
|
-
continue;
|
|
5326
|
-
}
|
|
5327
|
-
const at = m.index + (m[0].length - secret.length);
|
|
5328
|
-
const span = `${at}:${secret.length}`;
|
|
5329
|
-
if (!seenSpans.has(span)) {
|
|
5330
|
-
seenSpans.add(span);
|
|
5331
|
-
findings.push({ rule: r.label, line: lineAt(at), preview: maskSecret(secret) });
|
|
5332
|
-
}
|
|
5333
|
-
if (re.lastIndex === m.index)
|
|
5334
|
-
re.lastIndex++;
|
|
5335
|
-
}
|
|
5336
|
-
}
|
|
5337
|
-
for (const { start, end } of findContextualSecrets(text)) {
|
|
5338
|
-
const line = lineAt(start);
|
|
5339
|
-
findings.push({ rule: "secret-context", line, preview: maskSecret(text.slice(start, end)) });
|
|
5340
|
-
}
|
|
5341
|
-
return findings;
|
|
5342
|
-
}
|
|
5343
|
-
function privacyView() {
|
|
5344
|
-
let mtimeMs = -1;
|
|
5345
|
-
try {
|
|
5346
|
-
mtimeMs = statSync3(settingsFilePath()).mtimeMs;
|
|
5347
|
-
} catch {
|
|
5348
|
-
}
|
|
5349
|
-
if (privacyCache && privacyCache.mtimeMs === mtimeMs)
|
|
5350
|
-
return privacyCache;
|
|
5351
|
-
let redactToolOutputs = false, redactFilePaths2 = false;
|
|
5352
|
-
try {
|
|
5353
|
-
const s = loadSettings();
|
|
5354
|
-
redactToolOutputs = !!s.privacy?.redactToolOutputs;
|
|
5355
|
-
redactFilePaths2 = !!s.privacy?.redactFilePaths;
|
|
5356
|
-
} catch {
|
|
5357
|
-
}
|
|
5358
|
-
privacyCache = { mtimeMs, redactToolOutputs, redactFilePaths: redactFilePaths2 };
|
|
5359
|
-
return privacyCache;
|
|
5360
|
-
}
|
|
5361
|
-
function _resetPrivacyCache() {
|
|
5362
|
-
privacyCache = null;
|
|
5363
|
-
}
|
|
5364
|
-
function isToolOutputRedactionEnabled() {
|
|
5365
|
-
return privacyView().redactToolOutputs;
|
|
5366
|
-
}
|
|
5367
|
-
function isFilePathRedactionEnabled() {
|
|
5368
|
-
return privacyView().redactFilePaths;
|
|
5369
|
-
}
|
|
5370
|
-
function redactFilePaths(text) {
|
|
5371
|
-
if (!text)
|
|
5372
|
-
return text;
|
|
5373
|
-
return text.replace(PATH_REGEX, (m) => {
|
|
5374
|
-
if (m.startsWith("[REDACTED:"))
|
|
5375
|
-
return m;
|
|
5376
|
-
const h = createHash("sha256").update(m).digest("hex").slice(0, 12);
|
|
5377
|
-
return `[path:${h}]`;
|
|
5378
|
-
});
|
|
5379
|
-
}
|
|
5380
|
-
function applyChunkPrivacy(text) {
|
|
5381
|
-
let out = redactSecrets(text);
|
|
5382
|
-
if (privacyView().redactFilePaths)
|
|
5383
|
-
out = redactFilePaths(out);
|
|
5384
|
-
return out;
|
|
5385
|
-
}
|
|
5386
|
-
function redactToolResultBody(toolName, body) {
|
|
5387
|
-
if (!body)
|
|
5388
|
-
return body;
|
|
5389
|
-
return `[redacted: ${toolName} output, ${body.length} chars]`;
|
|
5390
|
-
}
|
|
5391
|
-
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache, privacyCache, PATH_REGEX;
|
|
5392
|
-
var init_secret_redactor = __esm({
|
|
5393
|
-
"../engine/dist/core/secret-redactor.js"() {
|
|
5394
|
-
"use strict";
|
|
5395
|
-
init_settings();
|
|
5396
|
-
DEFAULT_REDACTION_RULES = [
|
|
5397
|
-
// AWS access tokens. Prefix-anchored: AKIA, ASIA, ABIA (long-term,
|
|
5398
|
-
// STS, EC2). Always exactly 16 hex/alphanumeric after the prefix.
|
|
5399
|
-
// NOTE: this matches only the access-key-ID, NOT the secret key value —
|
|
5400
|
-
// the `env-secret` rule below covers AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN.
|
|
5401
|
-
{ label: "aws-access-token", pattern: /\b(?:AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}\b/g },
|
|
5402
|
-
// AWS STS session tokens. These are long base64 blobs with NO `NAME=` context
|
|
5403
|
-
// when pasted bare into prose/code, so `env-secret` misses them — but they
|
|
5404
|
-
// reliably start with one of a handful of base64 prefixes (the encoded
|
|
5405
|
-
// `{"...` JSON header). Prefix-anchored → low false-positive. This is the
|
|
5406
|
-
// bare-value form that leaked (`search('IQoJEXAMPLEfakeSESSIONtokenNOTreal01234567890abcDEF==...')`).
|
|
5407
|
-
{ label: "aws-session-token", pattern: /\b(?:IQoJ|FwoG|FwoH|FQoG|FQoH|FwoD)[A-Za-z0-9/+]{40,}={0,2}/g },
|
|
5408
|
-
// Env/shell-assignment secrets — a VAR whose name ends in KEY/SECRET/TOKEN/
|
|
5409
|
-
// PASSWORD/CREDENTIAL, then `=`/`:`, then the value. Zero-width lookbehind so
|
|
5410
|
-
// only the VALUE is redacted (the var name stays for context). This is the
|
|
5411
|
-
// dominant real-world leak vector (`export` dumps, .env files, `curl -H`,
|
|
5412
|
-
// tool output) and is exactly what leaked AWS_SECRET_ACCESS_KEY and
|
|
5413
|
-
// AWS_SESSION_TOKEN in cleartext while the access-key-ID rule above caught
|
|
5414
|
-
// only the (least-sensitive) ID.
|
|
5415
|
-
// Suffix list deliberately broad: DB_PASS (our own helm chart's name!),
|
|
5416
|
-
// NPM_AUTH, SENTRY_DSN, SESSION/COOKIE secrets and BEARER vars all leaked
|
|
5417
|
-
// past the original KEY/SECRET/TOKEN/PASSWORD-only list. Values under 12
|
|
5418
|
-
// chars don't redact, so flag-ish vars (BYPASS=true) stay readable.
|
|
5419
|
-
// Context CONSUMED, secret in group 1 — see RedactionRule.secret. As a
|
|
5420
|
-
// lookbehind this was the second most expensive rule in the collector.
|
|
5421
|
-
{ 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 },
|
|
5422
|
-
// Credentials embedded in a connection URL: scheme://user:PASSWORD@host.
|
|
5423
|
-
// Redacts only the password segment (keeps scheme/user/host for context).
|
|
5424
|
-
//
|
|
5425
|
-
// Scheme-agnostic on purpose. The old rule allowlisted eight DB schemes, so
|
|
5426
|
-
// `https://user:pass@host`, `ssh://`, `ftp://`, `smtp://` and every other
|
|
5427
|
-
// userinfo URL walked through in cleartext — and a `jdbc:postgresql://…`
|
|
5428
|
-
// prefix broke the \b anchor for the one family it did cover. Any scheme
|
|
5429
|
-
// followed by userinfo is a credential, so match the shape, not a list.
|
|
5430
|
-
{ label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/]{1,64}:([^@\s/]{1,256})(?=@)/g },
|
|
5431
|
-
// Bare AWS secret-access-key VALUE: EXACTLY 40 base64 chars, word-bounded,
|
|
5432
|
-
// containing upper+lower+digit. This is the gitleaks heuristic — the mixed-case
|
|
5433
|
-
// requirement excludes 40-char lowercase-hex git SHAs, and the exact-40 bound
|
|
5434
|
-
// excludes longer blobs/tokens. It catches the value when it appears bare in
|
|
5435
|
-
// prose with NO `NAME=` and NO nearby context word (e.g. inside a markdown
|
|
5436
|
-
// table or quoted in analysis) — the residual leak path the env-secret and
|
|
5437
|
-
// contextual rules both miss. Placed AFTER env-secret/url-password so the
|
|
5438
|
-
// keyed/URL forms keep their more-specific labels.
|
|
5439
|
-
// The three stacked lookaheads each re-scanned the same 40 characters, which
|
|
5440
|
-
// made this the MOST expensive rule of all 106 the collector runs (13.1% of a
|
|
5441
|
-
// 29.5 MB scan). The mixed-case-plus-digit test is now one JS pass.
|
|
5442
|
-
{
|
|
5443
|
-
label: "aws-secret-key",
|
|
5444
|
-
secret: 1,
|
|
5445
|
-
pattern: /(?<![A-Za-z0-9/+])([A-Za-z0-9/+]{40})(?![A-Za-z0-9/+])/g,
|
|
5446
|
-
where: (v) => /[a-z]/.test(v) && /[A-Z]/.test(v) && /[0-9]/.test(v)
|
|
5447
|
-
},
|
|
5448
|
-
// GitHub personal access tokens.
|
|
5449
|
-
{ label: "github-pat", pattern: /\bghp_[A-Za-z0-9]{36}\b/g },
|
|
5450
|
-
// GitHub fine-grained PATs.
|
|
5451
|
-
{ label: "github-fine", pattern: /\bgithub_pat_[A-Za-z0-9_]{82}\b/g },
|
|
5452
|
-
// GitHub OAuth.
|
|
5453
|
-
{ label: "github-oauth", pattern: /\bgho_[A-Za-z0-9]{36}\b/g },
|
|
5454
|
-
// GitHub app + refresh.
|
|
5455
|
-
{ label: "github-app", pattern: /\b(?:ghs|ghu|ghr)_[A-Za-z0-9]{36}\b/g },
|
|
5456
|
-
// Slack bot/user/app tokens.
|
|
5457
|
-
{ label: "slack-token", pattern: /\bxox[abopr]-[A-Za-z0-9-]{10,}\b/g },
|
|
5458
|
-
// Slack incoming webhook URL.
|
|
5459
|
-
{ label: "slack-webhook", pattern: /\bhttps:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+\b/g },
|
|
5460
|
-
// Stripe live + test keys.
|
|
5461
|
-
{ label: "stripe-key", pattern: /\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g },
|
|
5462
|
-
// Anthropic.
|
|
5463
|
-
{ label: "anthropic-key", pattern: /\bsk-ant-[a-zA-Z0-9_-]{40,}\b/g },
|
|
5464
|
-
// OpenAI. Two shapes, deliberately kept apart. The classic key is
|
|
5465
|
-
// `sk-` + base62 with NO hyphens; the modern scoped keys carry an explicit
|
|
5466
|
-
// proj/svcacct/admin segment first. Allowing hyphens after a bare `sk-`
|
|
5467
|
-
// (which is what admitted sk-proj- in the first place) also matches ordinary
|
|
5468
|
-
// kebab-case text — `sk-fix-the-login-redirect-bug`, `.sk-button-primary`,
|
|
5469
|
-
// `sk-2024-01-01-backup` — and this corpus is full of branch names and CSS
|
|
5470
|
-
// classes. Requiring the segment keeps sk-proj- coverage without that.
|
|
5471
|
-
{ label: "openai-key", pattern: /\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{20,}\b|\bsk-[A-Za-z0-9]{20,}\b/g },
|
|
5472
|
-
// Google API key (AIza…).
|
|
5473
|
-
{ label: "google-api-key", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
5474
|
-
// Generic JWT — three base64url segments.
|
|
5475
|
-
{ label: "jwt", pattern: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g },
|
|
5476
|
-
// Private key blocks (PEM). The label is a free word run rather than a fixed
|
|
5477
|
-
// list, so ENCRYPTED PRIVATE KEY and PGP PRIVATE KEY BLOCK are covered
|
|
5478
|
-
// without another enumeration, and \1 forces END to name the same kind as
|
|
5479
|
-
// BEGIN.
|
|
5480
|
-
//
|
|
5481
|
-
// The body is [^-], NOT [\s\S]*?. That is a performance boundary, not a
|
|
5482
|
-
// style choice. An unanchored prefix with an unbounded lazy gap re-scans to
|
|
5483
|
-
// end-of-input from every candidate start, so text carrying many BEGIN
|
|
5484
|
-
// markers and no matching END costs O(n^2): 500KB of that measured 810ms
|
|
5485
|
-
// here, and this runs synchronously on the server's event loop over
|
|
5486
|
-
// tenant-supplied text (services/secret-rescan.ts). A PEM body is base64
|
|
5487
|
-
// plus headers and contains no '-', so excluding it makes the scan stop at
|
|
5488
|
-
// the next delimiter instead of at EOF — same matches, linear cost.
|
|
5489
|
-
{ label: "private-key", pattern: /-----BEGIN ([A-Z0-9 ]{0,32})PRIVATE KEY(?: BLOCK)?-----[^-]{0,10000}?-----END \1PRIVATE KEY(?: BLOCK)?-----/g },
|
|
5490
|
-
// PuTTY keys are not PEM. Match the Private-Lines payload — the actual key
|
|
5491
|
-
// material — rather than spanning the whole file, which would need the same
|
|
5492
|
-
// unbounded gap the rule above just removed. Line-anchored and base64-only,
|
|
5493
|
-
// so it cannot run away.
|
|
5494
|
-
{ label: "putty-key", pattern: /^Private-Lines:[ \t]*\d{1,4}[\r\n]+(?:[A-Za-z0-9+/=]{8,120}[\r\n]+){1,400}/gm },
|
|
5495
|
-
// npm tokens (uuid-shaped — overlap with our UUID filter; intentional).
|
|
5496
|
-
{ label: "npm-token", pattern: /\bnpm_[A-Za-z0-9]{36}\b/g },
|
|
5497
|
-
// .npmrc auth lines: //registry.npmjs.org/:_authToken=VALUE (the key is not
|
|
5498
|
-
// ALL-CAPS, so the env-secret rule above never matched it). The leading `:`
|
|
5499
|
-
// is required — it is what makes this npmrc syntax rather than any shell var
|
|
5500
|
-
// ending in _AUTH, which env-secret already owns and labels better.
|
|
5501
|
-
// [^\s"'`]+ so the closing quote is not swallowed, and a ${VAR} placeholder
|
|
5502
|
-
// is left alone — redacting it destroys a config example and hides nothing.
|
|
5503
|
-
// The rule the perf profile caught the wedged daemon inside: 98.94% of samples.
|
|
5504
|
-
{ label: "npmrc-auth", secret: 1, pattern: /:_(?:authToken|password|auth)[ \t]*=[ \t]*(?!\$\{)([^\s"'`]{12,})/gi },
|
|
5505
|
-
// HTTP Authorization headers. env-secret requires an ALL-CAPS name, and
|
|
5506
|
-
// `Authorization` is mixed case, so both Bearer and Basic walked straight
|
|
5507
|
-
// through — including short opaque tokens the contextual pass also misses
|
|
5508
|
-
// (it needs 32+ chars AND mixed-case-plus-digit).
|
|
5509
|
-
// Same two guards as npmrc-auth: stop at a quote, and skip the obvious
|
|
5510
|
-
// placeholders that fill documentation (<YOUR_TOKEN>, ${TOKEN}, xxx…).
|
|
5511
|
-
{ label: "auth-header", secret: 1, pattern: /\bauthorization[ \t]*:[ \t]*(?:bearer|basic|token)[ \t]+(?![<$])([^\s"'`<]{8,})/gi },
|
|
5512
|
-
// Vendor tokens with unambiguous prefixes. Each is a fixed literal, so a
|
|
5513
|
-
// false positive is essentially impossible and the cost of listing is low.
|
|
5514
|
-
{ label: "gitlab-pat", pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
|
|
5515
|
-
{ label: "slack-app-token", pattern: /\bxapp-\d-[A-Z0-9]{8,}-\d{10,}-[a-f0-9]{32,}\b/g },
|
|
5516
|
-
{ label: "sendgrid-key", pattern: /\bSG\.[A-Za-z0-9_-]{20,24}\.[A-Za-z0-9_-]{40,50}\b/g },
|
|
5517
|
-
// (?<![-\w]) so `cache-key-<md5>` is not read as a mailgun key.
|
|
5518
|
-
{ label: "mailgun-key", pattern: /(?<![-\w])key-[a-f0-9]{32}\b/g },
|
|
5519
|
-
{ label: "digitalocean-pat", pattern: /\bdop_v1_[a-f0-9]{64}\b/g },
|
|
5520
|
-
{ label: "huggingface-token", pattern: /\bhf_[A-Za-z0-9]{30,}\b/g },
|
|
5521
|
-
{ label: "shopify-token", pattern: /\bshp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}\b/g },
|
|
5522
|
-
{ label: "pypi-token", pattern: /\bpypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}\b/g },
|
|
5523
|
-
// No twilio-sid rule: AC…/SK… are Twilio SIDs, which are public account and
|
|
5524
|
-
// key identifiers, not the auth token. Redacting them hid nothing and
|
|
5525
|
-
// collided with 32-hex etags and MD5 sums.
|
|
5526
|
-
// No discord-bot-token rule either: the shape (word.word.word) matched
|
|
5527
|
-
// ordinary dotted symbols such as a.b.ApplicationContextProviderImpl.
|
|
5528
|
-
{ label: "telegram-bot-token", pattern: /\b\d{8,10}:AA[A-Za-z0-9_-]{32,}\b/g },
|
|
5529
|
-
{ label: "doppler-token", pattern: /\bdp\.(?:pt|st|sa|ct)\.[A-Za-z0-9_-]{20,}\b/g },
|
|
5530
|
-
// Azure Storage SAS signature — the `sig=` parameter is the actual secret.
|
|
5531
|
-
{ label: "azure-sas", secret: 1, pattern: /[?&]sig=([A-Za-z0-9%/+=]{20,})/g }
|
|
5532
|
-
];
|
|
5533
|
-
SECRET_CONTEXT_RE = /\b(?:secret|password|passwd|credential|access[ _-]?key|private[ _-]?key|api[ _-]?key|auth(?:oriz\w*)?|bearer|token)\b/gi;
|
|
5534
|
-
HIGH_ENTROPY_TOKEN_RE = /[A-Za-z0-9/+_-]{32,}/g;
|
|
5535
|
-
cache = null;
|
|
5536
|
-
CANARY = "the quick brown fox jumps over the lazy dog 0123456789 commit 8ba1f109551bd432803012645ac136ddd475d0fb src/index.ts:42";
|
|
5537
|
-
MAX_PACK_RULES = 200;
|
|
5538
|
-
MAX_PATTERN_LEN = 512;
|
|
5539
|
-
serverPack = null;
|
|
5540
|
-
globalRegexCache = /* @__PURE__ */ new Map();
|
|
5541
|
-
privacyCache = null;
|
|
5542
|
-
PATH_REGEX = /(?<![A-Za-z0-9_])(?:\/[^\s'"`<>]+|[A-Za-z]:\\[^\s'"`<>]+)/g;
|
|
5543
|
-
}
|
|
5544
|
-
});
|
|
5545
|
-
|
|
5546
|
-
// ../engine/dist/parsers/chunker.js
|
|
5547
|
-
function stripInjectedBanners(text) {
|
|
5548
|
-
let result = text;
|
|
5549
|
-
for (const re of INJECTED_BANNERS)
|
|
5550
|
-
result = result.replace(re, " ");
|
|
5551
|
-
return result;
|
|
5552
|
-
}
|
|
5553
|
-
function cleanText(text) {
|
|
5554
|
-
let result = text.replace(/<system-reminder>.*?<\/system-reminder>/gs, "");
|
|
5555
|
-
result = stripInjectedBanners(result);
|
|
5556
|
-
result = result.replace(/\x1b\[[0-9;]*m/g, "");
|
|
5557
|
-
result = result.replace(/\s+/g, " ");
|
|
5558
|
-
return result.trim();
|
|
5559
|
-
}
|
|
5560
|
-
function windowText(text, maxChars, maxWindows = 12) {
|
|
5561
|
-
const clean = cleanText(text);
|
|
5562
|
-
if (clean.length <= maxChars)
|
|
5563
|
-
return clean ? [clean] : [];
|
|
5564
|
-
const out = [];
|
|
5565
|
-
const overlap = 80;
|
|
5566
|
-
const step = Math.max(1, maxChars - overlap);
|
|
5567
|
-
for (let i = 0; i < clean.length && out.length < maxWindows; i += step) {
|
|
5568
|
-
out.push(clean.slice(i, i + maxChars));
|
|
5569
|
-
}
|
|
5570
|
-
return out;
|
|
5571
|
-
}
|
|
5572
|
-
function chunkSession(entry, content, maxChunks = 80, maxTokensPerChunk = 500) {
|
|
5573
|
-
const chunks = [];
|
|
5574
|
-
const maxChars = maxTokensPerChunk * 4;
|
|
5575
|
-
const baseData = {
|
|
5576
|
-
sessionId: entry.sessionId,
|
|
5577
|
-
projectPath: entry.projectPath,
|
|
5578
|
-
created: entry.created,
|
|
5579
|
-
modified: entry.modified,
|
|
5580
|
-
mtime: entry.fileMtime,
|
|
5581
|
-
firstPrompt: entry.firstPrompt || content.firstPrompt,
|
|
5582
|
-
sourceFile: content.sessionPath
|
|
5583
|
-
};
|
|
5584
|
-
for (let i = 0; i < Math.min(2, content.summaries.length); i++) {
|
|
5585
|
-
const summary = content.summaries[i];
|
|
5586
|
-
if (!summary?.trim())
|
|
5587
|
-
continue;
|
|
5588
|
-
const chunkText = cleanText(summary.slice(0, maxChars));
|
|
5589
|
-
if (chunkText.length > 8e3) {
|
|
5590
|
-
chunks.push({
|
|
5591
|
-
chunkId: `${entry.sessionId}_summary_${i}`,
|
|
5592
|
-
chunkType: "summary",
|
|
5593
|
-
text: chunkText.slice(0, 8e3),
|
|
5594
|
-
sourceLine: 0,
|
|
5595
|
-
...baseData
|
|
5596
|
-
});
|
|
5597
|
-
} else {
|
|
5598
|
-
chunks.push({
|
|
5599
|
-
chunkId: `${entry.sessionId}_summary_${i}`,
|
|
5600
|
-
chunkType: "summary",
|
|
5601
|
-
text: chunkText,
|
|
5602
|
-
sourceLine: 0,
|
|
5603
|
-
...baseData
|
|
5604
|
-
});
|
|
5605
|
-
}
|
|
5606
|
-
}
|
|
5607
|
-
if (chunks.length >= maxChunks) {
|
|
5608
|
-
return chunks.slice(0, maxChunks);
|
|
5609
|
-
}
|
|
5610
|
-
const firstPrompt = entry.firstPrompt || content.firstPrompt;
|
|
5611
|
-
if (firstPrompt?.trim()) {
|
|
5612
|
-
const firstLine = content.userMessages[0]?.lineNumber || 0;
|
|
5613
|
-
chunks.push({
|
|
5614
|
-
chunkId: `${entry.sessionId}_first_prompt`,
|
|
5615
|
-
chunkType: "first_prompt",
|
|
5616
|
-
text: cleanText(firstPrompt.slice(0, maxChars)),
|
|
5617
|
-
sourceLine: firstLine,
|
|
5618
|
-
...baseData
|
|
5619
|
-
});
|
|
5620
|
-
}
|
|
5621
|
-
if (chunks.length >= maxChunks) {
|
|
5622
|
-
return chunks.slice(0, maxChunks);
|
|
5623
|
-
}
|
|
5624
|
-
const userStart = firstPrompt ? 1 : 0;
|
|
5625
|
-
for (let i = userStart; i < content.userMessages.length; i++) {
|
|
5626
|
-
if (chunks.length >= maxChunks)
|
|
5627
|
-
break;
|
|
5628
|
-
const msg = content.userMessages[i];
|
|
5629
|
-
if (!msg.text.trim())
|
|
5630
|
-
continue;
|
|
5631
|
-
const windows = windowText(msg.text, maxChars);
|
|
5632
|
-
for (let w = 0; w < windows.length; w++) {
|
|
5633
|
-
if (chunks.length >= maxChunks)
|
|
5634
|
-
break;
|
|
5635
|
-
chunks.push({
|
|
5636
|
-
chunkId: `${entry.sessionId}_user_${i}_${w}`,
|
|
5637
|
-
chunkType: "user_context",
|
|
5638
|
-
text: windows[w],
|
|
5639
|
-
sourceLine: msg.lineNumber,
|
|
5640
|
-
...baseData
|
|
5641
|
-
});
|
|
5642
|
-
}
|
|
5643
|
-
}
|
|
5644
|
-
if (chunks.length >= maxChunks) {
|
|
5645
|
-
return chunks.slice(0, maxChunks);
|
|
5646
|
-
}
|
|
5647
|
-
for (let i = 0; i < content.assistantMessages.length; i++) {
|
|
5648
|
-
if (chunks.length >= maxChunks)
|
|
5649
|
-
break;
|
|
5650
|
-
const msg = content.assistantMessages[i];
|
|
5651
|
-
if (!msg.text.trim() || msg.text.length <= 50)
|
|
5652
|
-
continue;
|
|
5653
|
-
const windows = windowText(msg.text, maxChars);
|
|
5654
|
-
for (let w = 0; w < windows.length; w++) {
|
|
5655
|
-
if (chunks.length >= maxChunks)
|
|
5656
|
-
break;
|
|
5657
|
-
chunks.push({
|
|
5658
|
-
chunkId: `${entry.sessionId}_assistant_${i}_${w}`,
|
|
5659
|
-
chunkType: "assistant",
|
|
5660
|
-
text: windows[w],
|
|
5661
|
-
sourceLine: msg.lineNumber,
|
|
5662
|
-
...baseData
|
|
5663
|
-
});
|
|
5664
|
-
}
|
|
5665
|
-
}
|
|
5666
|
-
if (chunks.length >= maxChunks) {
|
|
5667
|
-
return chunks.slice(0, maxChunks);
|
|
5668
|
-
}
|
|
5669
|
-
if (content.toolResults.length > 0) {
|
|
5670
|
-
const webSearches = content.toolResults.filter((r) => r.contentType === "web_search");
|
|
5671
|
-
const otherResults = content.toolResults.filter((r) => r.contentType !== "web_search");
|
|
5672
|
-
const resultsToProcess = [...webSearches.slice(0, 5), ...otherResults.slice(0, 10)];
|
|
5673
|
-
const stripBodies = isToolOutputRedactionEnabled();
|
|
5674
|
-
for (let i = 0; i < resultsToProcess.length; i++) {
|
|
5675
|
-
if (chunks.length >= maxChunks)
|
|
5676
|
-
break;
|
|
5677
|
-
const result = resultsToProcess[i];
|
|
5678
|
-
if (result.text.trim()) {
|
|
5679
|
-
const body = stripBodies && result.contentType !== "web_search" ? redactToolResultBody(result.contentType, result.text) : result.text.slice(0, maxChars);
|
|
5680
|
-
chunks.push({
|
|
5681
|
-
chunkId: `${entry.sessionId}_${result.contentType}_${i}`,
|
|
5682
|
-
chunkType: result.contentType,
|
|
5683
|
-
text: cleanText(body),
|
|
5684
|
-
sourceLine: result.lineNumber,
|
|
5685
|
-
...baseData
|
|
5686
|
-
});
|
|
5687
|
-
}
|
|
5688
|
-
}
|
|
5689
|
-
}
|
|
5690
|
-
return chunks.slice(0, maxChunks);
|
|
5691
|
-
}
|
|
5692
|
-
var INJECTED_BANNERS;
|
|
5693
|
-
var init_chunker = __esm({
|
|
5694
|
-
"../engine/dist/parsers/chunker.js"() {
|
|
5695
|
-
"use strict";
|
|
5696
|
-
init_secret_redactor();
|
|
5697
|
-
INJECTED_BANNERS = [
|
|
5698
|
-
/MCP issues detected\. ?Run \/mcp list for status\.?/g,
|
|
5699
|
-
/Context low[^\n]*Run \/compact[^\n]*/g,
|
|
5700
|
-
/API Error:[^\n]{0,120}/g
|
|
5701
|
-
];
|
|
5702
|
-
}
|
|
5703
|
-
});
|
|
5704
|
-
|
|
5705
|
-
// ../engine/dist/core/home-approval.js
|
|
5706
|
-
var home_approval_exports = {};
|
|
5707
|
-
__export(home_approval_exports, {
|
|
5708
|
-
approveHome: () => approveHome,
|
|
5709
|
-
declineHome: () => declineHome,
|
|
5710
|
-
grandfatherLegacyHomes: () => grandfatherLegacyHomes,
|
|
5711
|
-
homeDecision: () => homeDecision,
|
|
5712
|
-
isHomeSynced: () => isHomeSynced,
|
|
5713
|
-
normalizeHomePath: () => normalizeHomePath,
|
|
5714
|
-
resetHomeDecision: () => resetHomeDecision
|
|
5715
|
-
});
|
|
5716
|
-
import { existsSync as existsSync3, readdirSync as readdirSync2, realpathSync } from "fs";
|
|
5717
|
-
import { homedir as homedir2 } from "os";
|
|
5718
|
-
import { join as join3, dirname as dirname3 } from "path";
|
|
5719
|
-
function normalizeHomePath(p) {
|
|
5720
|
-
const expanded = p.startsWith("~") ? join3(homedir2(), p.slice(1)) : p;
|
|
5721
|
-
const trimmed = expanded.replace(/[/\\]+$/, "");
|
|
5722
|
-
try {
|
|
5723
|
-
return realpathSync(trimmed);
|
|
5724
|
-
} catch {
|
|
5725
|
-
return trimmed;
|
|
5726
|
-
}
|
|
5727
|
-
}
|
|
5728
|
-
function legacyAutoSyncedHomes() {
|
|
5729
|
-
const home = homedir2();
|
|
5730
|
-
const out = [];
|
|
5731
|
-
const add = (dir, marker) => {
|
|
5732
|
-
if (!existsSync3(join3(dir, marker)))
|
|
5733
|
-
return;
|
|
5734
|
-
const n = normalizeHomePath(dir);
|
|
5735
|
-
if (!out.includes(n))
|
|
5736
|
-
out.push(n);
|
|
5737
|
-
};
|
|
5738
|
-
const bases = [
|
|
5739
|
-
{ base: join3(home, ".claude"), marker: "projects" },
|
|
5740
|
-
{ base: join3(home, ".gemini"), marker: "tmp" },
|
|
5741
|
-
{ base: join3(home, ".codex"), marker: "sessions" },
|
|
5742
|
-
{ base: join3(home, ".gemini", "antigravity-cli"), marker: "brain" },
|
|
5743
|
-
{ base: join3(home, ".local", "share", "opencode"), marker: "opencode.db" },
|
|
5744
|
-
{ base: join3(home, ".cursor"), marker: "chats" }
|
|
5745
|
-
];
|
|
5746
|
-
for (const { base: base3, marker } of bases) {
|
|
5747
|
-
add(base3, marker);
|
|
5748
|
-
const parent = dirname3(base3);
|
|
5749
|
-
const leaf = base3.slice(parent.length + 1);
|
|
5750
|
-
try {
|
|
5751
|
-
for (const e of readdirSync2(parent, { withFileTypes: true })) {
|
|
5752
|
-
if (!e.isDirectory())
|
|
5753
|
-
continue;
|
|
5754
|
-
if (e.name === leaf || !e.name.startsWith(leaf + "-"))
|
|
5755
|
-
continue;
|
|
5756
|
-
if (e.name === ".claude-code")
|
|
5757
|
-
continue;
|
|
5758
|
-
add(join3(parent, e.name), marker);
|
|
5759
|
-
}
|
|
5760
|
-
} catch {
|
|
5761
|
-
}
|
|
5762
|
-
}
|
|
5763
|
-
return out;
|
|
5764
|
-
}
|
|
5765
|
-
function grandfatherLegacyHomes() {
|
|
5766
|
-
let s;
|
|
5767
|
-
try {
|
|
5768
|
-
s = loadSettings();
|
|
5769
|
-
} catch {
|
|
5770
|
-
return { seeded: [] };
|
|
5771
|
-
}
|
|
5772
|
-
if (s.sources.homesGrandfathered)
|
|
5773
|
-
return { seeded: [] };
|
|
5774
|
-
const legacy = legacyAutoSyncedHomes();
|
|
5775
|
-
const approved = new Set((s.sources.approvedHomes ?? []).map(normalizeHomePath));
|
|
5776
|
-
const seeded = [];
|
|
5777
|
-
for (const p of legacy) {
|
|
5778
|
-
if (!approved.has(p)) {
|
|
5779
|
-
approved.add(p);
|
|
5780
|
-
seeded.push(p);
|
|
5781
|
-
}
|
|
5782
|
-
}
|
|
5783
|
-
s.sources.approvedHomes = [...approved];
|
|
5784
|
-
s.sources.homesGrandfathered = true;
|
|
5785
|
-
try {
|
|
5786
|
-
saveSettings(s);
|
|
5787
|
-
} catch {
|
|
5788
|
-
return { seeded: [] };
|
|
5789
|
-
}
|
|
5790
|
-
return { seeded };
|
|
5791
|
-
}
|
|
5792
|
-
function primaryHomes() {
|
|
5793
|
-
const home = homedir2();
|
|
5794
|
-
const env = process.env;
|
|
5795
|
-
let s;
|
|
5796
|
-
try {
|
|
5797
|
-
s = loadSettings().sources;
|
|
5798
|
-
} catch {
|
|
5799
|
-
s = void 0;
|
|
5800
|
-
}
|
|
5801
|
-
const opencodeDb = env.CHAT_RECALL_OPENCODE_DB || s?.opencodeDbPath || join3(home, ".local", "share", "opencode", "opencode.db");
|
|
5802
|
-
const candidates2 = [
|
|
5803
|
-
env.CHAT_RECALL_CLAUDE_HOME || s?.claudeHome || join3(home, ".claude"),
|
|
5804
|
-
env.CHAT_RECALL_GEMINI_HOME || s?.geminiHome || join3(home, ".gemini"),
|
|
5805
|
-
env.CHAT_RECALL_CODEX_HOME || s?.codexHome || join3(home, ".codex"),
|
|
5806
|
-
env.CHAT_RECALL_AGY_HOME || s?.agyHome || join3(home, ".gemini", "antigravity-cli"),
|
|
5807
|
-
env.CHAT_RECALL_CURSOR_HOME || s?.cursorHome || join3(home, ".cursor"),
|
|
5808
|
-
dirOf(opencodeDb)
|
|
5809
|
-
];
|
|
5810
|
-
return candidates2.map(normalizeHomePath);
|
|
5811
|
-
}
|
|
5812
|
-
function homeDecision(path) {
|
|
5813
|
-
const p = normalizeHomePath(path);
|
|
5814
|
-
if (primaryHomes().includes(p))
|
|
5815
|
-
return "primary";
|
|
5816
|
-
let s;
|
|
5817
|
-
try {
|
|
5818
|
-
s = loadSettings().sources;
|
|
5819
|
-
} catch {
|
|
5820
|
-
return "pending";
|
|
5821
|
-
}
|
|
5822
|
-
if ((s.declinedHomes ?? []).map(normalizeHomePath).includes(p))
|
|
5823
|
-
return "declined";
|
|
5824
|
-
if ((s.approvedHomes ?? []).map(normalizeHomePath).includes(p))
|
|
5825
|
-
return "approved";
|
|
5826
|
-
if ((s.extraClaudeHomes ?? []).map(normalizeHomePath).includes(p))
|
|
5827
|
-
return "approved";
|
|
5828
|
-
return "pending";
|
|
5829
|
-
}
|
|
5830
|
-
function isHomeSynced(path) {
|
|
5831
|
-
const d = homeDecision(path);
|
|
5832
|
-
return d === "primary" || d === "approved";
|
|
5230
|
+
function isHomeSynced(path) {
|
|
5231
|
+
const d = homeDecision(path);
|
|
5232
|
+
return d === "primary" || d === "approved";
|
|
5833
5233
|
}
|
|
5834
5234
|
function setDecision(path, decision) {
|
|
5835
5235
|
const p = normalizeHomePath(path);
|
|
@@ -6287,7 +5687,7 @@ var init_model_pricing = __esm({
|
|
|
6287
5687
|
});
|
|
6288
5688
|
|
|
6289
5689
|
// ../engine/dist/parsers/session.js
|
|
6290
|
-
import { createReadStream, existsSync as existsSync5, readdirSync as readdirSync5, readFileSync as readFileSync2, statSync as
|
|
5690
|
+
import { createReadStream, existsSync as existsSync5, readdirSync as readdirSync5, readFileSync as readFileSync2, statSync as statSync3, openSync, readSync, closeSync } from "fs";
|
|
6291
5691
|
import { createInterface } from "readline";
|
|
6292
5692
|
import { join as join5, basename as basename2 } from "path";
|
|
6293
5693
|
function removeCodeBlocks(text) {
|
|
@@ -6334,44 +5734,6 @@ function isValuableToolResult(content, toolName = "") {
|
|
|
6334
5734
|
}
|
|
6335
5735
|
return true;
|
|
6336
5736
|
}
|
|
6337
|
-
function parseSessionsIndex(indexPath) {
|
|
6338
|
-
if (!existsSync5(indexPath)) {
|
|
6339
|
-
return [];
|
|
6340
|
-
}
|
|
6341
|
-
const data = JSON.parse(readFileSync2(indexPath, "utf-8"));
|
|
6342
|
-
const entries = data.entries || [];
|
|
6343
|
-
return entries.map((e) => ({
|
|
6344
|
-
sessionId: e.sessionId || "",
|
|
6345
|
-
fullPath: e.fullPath || "",
|
|
6346
|
-
fileMtime: e.fileMtime || 0,
|
|
6347
|
-
firstPrompt: e.firstPrompt || "",
|
|
6348
|
-
messageCount: e.messageCount || 0,
|
|
6349
|
-
created: e.created || "",
|
|
6350
|
-
modified: e.modified || "",
|
|
6351
|
-
gitBranch: e.gitBranch || "",
|
|
6352
|
-
projectPath: e.projectPath || "",
|
|
6353
|
-
isSidechain: e.isSidechain || false
|
|
6354
|
-
}));
|
|
6355
|
-
}
|
|
6356
|
-
function* iterAllSessionIndices(claudeDir) {
|
|
6357
|
-
const dir = claudeDir || claudeBackend.projectsDir();
|
|
6358
|
-
if (!existsSync5(dir)) {
|
|
6359
|
-
return;
|
|
6360
|
-
}
|
|
6361
|
-
const entries = readdirSync5(dir, { withFileTypes: true });
|
|
6362
|
-
for (const entry of entries) {
|
|
6363
|
-
if (!entry.isDirectory())
|
|
6364
|
-
continue;
|
|
6365
|
-
const projectDir = join5(dir, entry.name);
|
|
6366
|
-
const indexPath = join5(projectDir, "sessions-index.json");
|
|
6367
|
-
if (existsSync5(indexPath)) {
|
|
6368
|
-
const sessions = parseSessionsIndex(indexPath);
|
|
6369
|
-
if (sessions.length > 0) {
|
|
6370
|
-
yield [projectDir, sessions];
|
|
6371
|
-
}
|
|
6372
|
-
}
|
|
6373
|
-
}
|
|
6374
|
-
}
|
|
6375
5737
|
function hasSubagentsDir(sessionPath) {
|
|
6376
5738
|
const dir = sessionPath.slice(0, -6);
|
|
6377
5739
|
return existsSync5(join5(dir, "subagents"));
|
|
@@ -6382,40 +5744,6 @@ function getSubagentPaths(sessionPath) {
|
|
|
6382
5744
|
return [];
|
|
6383
5745
|
return readdirSync5(subagentsDir).filter((f) => f.endsWith(".jsonl")).sort().map((f) => join5(subagentsDir, f));
|
|
6384
5746
|
}
|
|
6385
|
-
function getSubagentProjectPath(sessionPath, folderDerivedPath) {
|
|
6386
|
-
const subagentPaths = getSubagentPaths(sessionPath);
|
|
6387
|
-
if (subagentPaths.length === 0)
|
|
6388
|
-
return folderDerivedPath;
|
|
6389
|
-
const cwdCounts = /* @__PURE__ */ new Map();
|
|
6390
|
-
for (const filePath of subagentPaths) {
|
|
6391
|
-
try {
|
|
6392
|
-
const lines = readFileSync2(filePath, "utf-8").split("\n");
|
|
6393
|
-
for (const line of lines) {
|
|
6394
|
-
if (!line.trim())
|
|
6395
|
-
continue;
|
|
6396
|
-
try {
|
|
6397
|
-
const entry = JSON.parse(line);
|
|
6398
|
-
if (entry.type === "user" && typeof entry.cwd === "string" && entry.cwd) {
|
|
6399
|
-
cwdCounts.set(entry.cwd, (cwdCounts.get(entry.cwd) ?? 0) + 1);
|
|
6400
|
-
}
|
|
6401
|
-
} catch {
|
|
6402
|
-
}
|
|
6403
|
-
}
|
|
6404
|
-
} catch {
|
|
6405
|
-
}
|
|
6406
|
-
}
|
|
6407
|
-
if (cwdCounts.size === 0)
|
|
6408
|
-
return folderDerivedPath;
|
|
6409
|
-
let best = folderDerivedPath;
|
|
6410
|
-
let bestCount = 0;
|
|
6411
|
-
for (const [cwd, count] of cwdCounts) {
|
|
6412
|
-
if (count > bestCount) {
|
|
6413
|
-
best = cwd;
|
|
6414
|
-
bestCount = count;
|
|
6415
|
-
}
|
|
6416
|
-
}
|
|
6417
|
-
return best;
|
|
6418
|
-
}
|
|
6419
5747
|
function readCwdFromJsonl(sessionPath) {
|
|
6420
5748
|
try {
|
|
6421
5749
|
if (!existsSync5(sessionPath))
|
|
@@ -6444,22 +5772,6 @@ function readCwdFromJsonl(sessionPath) {
|
|
|
6444
5772
|
}
|
|
6445
5773
|
return "";
|
|
6446
5774
|
}
|
|
6447
|
-
function getSessionMtime(sessionPath) {
|
|
6448
|
-
const subagentPaths = getSubagentPaths(sessionPath);
|
|
6449
|
-
if (subagentPaths.length === 0) {
|
|
6450
|
-
return statSync4(sessionPath).mtimeMs;
|
|
6451
|
-
}
|
|
6452
|
-
let maxMtime = statSync4(sessionPath).mtimeMs;
|
|
6453
|
-
for (const p of subagentPaths) {
|
|
6454
|
-
try {
|
|
6455
|
-
const m = statSync4(p).mtimeMs;
|
|
6456
|
-
if (m > maxMtime)
|
|
6457
|
-
maxMtime = m;
|
|
6458
|
-
} catch {
|
|
6459
|
-
}
|
|
6460
|
-
}
|
|
6461
|
-
return maxMtime;
|
|
6462
|
-
}
|
|
6463
5775
|
async function parseSessionFile(sessionPath, maxMessages = 50) {
|
|
6464
5776
|
const sessionId = basename2(sessionPath, ".jsonl");
|
|
6465
5777
|
const content = {
|
|
@@ -6675,98 +5987,32 @@ ${resultText}` : resultText;
|
|
|
6675
5987
|
content.toolResults.push({
|
|
6676
5988
|
text: searchText.slice(0, 2e3),
|
|
6677
5989
|
lineNumber: lineNum,
|
|
6678
|
-
contentType: "web_search"
|
|
6679
|
-
});
|
|
6680
|
-
toolCount++;
|
|
6681
|
-
}
|
|
6682
|
-
}
|
|
6683
|
-
} catch {
|
|
6684
|
-
continue;
|
|
6685
|
-
}
|
|
6686
|
-
}
|
|
6687
|
-
}
|
|
6688
|
-
content.metadata.toolsUsed = [...content.toolsUsed];
|
|
6689
|
-
content.metadata.modelsUsed = [...modelsUsed];
|
|
6690
|
-
content.metadata.filesModified = [...filesModified];
|
|
6691
|
-
content.metadata.messageCount = content.userMessages.length + content.assistantMessages.length;
|
|
6692
|
-
content.metadata.costUsd = estimateCostUsd(content.metadata.modelsUsed, {
|
|
6693
|
-
inputTokens: content.metadata.inputTokens,
|
|
6694
|
-
outputTokens: content.metadata.outputTokens,
|
|
6695
|
-
cacheReadTokens: content.metadata.cacheReadTokens,
|
|
6696
|
-
cacheCreationTokens: content.metadata.cacheCreationTokens
|
|
6697
|
-
});
|
|
6698
|
-
return content;
|
|
6699
|
-
}
|
|
6700
|
-
function* getAllSessions(claudeDir) {
|
|
6701
|
-
const seenSessionIds = /* @__PURE__ */ new Set();
|
|
6702
|
-
const projectDirs = claudeDir ? [claudeDir] : claudeProjectDirs();
|
|
6703
|
-
for (const dir of projectDirs) {
|
|
6704
|
-
for (const [, entries] of iterAllSessionIndices(dir)) {
|
|
6705
|
-
for (const entry of entries) {
|
|
6706
|
-
if (!seenSessionIds.has(entry.sessionId) && existsSync5(entry.fullPath)) {
|
|
6707
|
-
seenSessionIds.add(entry.sessionId);
|
|
6708
|
-
yield [entry, entry.fullPath];
|
|
6709
|
-
}
|
|
6710
|
-
}
|
|
6711
|
-
}
|
|
6712
|
-
if (!existsSync5(dir))
|
|
6713
|
-
continue;
|
|
6714
|
-
const dirEntries = readdirSync5(dir, { withFileTypes: true });
|
|
6715
|
-
for (const projDirEntry of dirEntries) {
|
|
6716
|
-
if (!projDirEntry.isDirectory())
|
|
6717
|
-
continue;
|
|
6718
|
-
const projectPath = join5(dir, projDirEntry.name);
|
|
6719
|
-
const files = readdirSync5(projectPath);
|
|
6720
|
-
for (const file of files) {
|
|
6721
|
-
if (!file.endsWith(".jsonl"))
|
|
6722
|
-
continue;
|
|
6723
|
-
if (file.startsWith("agent-"))
|
|
6724
|
-
continue;
|
|
6725
|
-
if (file === "sessions-index.json")
|
|
6726
|
-
continue;
|
|
6727
|
-
const sessionId = basename2(file, ".jsonl");
|
|
6728
|
-
if (seenSessionIds.has(sessionId))
|
|
6729
|
-
continue;
|
|
6730
|
-
const fullPath = join5(projectPath, file);
|
|
6731
|
-
try {
|
|
6732
|
-
const stat3 = statSync4(fullPath);
|
|
6733
|
-
const derivedProjectPath = resolveProjectDirName(projDirEntry.name);
|
|
6734
|
-
const effectiveMtime = getSessionMtime(fullPath);
|
|
6735
|
-
let projectPath2 = "";
|
|
6736
|
-
if (hasSubagentsDir(fullPath)) {
|
|
6737
|
-
projectPath2 = getSubagentProjectPath(fullPath, derivedProjectPath);
|
|
6738
|
-
} else {
|
|
6739
|
-
const fromJsonl = readCwdFromJsonl(fullPath);
|
|
6740
|
-
if (fromJsonl)
|
|
6741
|
-
projectPath2 = fromJsonl;
|
|
5990
|
+
contentType: "web_search"
|
|
5991
|
+
});
|
|
5992
|
+
toolCount++;
|
|
6742
5993
|
}
|
|
6743
|
-
if (!projectPath2)
|
|
6744
|
-
projectPath2 = derivedProjectPath;
|
|
6745
|
-
const entry = {
|
|
6746
|
-
sessionId,
|
|
6747
|
-
fullPath,
|
|
6748
|
-
fileMtime: effectiveMtime,
|
|
6749
|
-
firstPrompt: "",
|
|
6750
|
-
messageCount: 0,
|
|
6751
|
-
created: stat3.birthtime.toISOString(),
|
|
6752
|
-
modified: new Date(effectiveMtime).toISOString(),
|
|
6753
|
-
gitBranch: "",
|
|
6754
|
-
projectPath: projectPath2,
|
|
6755
|
-
isSidechain: false
|
|
6756
|
-
};
|
|
6757
|
-
seenSessionIds.add(sessionId);
|
|
6758
|
-
yield [entry, fullPath];
|
|
6759
|
-
} catch {
|
|
6760
|
-
continue;
|
|
6761
5994
|
}
|
|
5995
|
+
} catch {
|
|
5996
|
+
continue;
|
|
6762
5997
|
}
|
|
6763
5998
|
}
|
|
6764
5999
|
}
|
|
6000
|
+
content.metadata.toolsUsed = [...content.toolsUsed];
|
|
6001
|
+
content.metadata.modelsUsed = [...modelsUsed];
|
|
6002
|
+
content.metadata.filesModified = [...filesModified];
|
|
6003
|
+
content.metadata.messageCount = content.userMessages.length + content.assistantMessages.length;
|
|
6004
|
+
content.metadata.costUsd = estimateCostUsd(content.metadata.modelsUsed, {
|
|
6005
|
+
inputTokens: content.metadata.inputTokens,
|
|
6006
|
+
outputTokens: content.metadata.outputTokens,
|
|
6007
|
+
cacheReadTokens: content.metadata.cacheReadTokens,
|
|
6008
|
+
cacheCreationTokens: content.metadata.cacheCreationTokens
|
|
6009
|
+
});
|
|
6010
|
+
return content;
|
|
6765
6011
|
}
|
|
6766
6012
|
var init_session = __esm({
|
|
6767
6013
|
"../engine/dist/parsers/session.js"() {
|
|
6768
6014
|
"use strict";
|
|
6769
|
-
|
|
6015
|
+
init_banners();
|
|
6770
6016
|
init_claude2();
|
|
6771
6017
|
init_tool_paths();
|
|
6772
6018
|
init_project_dir_name();
|
|
@@ -7287,7 +6533,7 @@ __export(raw_exports, {
|
|
|
7287
6533
|
parseTranscriptFromContainer: () => parseTranscriptFromContainer
|
|
7288
6534
|
});
|
|
7289
6535
|
import { gzipSync, gunzipSync } from "zlib";
|
|
7290
|
-
import { createHash
|
|
6536
|
+
import { createHash } from "crypto";
|
|
7291
6537
|
import * as fsMod from "fs";
|
|
7292
6538
|
import * as pathMod from "path";
|
|
7293
6539
|
function buildRawContainer(exp) {
|
|
@@ -7299,7 +6545,7 @@ function buildRawContainer(exp) {
|
|
|
7299
6545
|
};
|
|
7300
6546
|
}
|
|
7301
6547
|
function containerSrcHash(c) {
|
|
7302
|
-
const h =
|
|
6548
|
+
const h = createHash("sha1");
|
|
7303
6549
|
h.update(c.tool);
|
|
7304
6550
|
for (const f of c.files) {
|
|
7305
6551
|
h.update("\0");
|
|
@@ -8846,11 +8092,11 @@ var init_opencode = __esm({
|
|
|
8846
8092
|
});
|
|
8847
8093
|
|
|
8848
8094
|
// ../engine/dist/core/backends/tail-read.js
|
|
8849
|
-
import { openSync as openSync2, readSync as readSync2, closeSync as closeSync2, statSync as
|
|
8095
|
+
import { openSync as openSync2, readSync as readSync2, closeSync as closeSync2, statSync as statSync4 } from "node:fs";
|
|
8850
8096
|
function readTailFromOffset(path, offset) {
|
|
8851
8097
|
let size = 0;
|
|
8852
8098
|
try {
|
|
8853
|
-
size =
|
|
8099
|
+
size = statSync4(path).size;
|
|
8854
8100
|
} catch {
|
|
8855
8101
|
return { text: "", newOffset: offset };
|
|
8856
8102
|
}
|
|
@@ -8895,7 +8141,7 @@ var init_tail_read = __esm({
|
|
|
8895
8141
|
});
|
|
8896
8142
|
|
|
8897
8143
|
// ../engine/dist/core/backends/codex.js
|
|
8898
|
-
import { readdirSync as readdirSync6, readFileSync as readFileSync3, statSync as
|
|
8144
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync3, statSync as statSync5, openSync as openSync3, readSync as readSync3, closeSync as closeSync3 } from "fs";
|
|
8899
8145
|
import { basename as basename7, dirname as dirname9, join as join9 } from "path";
|
|
8900
8146
|
function parseShellWrites(cmd) {
|
|
8901
8147
|
const out = [];
|
|
@@ -9103,7 +8349,7 @@ var init_codex2 = __esm({
|
|
|
9103
8349
|
return null;
|
|
9104
8350
|
let mtime = 0;
|
|
9105
8351
|
try {
|
|
9106
|
-
mtime =
|
|
8352
|
+
mtime = statSync5(located.path).mtimeMs;
|
|
9107
8353
|
} catch {
|
|
9108
8354
|
}
|
|
9109
8355
|
return {
|
|
@@ -9123,7 +8369,7 @@ var init_codex2 = __esm({
|
|
|
9123
8369
|
for (const filePath of walkRollouts(root)) {
|
|
9124
8370
|
let stat3;
|
|
9125
8371
|
try {
|
|
9126
|
-
stat3 =
|
|
8372
|
+
stat3 = statSync5(filePath);
|
|
9127
8373
|
} catch {
|
|
9128
8374
|
continue;
|
|
9129
8375
|
}
|
|
@@ -9319,7 +8565,7 @@ var init_codex2 = __esm({
|
|
|
9319
8565
|
let mtime = 0;
|
|
9320
8566
|
try {
|
|
9321
8567
|
raw = readFileSync3(path, "utf-8");
|
|
9322
|
-
mtime =
|
|
8568
|
+
mtime = statSync5(path).mtimeMs;
|
|
9323
8569
|
} catch {
|
|
9324
8570
|
return [];
|
|
9325
8571
|
}
|
|
@@ -9419,7 +8665,7 @@ var init_codex2 = __esm({
|
|
|
9419
8665
|
const events = this.readEvents(this.toRawId(id));
|
|
9420
8666
|
let fileMtime = 0;
|
|
9421
8667
|
try {
|
|
9422
|
-
fileMtime =
|
|
8668
|
+
fileMtime = statSync5(located.path).mtimeMs;
|
|
9423
8669
|
} catch {
|
|
9424
8670
|
}
|
|
9425
8671
|
return liveScanEditsFromEvents(events, this.fileToolMap, {
|
|
@@ -9483,7 +8729,7 @@ var init_codex2 = __esm({
|
|
|
9483
8729
|
const p = join9(dir, entry.name);
|
|
9484
8730
|
let st;
|
|
9485
8731
|
try {
|
|
9486
|
-
st =
|
|
8732
|
+
st = statSync5(p);
|
|
9487
8733
|
} catch {
|
|
9488
8734
|
continue;
|
|
9489
8735
|
}
|
|
@@ -9550,7 +8796,7 @@ var init_codex2 = __esm({
|
|
|
9550
8796
|
let mtime = 0;
|
|
9551
8797
|
const push = (path, name) => {
|
|
9552
8798
|
try {
|
|
9553
|
-
const st =
|
|
8799
|
+
const st = statSync5(path);
|
|
9554
8800
|
files.push({ name, bytes: readFileSync3(path) });
|
|
9555
8801
|
if (st.mtimeMs > mtime)
|
|
9556
8802
|
mtime = st.mtimeMs;
|
|
@@ -9592,7 +8838,7 @@ var init_codex2 = __esm({
|
|
|
9592
8838
|
if (!loc)
|
|
9593
8839
|
return 0;
|
|
9594
8840
|
try {
|
|
9595
|
-
return
|
|
8841
|
+
return statSync5(loc.path).size;
|
|
9596
8842
|
} catch {
|
|
9597
8843
|
return 0;
|
|
9598
8844
|
}
|
|
@@ -9609,7 +8855,7 @@ var init_codex2 = __esm({
|
|
|
9609
8855
|
});
|
|
9610
8856
|
|
|
9611
8857
|
// ../engine/dist/core/backends/agy.js
|
|
9612
|
-
import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync4, statSync as
|
|
8858
|
+
import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync4, statSync as statSync6 } from "fs";
|
|
9613
8859
|
import { basename as basename8, dirname as dirname10, join as join10 } from "path";
|
|
9614
8860
|
function agyTranscriptPath(logsDir) {
|
|
9615
8861
|
const full = join10(logsDir, "transcript_full.jsonl");
|
|
@@ -9802,7 +9048,7 @@ var init_agy = __esm({
|
|
|
9802
9048
|
return null;
|
|
9803
9049
|
let mtime = 0;
|
|
9804
9050
|
try {
|
|
9805
|
-
mtime =
|
|
9051
|
+
mtime = statSync6(path).mtimeMs;
|
|
9806
9052
|
} catch {
|
|
9807
9053
|
}
|
|
9808
9054
|
const projectPath = resolveAgyProject(dirname10(path), this.homeDir());
|
|
@@ -9830,7 +9076,7 @@ var init_agy = __esm({
|
|
|
9830
9076
|
for (const rawId of sessionDirs) {
|
|
9831
9077
|
const sessionPath = join10(brainDir, rawId);
|
|
9832
9078
|
try {
|
|
9833
|
-
if (!
|
|
9079
|
+
if (!statSync6(sessionPath).isDirectory())
|
|
9834
9080
|
continue;
|
|
9835
9081
|
} catch {
|
|
9836
9082
|
continue;
|
|
@@ -9840,7 +9086,7 @@ var init_agy = __esm({
|
|
|
9840
9086
|
continue;
|
|
9841
9087
|
let stat3;
|
|
9842
9088
|
try {
|
|
9843
|
-
stat3 =
|
|
9089
|
+
stat3 = statSync6(filePath);
|
|
9844
9090
|
} catch {
|
|
9845
9091
|
continue;
|
|
9846
9092
|
}
|
|
@@ -10105,7 +9351,7 @@ var init_agy = __esm({
|
|
|
10105
9351
|
for (const rawId of sessionDirs) {
|
|
10106
9352
|
const sessionPath = join10(brainDir, rawId);
|
|
10107
9353
|
try {
|
|
10108
|
-
if (!
|
|
9354
|
+
if (!statSync6(sessionPath).isDirectory())
|
|
10109
9355
|
continue;
|
|
10110
9356
|
} catch {
|
|
10111
9357
|
continue;
|
|
@@ -10114,7 +9360,7 @@ var init_agy = __esm({
|
|
|
10114
9360
|
if (!filePath)
|
|
10115
9361
|
continue;
|
|
10116
9362
|
try {
|
|
10117
|
-
const st =
|
|
9363
|
+
const st = statSync6(filePath);
|
|
10118
9364
|
if (st.mtimeMs < opts.sinceMs)
|
|
10119
9365
|
continue;
|
|
10120
9366
|
candidates2.push({ rawId, mtime: st.mtimeMs });
|
|
@@ -10142,7 +9388,7 @@ var init_agy = __esm({
|
|
|
10142
9388
|
try {
|
|
10143
9389
|
return {
|
|
10144
9390
|
tool: "agy",
|
|
10145
|
-
mtime:
|
|
9391
|
+
mtime: statSync6(loc.path).mtimeMs,
|
|
10146
9392
|
files: [{ name: basename8(loc.path), bytes: readFileSync4(loc.path) }]
|
|
10147
9393
|
};
|
|
10148
9394
|
} catch {
|
|
@@ -10157,7 +9403,7 @@ var init_agy = __esm({
|
|
|
10157
9403
|
if (!loc)
|
|
10158
9404
|
return 0;
|
|
10159
9405
|
try {
|
|
10160
|
-
return
|
|
9406
|
+
return statSync6(loc.path).size;
|
|
10161
9407
|
} catch {
|
|
10162
9408
|
return 0;
|
|
10163
9409
|
}
|
|
@@ -10174,7 +9420,7 @@ var init_agy = __esm({
|
|
|
10174
9420
|
});
|
|
10175
9421
|
|
|
10176
9422
|
// ../engine/dist/core/backends/cursor-store.js
|
|
10177
|
-
import { existsSync as existsSync9, readdirSync as readdirSync8, readFileSync as readFileSync5, statSync as
|
|
9423
|
+
import { existsSync as existsSync9, readdirSync as readdirSync8, readFileSync as readFileSync5, statSync as statSync7 } from "fs";
|
|
10178
9424
|
import { join as join11 } from "path";
|
|
10179
9425
|
function cursorProjectSlug(absPath) {
|
|
10180
9426
|
return absPath.replace(/[^a-zA-Z0-9]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
|
|
@@ -10191,7 +9437,7 @@ function listChatsIn(chatsRoot) {
|
|
|
10191
9437
|
const hashPath3 = join11(chatsRoot, workspaceHash);
|
|
10192
9438
|
let chatIds;
|
|
10193
9439
|
try {
|
|
10194
|
-
if (!
|
|
9440
|
+
if (!statSync7(hashPath3).isDirectory())
|
|
10195
9441
|
continue;
|
|
10196
9442
|
chatIds = readdirSync8(hashPath3);
|
|
10197
9443
|
} catch {
|
|
@@ -10213,7 +9459,7 @@ function listChatsIn(chatsRoot) {
|
|
|
10213
9459
|
let created = meta.createdAtMs ?? 0;
|
|
10214
9460
|
if (!mtime || !created) {
|
|
10215
9461
|
try {
|
|
10216
|
-
const st =
|
|
9462
|
+
const st = statSync7(dbPath);
|
|
10217
9463
|
mtime = mtime || st.mtimeMs;
|
|
10218
9464
|
created = created || st.birthtimeMs || st.mtimeMs;
|
|
10219
9465
|
} catch {
|
|
@@ -10256,7 +9502,7 @@ function findChat(chatsRoots, chatId) {
|
|
|
10256
9502
|
let created = meta.createdAtMs ?? 0;
|
|
10257
9503
|
if (!mtime || !created) {
|
|
10258
9504
|
try {
|
|
10259
|
-
const st =
|
|
9505
|
+
const st = statSync7(dbPath);
|
|
10260
9506
|
mtime = mtime || st.mtimeMs;
|
|
10261
9507
|
created = created || st.birthtimeMs || st.mtimeMs;
|
|
10262
9508
|
} catch {
|
|
@@ -10559,7 +9805,7 @@ var init_cursor_store = __esm({
|
|
|
10559
9805
|
});
|
|
10560
9806
|
|
|
10561
9807
|
// ../engine/dist/core/backends/cursor-ide.js
|
|
10562
|
-
import { existsSync as existsSync10, readFileSync as readFileSync6, readdirSync as readdirSync9, statSync as
|
|
9808
|
+
import { existsSync as existsSync10, readFileSync as readFileSync6, readdirSync as readdirSync9, statSync as statSync8 } from "fs";
|
|
10563
9809
|
import { dirname as dirname11, join as join12 } from "path";
|
|
10564
9810
|
function jsonOf(value) {
|
|
10565
9811
|
if (value == null)
|
|
@@ -10629,7 +9875,7 @@ function workspaceIndex(workspaceRoots) {
|
|
|
10629
9875
|
for (const id of entries) {
|
|
10630
9876
|
const dir = join12(root, id);
|
|
10631
9877
|
try {
|
|
10632
|
-
if (!
|
|
9878
|
+
if (!statSync8(dir).isDirectory())
|
|
10633
9879
|
continue;
|
|
10634
9880
|
} catch {
|
|
10635
9881
|
continue;
|
|
@@ -10975,7 +10221,7 @@ var init_cursor_ide = __esm({
|
|
|
10975
10221
|
});
|
|
10976
10222
|
|
|
10977
10223
|
// ../engine/dist/core/backends/cursor.js
|
|
10978
|
-
import { existsSync as existsSync11, readFileSync as readFileSync7, statSync as
|
|
10224
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, statSync as statSync9 } from "fs";
|
|
10979
10225
|
import { join as join13 } from "path";
|
|
10980
10226
|
var PREFIX4, CursorBackend, cursorBackend;
|
|
10981
10227
|
var init_cursor = __esm({
|
|
@@ -11028,7 +10274,7 @@ var init_cursor = __esm({
|
|
|
11028
10274
|
if (r.surface === "cli") {
|
|
11029
10275
|
let mtime2 = r.chat.updatedAtMs;
|
|
11030
10276
|
try {
|
|
11031
|
-
mtime2 =
|
|
10277
|
+
mtime2 = statSync9(r.chat.dbPath).mtimeMs || mtime2;
|
|
11032
10278
|
} catch {
|
|
11033
10279
|
}
|
|
11034
10280
|
return {
|
|
@@ -11041,7 +10287,7 @@ var init_cursor = __esm({
|
|
|
11041
10287
|
}
|
|
11042
10288
|
let mtime = r.composer.updatedAtMs;
|
|
11043
10289
|
try {
|
|
11044
|
-
mtime =
|
|
10290
|
+
mtime = statSync9(r.composer.globalDbPath).mtimeMs || mtime;
|
|
11045
10291
|
} catch {
|
|
11046
10292
|
}
|
|
11047
10293
|
return {
|
|
@@ -11287,7 +10533,7 @@ var init_cursor = __esm({
|
|
|
11287
10533
|
if (existsSync11(metaPath)) {
|
|
11288
10534
|
files.push({ name: "meta.json", bytes: readFileSync7(metaPath) });
|
|
11289
10535
|
}
|
|
11290
|
-
return { tool: "cursor", mtime:
|
|
10536
|
+
return { tool: "cursor", mtime: statSync9(r.chat.dbPath).mtimeMs, files };
|
|
11291
10537
|
}
|
|
11292
10538
|
const events = readComposerEvents(r.composer);
|
|
11293
10539
|
if (events.length === 0)
|
|
@@ -11295,7 +10541,7 @@ var init_cursor = __esm({
|
|
|
11295
10541
|
const body = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
11296
10542
|
return {
|
|
11297
10543
|
tool: "cursor",
|
|
11298
|
-
mtime:
|
|
10544
|
+
mtime: statSync9(r.composer.globalDbPath).mtimeMs,
|
|
11299
10545
|
files: [{ name: `${r.composer.composerId}.jsonl`, bytes: Buffer.from(body, "utf8") }]
|
|
11300
10546
|
};
|
|
11301
10547
|
} catch {
|
|
@@ -11361,8 +10607,8 @@ var init_backends = __esm({
|
|
|
11361
10607
|
|
|
11362
10608
|
// ../engine/dist/transcript/shadow.js
|
|
11363
10609
|
import { gzipSync as gzipSync2, gunzipSync as gunzipSync2 } from "zlib";
|
|
11364
|
-
import { createHash as
|
|
11365
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as
|
|
10610
|
+
import { createHash as createHash2 } from "crypto";
|
|
10611
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2, renameSync as renameSync2, statSync as statSync10 } from "fs";
|
|
11366
10612
|
import { dirname as dirname12, join as join14 } from "path";
|
|
11367
10613
|
function shadowRoot() {
|
|
11368
10614
|
return join14(getDataDir(), "shadow");
|
|
@@ -11392,7 +10638,7 @@ function writeShadowContainer(tool, rawId, container) {
|
|
|
11392
10638
|
renameSync2(tmp, path);
|
|
11393
10639
|
}
|
|
11394
10640
|
function sha1(s) {
|
|
11395
|
-
return
|
|
10641
|
+
return createHash2("sha1").update(s).digest("hex");
|
|
11396
10642
|
}
|
|
11397
10643
|
function lineKey(line) {
|
|
11398
10644
|
try {
|
|
@@ -11570,7 +10816,7 @@ function liveFingerprint(backend, rawId) {
|
|
|
11570
10816
|
const loc = backend.findSession(rawId);
|
|
11571
10817
|
if (!loc?.path)
|
|
11572
10818
|
return "";
|
|
11573
|
-
const st =
|
|
10819
|
+
const st = statSync10(loc.path);
|
|
11574
10820
|
return `${st.mtimeMs}:${st.size}`;
|
|
11575
10821
|
} catch {
|
|
11576
10822
|
return "";
|
|
@@ -11588,7 +10834,7 @@ function seedShadow(sessionId, container) {
|
|
|
11588
10834
|
}
|
|
11589
10835
|
function shadowSizeOnDisk(tool, rawId) {
|
|
11590
10836
|
try {
|
|
11591
|
-
return
|
|
10837
|
+
return statSync10(shadowFileFor(tool, rawId)).size;
|
|
11592
10838
|
} catch {
|
|
11593
10839
|
return 0;
|
|
11594
10840
|
}
|
|
@@ -11606,7 +10852,7 @@ var init_shadow = __esm({
|
|
|
11606
10852
|
});
|
|
11607
10853
|
|
|
11608
10854
|
// ../engine/dist/core/live-session-scan.js
|
|
11609
|
-
import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync9, statSync as
|
|
10855
|
+
import { existsSync as existsSync13, readdirSync as readdirSync10, readFileSync as readFileSync9, statSync as statSync11, openSync as openSync4, readSync as readSync4, closeSync as closeSync4 } from "fs";
|
|
11610
10856
|
import { join as join15, basename as basename9 } from "path";
|
|
11611
10857
|
function detectTool(sessionId) {
|
|
11612
10858
|
return getBackendForId(sessionId)?.id ?? "claude";
|
|
@@ -11724,7 +10970,7 @@ function readSessionGroupText(group) {
|
|
|
11724
10970
|
const parts = [];
|
|
11725
10971
|
for (const p of group.paths) {
|
|
11726
10972
|
try {
|
|
11727
|
-
const st =
|
|
10973
|
+
const st = statSync11(p);
|
|
11728
10974
|
parts.push(`${p}:${st.mtimeMs}:${st.size}`);
|
|
11729
10975
|
} catch {
|
|
11730
10976
|
parts.push(`${p}:missing`);
|
|
@@ -11744,7 +10990,7 @@ function readSessionGroupText(group) {
|
|
|
11744
10990
|
continue;
|
|
11745
10991
|
}
|
|
11746
10992
|
try {
|
|
11747
|
-
mtime = Math.max(mtime,
|
|
10993
|
+
mtime = Math.max(mtime, statSync11(p).mtimeMs);
|
|
11748
10994
|
} catch {
|
|
11749
10995
|
}
|
|
11750
10996
|
text = text ? mergeLineText(text, raw).text : raw;
|
|
@@ -11961,7 +11207,7 @@ var init_first_prompt = __esm({
|
|
|
11961
11207
|
});
|
|
11962
11208
|
|
|
11963
11209
|
// ../engine/dist/core/backends/claude.js
|
|
11964
|
-
import { existsSync as existsSync15, readdirSync as readdirSync11, readFileSync as readFileSync10, statSync as
|
|
11210
|
+
import { existsSync as existsSync15, readdirSync as readdirSync11, readFileSync as readFileSync10, statSync as statSync12, openSync as openSync6, readSync as readSync6, closeSync as closeSync6 } from "fs";
|
|
11965
11211
|
import { join as join16, basename as basename10 } from "path";
|
|
11966
11212
|
function stripReminders(text) {
|
|
11967
11213
|
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
@@ -12091,7 +11337,7 @@ var init_claude2 = __esm({
|
|
|
12091
11337
|
let mtime = 0;
|
|
12092
11338
|
for (const c of copies) {
|
|
12093
11339
|
try {
|
|
12094
|
-
mtime = Math.max(mtime,
|
|
11340
|
+
mtime = Math.max(mtime, statSync12(c.path).mtimeMs);
|
|
12095
11341
|
} catch {
|
|
12096
11342
|
}
|
|
12097
11343
|
}
|
|
@@ -12167,7 +11413,7 @@ var init_claude2 = __esm({
|
|
|
12167
11413
|
const fullPath = join16(projPath, f);
|
|
12168
11414
|
let stat3;
|
|
12169
11415
|
try {
|
|
12170
|
-
stat3 =
|
|
11416
|
+
stat3 = statSync12(fullPath);
|
|
12171
11417
|
} catch {
|
|
12172
11418
|
continue;
|
|
12173
11419
|
}
|
|
@@ -12388,7 +11634,7 @@ var init_claude2 = __esm({
|
|
|
12388
11634
|
const events = this.readEvents(rawId);
|
|
12389
11635
|
let fileMtime = 0;
|
|
12390
11636
|
try {
|
|
12391
|
-
fileMtime =
|
|
11637
|
+
fileMtime = statSync12(located.path).mtimeMs;
|
|
12392
11638
|
} catch {
|
|
12393
11639
|
}
|
|
12394
11640
|
return liveScanEditsFromEvents(events, this.fileToolMap, {
|
|
@@ -12443,13 +11689,13 @@ var init_claude2 = __esm({
|
|
|
12443
11689
|
continue;
|
|
12444
11690
|
const fp = join16(projPath, f);
|
|
12445
11691
|
try {
|
|
12446
|
-
const st =
|
|
11692
|
+
const st = statSync12(fp);
|
|
12447
11693
|
let mtime = st.mtimeMs;
|
|
12448
11694
|
const subDir = join16(projPath, f.slice(0, -6), "subagents");
|
|
12449
11695
|
if (existsSync15(subDir)) {
|
|
12450
11696
|
for (const sub of readdirSync11(subDir)) {
|
|
12451
11697
|
try {
|
|
12452
|
-
const subSt =
|
|
11698
|
+
const subSt = statSync12(join16(subDir, sub));
|
|
12453
11699
|
if (subSt.mtimeMs > mtime)
|
|
12454
11700
|
mtime = subSt.mtimeMs;
|
|
12455
11701
|
} catch {
|
|
@@ -12514,7 +11760,7 @@ var init_claude2 = __esm({
|
|
|
12514
11760
|
let total = 0;
|
|
12515
11761
|
for (const located of findSessionFiles(this.toRawId(prefixedId))) {
|
|
12516
11762
|
try {
|
|
12517
|
-
total +=
|
|
11763
|
+
total += statSync12(located.path).size;
|
|
12518
11764
|
} catch {
|
|
12519
11765
|
}
|
|
12520
11766
|
}
|
|
@@ -12563,8 +11809,8 @@ __export(project_resolver_exports, {
|
|
|
12563
11809
|
resolveWorkspaceId: () => resolveWorkspaceId
|
|
12564
11810
|
});
|
|
12565
11811
|
import { execSync } from "child_process";
|
|
12566
|
-
import { createHash as
|
|
12567
|
-
import { existsSync as existsSync16, readFileSync as readFileSync11, realpathSync as realpathSync2, readdirSync as readdirSync12, statSync as
|
|
11812
|
+
import { createHash as createHash3 } from "crypto";
|
|
11813
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11, realpathSync as realpathSync2, readdirSync as readdirSync12, statSync as statSync13 } from "fs";
|
|
12568
11814
|
import { basename as basename11, dirname as dirname13, isAbsolute, join as join17, resolve, sep } from "path";
|
|
12569
11815
|
function getProjectsConfigPath() {
|
|
12570
11816
|
return join17(getDataDir(), "projects.json");
|
|
@@ -12578,7 +11824,7 @@ function loadProjectsConfig() {
|
|
|
12578
11824
|
cachedConfig = { mtime: 0, cfg: {} };
|
|
12579
11825
|
return cachedConfig.cfg;
|
|
12580
11826
|
}
|
|
12581
|
-
const mtime =
|
|
11827
|
+
const mtime = statSync13(path).mtimeMs;
|
|
12582
11828
|
if (cachedConfig && cachedConfig.mtime === mtime)
|
|
12583
11829
|
return cachedConfig.cfg;
|
|
12584
11830
|
try {
|
|
@@ -12735,7 +11981,7 @@ function resolveGit(realPath) {
|
|
|
12735
11981
|
if (probe.kind === "failed") {
|
|
12736
11982
|
console.error(`[project] could not read git remotes in ${toplevel} \u2014 filing it as a local-only repo for now, which is probably wrong: ${probe.reason}`);
|
|
12737
11983
|
}
|
|
12738
|
-
const hash =
|
|
11984
|
+
const hash = createHash3("sha1").update(toplevel).digest("hex").slice(0, 12);
|
|
12739
11985
|
return {
|
|
12740
11986
|
id: `git-local:${hash}`,
|
|
12741
11987
|
displayName: basename11(toplevel),
|
|
@@ -12799,154 +12045,614 @@ function parseGitRemote(url) {
|
|
|
12799
12045
|
return { host: normaliseHost(url1[1]), owner: url1[2], repo: url1[3] };
|
|
12800
12046
|
return null;
|
|
12801
12047
|
}
|
|
12802
|
-
function normaliseHost(host) {
|
|
12803
|
-
for (const known of ["github.com", "gitlab.com", "bitbucket.org", "codeberg.org", "gitea.com"]) {
|
|
12804
|
-
if (host === known)
|
|
12805
|
-
return known;
|
|
12806
|
-
if (host.startsWith(known + "-") || host.startsWith(known + "."))
|
|
12807
|
-
return known;
|
|
12048
|
+
function normaliseHost(host) {
|
|
12049
|
+
for (const known of ["github.com", "gitlab.com", "bitbucket.org", "codeberg.org", "gitea.com"]) {
|
|
12050
|
+
if (host === known)
|
|
12051
|
+
return known;
|
|
12052
|
+
if (host.startsWith(known + "-") || host.startsWith(known + "."))
|
|
12053
|
+
return known;
|
|
12054
|
+
}
|
|
12055
|
+
return host;
|
|
12056
|
+
}
|
|
12057
|
+
function resolveAutoWorkspace(realPath, minRepos) {
|
|
12058
|
+
let cur = realPath;
|
|
12059
|
+
let last = "";
|
|
12060
|
+
let depth = 0;
|
|
12061
|
+
while (cur && cur !== last && depth < AUTO_WORKSPACE_MAX_DEPTH) {
|
|
12062
|
+
if (!existsSync16(join17(cur, ".git"))) {
|
|
12063
|
+
const cached = workspaceCache.get(cur);
|
|
12064
|
+
let qualifies;
|
|
12065
|
+
if (cached === void 0) {
|
|
12066
|
+
qualifies = countGitChildren(cur) >= minRepos;
|
|
12067
|
+
workspaceCache.set(cur, qualifies ? cur : null);
|
|
12068
|
+
} else {
|
|
12069
|
+
qualifies = cached !== null;
|
|
12070
|
+
}
|
|
12071
|
+
if (qualifies) {
|
|
12072
|
+
const name = basename11(cur);
|
|
12073
|
+
return { id: `ws:${name}`, displayName: name, source: "auto-workspace" };
|
|
12074
|
+
}
|
|
12075
|
+
}
|
|
12076
|
+
last = cur;
|
|
12077
|
+
cur = dirname13(cur);
|
|
12078
|
+
depth++;
|
|
12079
|
+
}
|
|
12080
|
+
return null;
|
|
12081
|
+
}
|
|
12082
|
+
function countGitChildren(dir) {
|
|
12083
|
+
let count = 0;
|
|
12084
|
+
let entries;
|
|
12085
|
+
try {
|
|
12086
|
+
entries = readdirSync12(dir);
|
|
12087
|
+
} catch {
|
|
12088
|
+
return 0;
|
|
12089
|
+
}
|
|
12090
|
+
for (const name of entries) {
|
|
12091
|
+
if (name.startsWith("."))
|
|
12092
|
+
continue;
|
|
12093
|
+
const child = join17(dir, name);
|
|
12094
|
+
try {
|
|
12095
|
+
const st = statSync13(child);
|
|
12096
|
+
if (!st.isDirectory())
|
|
12097
|
+
continue;
|
|
12098
|
+
if (existsSync16(join17(child, ".git")))
|
|
12099
|
+
count++;
|
|
12100
|
+
} catch {
|
|
12101
|
+
}
|
|
12102
|
+
}
|
|
12103
|
+
return count;
|
|
12104
|
+
}
|
|
12105
|
+
function safeRealpath(p) {
|
|
12106
|
+
try {
|
|
12107
|
+
return realpathSync2(p);
|
|
12108
|
+
} catch {
|
|
12109
|
+
return resolve(p);
|
|
12110
|
+
}
|
|
12111
|
+
}
|
|
12112
|
+
function isInside(child, parent) {
|
|
12113
|
+
if (!parent)
|
|
12114
|
+
return false;
|
|
12115
|
+
if (child === parent)
|
|
12116
|
+
return true;
|
|
12117
|
+
const c = child.endsWith(sep) ? child : child + sep;
|
|
12118
|
+
const p = parent.endsWith(sep) ? parent : parent + sep;
|
|
12119
|
+
return c.startsWith(p);
|
|
12120
|
+
}
|
|
12121
|
+
function globMatch(pattern, path) {
|
|
12122
|
+
const re = new RegExp("^" + globToRegex(toPosix(pattern)) + "$");
|
|
12123
|
+
return re.test(toPosix(path));
|
|
12124
|
+
}
|
|
12125
|
+
function toPosix(p) {
|
|
12126
|
+
return p.replace(/\\/g, "/");
|
|
12127
|
+
}
|
|
12128
|
+
function globToRegex(glob) {
|
|
12129
|
+
let out = "";
|
|
12130
|
+
let i = 0;
|
|
12131
|
+
while (i < glob.length) {
|
|
12132
|
+
const c = glob[i];
|
|
12133
|
+
if (c === "*" && glob[i + 1] === "*") {
|
|
12134
|
+
out += ".*";
|
|
12135
|
+
i += 2;
|
|
12136
|
+
if (glob[i] === "/")
|
|
12137
|
+
i++;
|
|
12138
|
+
} else if (c === "*") {
|
|
12139
|
+
out += "[^/]*";
|
|
12140
|
+
i++;
|
|
12141
|
+
} else if (c === "?") {
|
|
12142
|
+
out += "[^/]";
|
|
12143
|
+
i++;
|
|
12144
|
+
} else if (c === "{") {
|
|
12145
|
+
const end = glob.indexOf("}", i);
|
|
12146
|
+
if (end === -1) {
|
|
12147
|
+
out += "\\{";
|
|
12148
|
+
i++;
|
|
12149
|
+
continue;
|
|
12150
|
+
}
|
|
12151
|
+
const opts = glob.slice(i + 1, end).split(",").map(escapeRe).join("|");
|
|
12152
|
+
out += "(?:" + opts + ")";
|
|
12153
|
+
i = end + 1;
|
|
12154
|
+
} else {
|
|
12155
|
+
out += escapeRe(c);
|
|
12156
|
+
i++;
|
|
12157
|
+
}
|
|
12158
|
+
}
|
|
12159
|
+
return out;
|
|
12160
|
+
}
|
|
12161
|
+
function escapeRe(s) {
|
|
12162
|
+
return s.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
12163
|
+
}
|
|
12164
|
+
var DEFAULT_AUTO_WORKSPACE_MIN_REPOS, BOT_WORKTREE_MARKERS, resolveCache, gitCache, workspaceCache, wsIdCache, cachedConfig, GIT_TIMEOUT_MS, AUTO_WORKSPACE_MAX_DEPTH;
|
|
12165
|
+
var init_project_resolver = __esm({
|
|
12166
|
+
"../engine/dist/core/project-resolver.js"() {
|
|
12167
|
+
"use strict";
|
|
12168
|
+
init_paths();
|
|
12169
|
+
DEFAULT_AUTO_WORKSPACE_MIN_REPOS = 3;
|
|
12170
|
+
BOT_WORKTREE_MARKERS = [".claude-pr-bot"];
|
|
12171
|
+
resolveCache = /* @__PURE__ */ new Map();
|
|
12172
|
+
gitCache = /* @__PURE__ */ new Map();
|
|
12173
|
+
workspaceCache = /* @__PURE__ */ new Map();
|
|
12174
|
+
wsIdCache = /* @__PURE__ */ new Map();
|
|
12175
|
+
cachedConfig = null;
|
|
12176
|
+
GIT_TIMEOUT_MS = 1e4;
|
|
12177
|
+
AUTO_WORKSPACE_MAX_DEPTH = 2;
|
|
12178
|
+
}
|
|
12179
|
+
});
|
|
12180
|
+
|
|
12181
|
+
// ../engine/dist/core/credentials-env.js
|
|
12182
|
+
function envCredentials(env = process.env) {
|
|
12183
|
+
const token = (env.CHAT_RECALL_TOKEN || "").trim();
|
|
12184
|
+
const server = (env.CHAT_RECALL_SERVER || "").trim();
|
|
12185
|
+
if (!token || !server)
|
|
12186
|
+
return null;
|
|
12187
|
+
if (!/^https?:\/\//i.test(server))
|
|
12188
|
+
return null;
|
|
12189
|
+
return { serverUrl: normalise(server), token };
|
|
12190
|
+
}
|
|
12191
|
+
var normalise;
|
|
12192
|
+
var init_credentials_env = __esm({
|
|
12193
|
+
"../engine/dist/core/credentials-env.js"() {
|
|
12194
|
+
"use strict";
|
|
12195
|
+
normalise = (u) => u.trim().replace(/\/+$/, "");
|
|
12196
|
+
}
|
|
12197
|
+
});
|
|
12198
|
+
|
|
12199
|
+
// ../engine/dist/core/secret-redactor.js
|
|
12200
|
+
var secret_redactor_exports = {};
|
|
12201
|
+
__export(secret_redactor_exports, {
|
|
12202
|
+
DEFAULT_REDACTION_RULES: () => DEFAULT_REDACTION_RULES,
|
|
12203
|
+
_clearServerRulePack: () => _clearServerRulePack,
|
|
12204
|
+
_resetPrivacyCache: () => _resetPrivacyCache,
|
|
12205
|
+
_resetRedactorCache: () => _resetRedactorCache,
|
|
12206
|
+
applyChunkPrivacy: () => applyChunkPrivacy,
|
|
12207
|
+
findContextualSecrets: () => findContextualSecrets,
|
|
12208
|
+
installServerRulePack: () => installServerRulePack,
|
|
12209
|
+
isFilePathRedactionEnabled: () => isFilePathRedactionEnabled,
|
|
12210
|
+
isRedactionEnabled: () => isRedactionEnabled,
|
|
12211
|
+
isToolOutputRedactionEnabled: () => isToolOutputRedactionEnabled,
|
|
12212
|
+
redactFilePaths: () => redactFilePaths,
|
|
12213
|
+
redactSecrets: () => redactSecrets,
|
|
12214
|
+
redactToolResultBody: () => redactToolResultBody,
|
|
12215
|
+
scanTextForFindings: () => scanTextForFindings,
|
|
12216
|
+
serverRulePackVersion: () => serverRulePackVersion,
|
|
12217
|
+
validateRedactionRule: () => validateRedactionRule
|
|
12218
|
+
});
|
|
12219
|
+
import { statSync as statSync14 } from "fs";
|
|
12220
|
+
import { createHash as createHash4 } from "crypto";
|
|
12221
|
+
function secretOf(rule, m) {
|
|
12222
|
+
const raw = rule.secret != null ? m[rule.secret] : m[0];
|
|
12223
|
+
if (raw == null)
|
|
12224
|
+
return null;
|
|
12225
|
+
if (rule.where && !rule.where(raw))
|
|
12226
|
+
return null;
|
|
12227
|
+
return raw;
|
|
12228
|
+
}
|
|
12229
|
+
function looksLikeSecretToken(t) {
|
|
12230
|
+
if (t.length < 32)
|
|
12231
|
+
return false;
|
|
12232
|
+
if (/^[a-f0-9]+$/i.test(t))
|
|
12233
|
+
return true;
|
|
12234
|
+
return /[A-Z]/.test(t) && /[a-z]/.test(t) && /[0-9]/.test(t);
|
|
12235
|
+
}
|
|
12236
|
+
function findContextualSecrets(text) {
|
|
12237
|
+
if (!text)
|
|
12238
|
+
return [];
|
|
12239
|
+
const ranges = [];
|
|
12240
|
+
let m;
|
|
12241
|
+
SECRET_CONTEXT_RE.lastIndex = 0;
|
|
12242
|
+
while ((m = SECRET_CONTEXT_RE.exec(text)) !== null) {
|
|
12243
|
+
const winStart = m.index + m[0].length;
|
|
12244
|
+
const window = text.slice(winStart, winStart + 80);
|
|
12245
|
+
HIGH_ENTROPY_TOKEN_RE.lastIndex = 0;
|
|
12246
|
+
let tm;
|
|
12247
|
+
while ((tm = HIGH_ENTROPY_TOKEN_RE.exec(window)) !== null) {
|
|
12248
|
+
if (!looksLikeSecretToken(tm[0]))
|
|
12249
|
+
continue;
|
|
12250
|
+
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))) {
|
|
12251
|
+
continue;
|
|
12252
|
+
}
|
|
12253
|
+
ranges.push({ start: winStart + tm.index, end: winStart + tm.index + tm[0].length });
|
|
12254
|
+
break;
|
|
12255
|
+
}
|
|
12256
|
+
}
|
|
12257
|
+
ranges.sort((a, b) => a.start - b.start);
|
|
12258
|
+
const out = [];
|
|
12259
|
+
for (const r of ranges) {
|
|
12260
|
+
const last = out[out.length - 1];
|
|
12261
|
+
if (last && r.start < last.end) {
|
|
12262
|
+
last.end = Math.max(last.end, r.end);
|
|
12263
|
+
continue;
|
|
12264
|
+
}
|
|
12265
|
+
out.push({ ...r });
|
|
12266
|
+
}
|
|
12267
|
+
return out;
|
|
12268
|
+
}
|
|
12269
|
+
function isEnvRedactionRequested() {
|
|
12270
|
+
const v = process.env.CHAT_RECALL_REDACT_INDEX;
|
|
12271
|
+
if (v === void 0)
|
|
12272
|
+
return null;
|
|
12273
|
+
return v === "1" || v === "true" || v === "yes";
|
|
12274
|
+
}
|
|
12275
|
+
function settingsView() {
|
|
12276
|
+
let mtimeMs = -1;
|
|
12277
|
+
try {
|
|
12278
|
+
mtimeMs = statSync14(settingsFilePath()).mtimeMs;
|
|
12279
|
+
} catch {
|
|
12808
12280
|
}
|
|
12809
|
-
|
|
12810
|
-
|
|
12811
|
-
|
|
12812
|
-
|
|
12813
|
-
|
|
12814
|
-
|
|
12815
|
-
|
|
12816
|
-
|
|
12817
|
-
|
|
12818
|
-
|
|
12819
|
-
|
|
12820
|
-
qualifies = countGitChildren(cur) >= minRepos;
|
|
12821
|
-
workspaceCache.set(cur, qualifies ? cur : null);
|
|
12822
|
-
} else {
|
|
12823
|
-
qualifies = cached !== null;
|
|
12824
|
-
}
|
|
12825
|
-
if (qualifies) {
|
|
12826
|
-
const name = basename11(cur);
|
|
12827
|
-
return { id: `ws:${name}`, displayName: name, source: "auto-workspace" };
|
|
12281
|
+
if (cache && cache.mtimeMs === mtimeMs)
|
|
12282
|
+
return cache;
|
|
12283
|
+
let enabled = false;
|
|
12284
|
+
const extra = [];
|
|
12285
|
+
try {
|
|
12286
|
+
const s = loadSettings();
|
|
12287
|
+
enabled = !!s.privacy?.redactIndex;
|
|
12288
|
+
for (const r of s.privacy?.redactionRules ?? []) {
|
|
12289
|
+
try {
|
|
12290
|
+
extra.push({ label: r.label, pattern: new RegExp(r.pattern, "g") });
|
|
12291
|
+
} catch {
|
|
12828
12292
|
}
|
|
12829
12293
|
}
|
|
12830
|
-
|
|
12831
|
-
cur = dirname13(cur);
|
|
12832
|
-
depth++;
|
|
12294
|
+
} catch {
|
|
12833
12295
|
}
|
|
12834
|
-
|
|
12296
|
+
cache = { mtimeMs, enabled, rules: [...DEFAULT_REDACTION_RULES, ...extra] };
|
|
12297
|
+
return cache;
|
|
12835
12298
|
}
|
|
12836
|
-
function
|
|
12837
|
-
|
|
12838
|
-
|
|
12299
|
+
function compileServerRule(spec) {
|
|
12300
|
+
const name = spec.name || "(unnamed)";
|
|
12301
|
+
if (!spec.regex)
|
|
12302
|
+
return { name, reason: "empty pattern" };
|
|
12303
|
+
if (spec.regex.length > MAX_PATTERN_LEN)
|
|
12304
|
+
return { name, reason: `pattern longer than ${MAX_PATTERN_LEN} chars` };
|
|
12305
|
+
let re;
|
|
12839
12306
|
try {
|
|
12840
|
-
|
|
12841
|
-
|
|
12842
|
-
|
|
12307
|
+
const flags = "g" + (spec.flags || "").replace(/[^ims]/g, "");
|
|
12308
|
+
re = new RegExp(spec.regex, flags);
|
|
12309
|
+
} catch (e) {
|
|
12310
|
+
return { name, reason: `invalid regex: ${e instanceof Error ? e.message : e}` };
|
|
12843
12311
|
}
|
|
12844
|
-
|
|
12845
|
-
|
|
12312
|
+
if (re.test(""))
|
|
12313
|
+
return { name, reason: "matches the empty string (would redact everything)" };
|
|
12314
|
+
re.lastIndex = 0;
|
|
12315
|
+
if (re.test(CANARY))
|
|
12316
|
+
return { name, reason: "matches benign text \u2014 too broad" };
|
|
12317
|
+
re.lastIndex = 0;
|
|
12318
|
+
return { label: `${spec.source === "pack" ? "pack" : "tenant"}:${name}`, pattern: re };
|
|
12319
|
+
}
|
|
12320
|
+
function validateRedactionRule(spec) {
|
|
12321
|
+
const out = compileServerRule(spec);
|
|
12322
|
+
return "reason" in out ? { ok: false, reason: out.reason } : { ok: true };
|
|
12323
|
+
}
|
|
12324
|
+
function installServerRulePack(pack) {
|
|
12325
|
+
const rejected = [];
|
|
12326
|
+
const rules = [];
|
|
12327
|
+
for (const spec of pack.rules || []) {
|
|
12328
|
+
if (rules.length >= MAX_PACK_RULES) {
|
|
12329
|
+
rejected.push({ name: spec.name || "(unnamed)", reason: `pack exceeds ${MAX_PACK_RULES} rules` });
|
|
12846
12330
|
continue;
|
|
12847
|
-
const child = join17(dir, name);
|
|
12848
|
-
try {
|
|
12849
|
-
const st = statSync14(child);
|
|
12850
|
-
if (!st.isDirectory())
|
|
12851
|
-
continue;
|
|
12852
|
-
if (existsSync16(join17(child, ".git")))
|
|
12853
|
-
count++;
|
|
12854
|
-
} catch {
|
|
12855
12331
|
}
|
|
12332
|
+
const out = compileServerRule(spec);
|
|
12333
|
+
if ("reason" in out)
|
|
12334
|
+
rejected.push(out);
|
|
12335
|
+
else
|
|
12336
|
+
rules.push(out);
|
|
12856
12337
|
}
|
|
12857
|
-
|
|
12338
|
+
const version2 = pack.version || "";
|
|
12339
|
+
serverPack = { version: version2, rules };
|
|
12340
|
+
return { version: version2, accepted: rules.length, rejected };
|
|
12858
12341
|
}
|
|
12859
|
-
function
|
|
12860
|
-
|
|
12861
|
-
|
|
12862
|
-
|
|
12863
|
-
|
|
12342
|
+
function serverRulePackVersion() {
|
|
12343
|
+
return serverPack ? serverPack.version || "unversioned" : null;
|
|
12344
|
+
}
|
|
12345
|
+
function _clearServerRulePack() {
|
|
12346
|
+
serverPack = null;
|
|
12347
|
+
}
|
|
12348
|
+
function activeRules() {
|
|
12349
|
+
const base3 = settingsView().rules;
|
|
12350
|
+
return serverPack && serverPack.rules.length > 0 ? [...base3, ...serverPack.rules] : base3;
|
|
12351
|
+
}
|
|
12352
|
+
function isRedactionEnabled() {
|
|
12353
|
+
const env = isEnvRedactionRequested();
|
|
12354
|
+
if (env !== null)
|
|
12355
|
+
return env;
|
|
12356
|
+
return settingsView().enabled;
|
|
12357
|
+
}
|
|
12358
|
+
function _resetRedactorCache() {
|
|
12359
|
+
cache = null;
|
|
12360
|
+
}
|
|
12361
|
+
function redactSecrets(text, opts = {}) {
|
|
12362
|
+
if (!opts.force && !isRedactionEnabled())
|
|
12363
|
+
return text;
|
|
12364
|
+
if (!text)
|
|
12365
|
+
return text;
|
|
12366
|
+
const rules = opts.rules || activeRules();
|
|
12367
|
+
let out = text;
|
|
12368
|
+
for (const r of rules) {
|
|
12369
|
+
out = out.replace(r.pattern, (...args) => {
|
|
12370
|
+
const whole = args[0];
|
|
12371
|
+
const m = args.slice(0, args.length);
|
|
12372
|
+
const secret = secretOf(r, m);
|
|
12373
|
+
if (secret == null)
|
|
12374
|
+
return whole;
|
|
12375
|
+
if (opts.count)
|
|
12376
|
+
opts.count.redactions++;
|
|
12377
|
+
return whole.slice(0, whole.length - secret.length) + `[REDACTED:${r.label}]`;
|
|
12378
|
+
});
|
|
12379
|
+
}
|
|
12380
|
+
const ctx = findContextualSecrets(out);
|
|
12381
|
+
for (let i = ctx.length - 1; i >= 0; i--) {
|
|
12382
|
+
const { start, end } = ctx[i];
|
|
12383
|
+
if (opts.count)
|
|
12384
|
+
opts.count.redactions++;
|
|
12385
|
+
out = out.slice(0, start) + "[REDACTED:secret-context]" + out.slice(end);
|
|
12864
12386
|
}
|
|
12387
|
+
return out;
|
|
12865
12388
|
}
|
|
12866
|
-
function
|
|
12867
|
-
if (!
|
|
12868
|
-
return
|
|
12869
|
-
if (
|
|
12870
|
-
return
|
|
12871
|
-
|
|
12872
|
-
const p = parent.endsWith(sep) ? parent : parent + sep;
|
|
12873
|
-
return c.startsWith(p);
|
|
12389
|
+
function maskSecret(s) {
|
|
12390
|
+
if (!s)
|
|
12391
|
+
return "";
|
|
12392
|
+
if (s.length <= 4)
|
|
12393
|
+
return "*".repeat(s.length);
|
|
12394
|
+
return "*".repeat(Math.min(s.length - 4, 60)) + s.slice(-4);
|
|
12874
12395
|
}
|
|
12875
|
-
function
|
|
12876
|
-
const
|
|
12877
|
-
|
|
12396
|
+
function globalRegexFor(pattern) {
|
|
12397
|
+
const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
|
|
12398
|
+
const key2 = pattern.source + "\0" + flags;
|
|
12399
|
+
let re = globalRegexCache.get(key2);
|
|
12400
|
+
if (!re) {
|
|
12401
|
+
re = new RegExp(pattern.source, flags);
|
|
12402
|
+
globalRegexCache.set(key2, re);
|
|
12403
|
+
}
|
|
12404
|
+
return re;
|
|
12878
12405
|
}
|
|
12879
|
-
function
|
|
12880
|
-
|
|
12406
|
+
function makeLineResolver(text) {
|
|
12407
|
+
const starts = [];
|
|
12408
|
+
for (let i = text.indexOf("\n"); i !== -1; i = text.indexOf("\n", i + 1))
|
|
12409
|
+
starts.push(i);
|
|
12410
|
+
return (index) => {
|
|
12411
|
+
let lo = 0, hi = starts.length;
|
|
12412
|
+
while (lo < hi) {
|
|
12413
|
+
const mid = lo + hi >> 1;
|
|
12414
|
+
if (starts[mid] < index)
|
|
12415
|
+
lo = mid + 1;
|
|
12416
|
+
else
|
|
12417
|
+
hi = mid;
|
|
12418
|
+
}
|
|
12419
|
+
return lo + 1;
|
|
12420
|
+
};
|
|
12881
12421
|
}
|
|
12882
|
-
function
|
|
12883
|
-
|
|
12884
|
-
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
12890
|
-
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
12897
|
-
|
|
12898
|
-
} else if (c === "{") {
|
|
12899
|
-
const end = glob.indexOf("}", i);
|
|
12900
|
-
if (end === -1) {
|
|
12901
|
-
out += "\\{";
|
|
12902
|
-
i++;
|
|
12422
|
+
function scanTextForFindings(text, opts = {}) {
|
|
12423
|
+
if (!text)
|
|
12424
|
+
return [];
|
|
12425
|
+
const rules = opts.rules || activeRules();
|
|
12426
|
+
const findings = [];
|
|
12427
|
+
const seenSpans = /* @__PURE__ */ new Set();
|
|
12428
|
+
const lineAt = makeLineResolver(text);
|
|
12429
|
+
for (const r of rules) {
|
|
12430
|
+
const re = globalRegexFor(r.pattern);
|
|
12431
|
+
re.lastIndex = 0;
|
|
12432
|
+
let m;
|
|
12433
|
+
while ((m = re.exec(text)) !== null) {
|
|
12434
|
+
const secret = secretOf(r, m);
|
|
12435
|
+
if (secret == null) {
|
|
12436
|
+
if (re.lastIndex === m.index)
|
|
12437
|
+
re.lastIndex++;
|
|
12903
12438
|
continue;
|
|
12904
12439
|
}
|
|
12905
|
-
const
|
|
12906
|
-
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
|
|
12910
|
-
|
|
12440
|
+
const at = m.index + (m[0].length - secret.length);
|
|
12441
|
+
const span = `${at}:${secret.length}`;
|
|
12442
|
+
if (!seenSpans.has(span)) {
|
|
12443
|
+
seenSpans.add(span);
|
|
12444
|
+
findings.push({ rule: r.label, line: lineAt(at), preview: maskSecret(secret) });
|
|
12445
|
+
}
|
|
12446
|
+
if (re.lastIndex === m.index)
|
|
12447
|
+
re.lastIndex++;
|
|
12911
12448
|
}
|
|
12912
12449
|
}
|
|
12913
|
-
|
|
12450
|
+
for (const { start, end } of findContextualSecrets(text)) {
|
|
12451
|
+
const line = lineAt(start);
|
|
12452
|
+
findings.push({ rule: "secret-context", line, preview: maskSecret(text.slice(start, end)) });
|
|
12453
|
+
}
|
|
12454
|
+
return findings;
|
|
12455
|
+
}
|
|
12456
|
+
function privacyView() {
|
|
12457
|
+
let mtimeMs = -1;
|
|
12458
|
+
try {
|
|
12459
|
+
mtimeMs = statSync14(settingsFilePath()).mtimeMs;
|
|
12460
|
+
} catch {
|
|
12461
|
+
}
|
|
12462
|
+
if (privacyCache && privacyCache.mtimeMs === mtimeMs)
|
|
12463
|
+
return privacyCache;
|
|
12464
|
+
let redactToolOutputs = false, redactFilePaths2 = false;
|
|
12465
|
+
try {
|
|
12466
|
+
const s = loadSettings();
|
|
12467
|
+
redactToolOutputs = !!s.privacy?.redactToolOutputs;
|
|
12468
|
+
redactFilePaths2 = !!s.privacy?.redactFilePaths;
|
|
12469
|
+
} catch {
|
|
12470
|
+
}
|
|
12471
|
+
privacyCache = { mtimeMs, redactToolOutputs, redactFilePaths: redactFilePaths2 };
|
|
12472
|
+
return privacyCache;
|
|
12914
12473
|
}
|
|
12915
|
-
function
|
|
12916
|
-
|
|
12474
|
+
function _resetPrivacyCache() {
|
|
12475
|
+
privacyCache = null;
|
|
12917
12476
|
}
|
|
12918
|
-
|
|
12919
|
-
|
|
12920
|
-
"../engine/dist/core/project-resolver.js"() {
|
|
12921
|
-
"use strict";
|
|
12922
|
-
init_paths();
|
|
12923
|
-
DEFAULT_AUTO_WORKSPACE_MIN_REPOS = 3;
|
|
12924
|
-
BOT_WORKTREE_MARKERS = [".claude-pr-bot"];
|
|
12925
|
-
resolveCache = /* @__PURE__ */ new Map();
|
|
12926
|
-
gitCache = /* @__PURE__ */ new Map();
|
|
12927
|
-
workspaceCache = /* @__PURE__ */ new Map();
|
|
12928
|
-
wsIdCache = /* @__PURE__ */ new Map();
|
|
12929
|
-
cachedConfig = null;
|
|
12930
|
-
GIT_TIMEOUT_MS = 1e4;
|
|
12931
|
-
AUTO_WORKSPACE_MAX_DEPTH = 2;
|
|
12932
|
-
}
|
|
12933
|
-
});
|
|
12934
|
-
|
|
12935
|
-
// ../engine/dist/core/credentials-env.js
|
|
12936
|
-
function envCredentials(env = process.env) {
|
|
12937
|
-
const token = (env.CHAT_RECALL_TOKEN || "").trim();
|
|
12938
|
-
const server = (env.CHAT_RECALL_SERVER || "").trim();
|
|
12939
|
-
if (!token || !server)
|
|
12940
|
-
return null;
|
|
12941
|
-
if (!/^https?:\/\//i.test(server))
|
|
12942
|
-
return null;
|
|
12943
|
-
return { serverUrl: normalise(server), token };
|
|
12477
|
+
function isToolOutputRedactionEnabled() {
|
|
12478
|
+
return privacyView().redactToolOutputs;
|
|
12944
12479
|
}
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12480
|
+
function isFilePathRedactionEnabled() {
|
|
12481
|
+
return privacyView().redactFilePaths;
|
|
12482
|
+
}
|
|
12483
|
+
function redactFilePaths(text) {
|
|
12484
|
+
if (!text)
|
|
12485
|
+
return text;
|
|
12486
|
+
return text.replace(PATH_REGEX, (m) => {
|
|
12487
|
+
if (m.startsWith("[REDACTED:"))
|
|
12488
|
+
return m;
|
|
12489
|
+
const h = createHash4("sha256").update(m).digest("hex").slice(0, 12);
|
|
12490
|
+
return `[path:${h}]`;
|
|
12491
|
+
});
|
|
12492
|
+
}
|
|
12493
|
+
function applyChunkPrivacy(text) {
|
|
12494
|
+
let out = redactSecrets(text);
|
|
12495
|
+
if (privacyView().redactFilePaths)
|
|
12496
|
+
out = redactFilePaths(out);
|
|
12497
|
+
return out;
|
|
12498
|
+
}
|
|
12499
|
+
function redactToolResultBody(toolName, body) {
|
|
12500
|
+
if (!body)
|
|
12501
|
+
return body;
|
|
12502
|
+
return `[redacted: ${toolName} output, ${body.length} chars]`;
|
|
12503
|
+
}
|
|
12504
|
+
var DEFAULT_REDACTION_RULES, SECRET_CONTEXT_RE, HIGH_ENTROPY_TOKEN_RE, cache, CANARY, MAX_PACK_RULES, MAX_PATTERN_LEN, serverPack, globalRegexCache, privacyCache, PATH_REGEX;
|
|
12505
|
+
var init_secret_redactor = __esm({
|
|
12506
|
+
"../engine/dist/core/secret-redactor.js"() {
|
|
12948
12507
|
"use strict";
|
|
12949
|
-
|
|
12508
|
+
init_settings();
|
|
12509
|
+
DEFAULT_REDACTION_RULES = [
|
|
12510
|
+
// AWS access tokens. Prefix-anchored: AKIA, ASIA, ABIA (long-term,
|
|
12511
|
+
// STS, EC2). Always exactly 16 hex/alphanumeric after the prefix.
|
|
12512
|
+
// NOTE: this matches only the access-key-ID, NOT the secret key value —
|
|
12513
|
+
// the `env-secret` rule below covers AWS_SECRET_ACCESS_KEY / AWS_SESSION_TOKEN.
|
|
12514
|
+
{ label: "aws-access-token", pattern: /\b(?:AKIA|ASIA|ABIA|ACCA)[A-Z0-9]{16}\b/g },
|
|
12515
|
+
// AWS STS session tokens. These are long base64 blobs with NO `NAME=` context
|
|
12516
|
+
// when pasted bare into prose/code, so `env-secret` misses them — but they
|
|
12517
|
+
// reliably start with one of a handful of base64 prefixes (the encoded
|
|
12518
|
+
// `{"...` JSON header). Prefix-anchored → low false-positive. This is the
|
|
12519
|
+
// bare-value form that leaked (`search('IQoJEXAMPLEfakeSESSIONtokenNOTreal01234567890abcDEF==...')`).
|
|
12520
|
+
{ label: "aws-session-token", pattern: /\b(?:IQoJ|FwoG|FwoH|FQoG|FQoH|FwoD)[A-Za-z0-9/+]{40,}={0,2}/g },
|
|
12521
|
+
// Env/shell-assignment secrets — a VAR whose name ends in KEY/SECRET/TOKEN/
|
|
12522
|
+
// PASSWORD/CREDENTIAL, then `=`/`:`, then the value. Zero-width lookbehind so
|
|
12523
|
+
// only the VALUE is redacted (the var name stays for context). This is the
|
|
12524
|
+
// dominant real-world leak vector (`export` dumps, .env files, `curl -H`,
|
|
12525
|
+
// tool output) and is exactly what leaked AWS_SECRET_ACCESS_KEY and
|
|
12526
|
+
// AWS_SESSION_TOKEN in cleartext while the access-key-ID rule above caught
|
|
12527
|
+
// only the (least-sensitive) ID.
|
|
12528
|
+
// Suffix list deliberately broad: DB_PASS (our own helm chart's name!),
|
|
12529
|
+
// NPM_AUTH, SENTRY_DSN, SESSION/COOKIE secrets and BEARER vars all leaked
|
|
12530
|
+
// past the original KEY/SECRET/TOKEN/PASSWORD-only list. Values under 12
|
|
12531
|
+
// chars don't redact, so flag-ish vars (BYPASS=true) stay readable.
|
|
12532
|
+
// Context CONSUMED, secret in group 1 — see RedactionRule.secret. As a
|
|
12533
|
+
// lookbehind this was the second most expensive rule in the collector.
|
|
12534
|
+
{ 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 },
|
|
12535
|
+
// Credentials embedded in a connection URL: scheme://user:PASSWORD@host.
|
|
12536
|
+
// Redacts only the password segment (keeps scheme/user/host for context).
|
|
12537
|
+
//
|
|
12538
|
+
// Scheme-agnostic on purpose. The old rule allowlisted eight DB schemes, so
|
|
12539
|
+
// `https://user:pass@host`, `ssh://`, `ftp://`, `smtp://` and every other
|
|
12540
|
+
// userinfo URL walked through in cleartext — and a `jdbc:postgresql://…`
|
|
12541
|
+
// prefix broke the \b anchor for the one family it did cover. Any scheme
|
|
12542
|
+
// followed by userinfo is a credential, so match the shape, not a list.
|
|
12543
|
+
{ label: "url-password", secret: 1, pattern: /\b[a-zA-Z][a-zA-Z0-9+.-]{1,31}:\/\/[^:@\s/]{1,64}:([^@\s/]{1,256})(?=@)/g },
|
|
12544
|
+
// Bare AWS secret-access-key VALUE: EXACTLY 40 base64 chars, word-bounded,
|
|
12545
|
+
// containing upper+lower+digit. This is the gitleaks heuristic — the mixed-case
|
|
12546
|
+
// requirement excludes 40-char lowercase-hex git SHAs, and the exact-40 bound
|
|
12547
|
+
// excludes longer blobs/tokens. It catches the value when it appears bare in
|
|
12548
|
+
// prose with NO `NAME=` and NO nearby context word (e.g. inside a markdown
|
|
12549
|
+
// table or quoted in analysis) — the residual leak path the env-secret and
|
|
12550
|
+
// contextual rules both miss. Placed AFTER env-secret/url-password so the
|
|
12551
|
+
// keyed/URL forms keep their more-specific labels.
|
|
12552
|
+
// The three stacked lookaheads each re-scanned the same 40 characters, which
|
|
12553
|
+
// made this the MOST expensive rule of all 106 the collector runs (13.1% of a
|
|
12554
|
+
// 29.5 MB scan). The mixed-case-plus-digit test is now one JS pass.
|
|
12555
|
+
{
|
|
12556
|
+
label: "aws-secret-key",
|
|
12557
|
+
secret: 1,
|
|
12558
|
+
pattern: /(?<![A-Za-z0-9/+])([A-Za-z0-9/+]{40})(?![A-Za-z0-9/+])/g,
|
|
12559
|
+
where: (v) => /[a-z]/.test(v) && /[A-Z]/.test(v) && /[0-9]/.test(v)
|
|
12560
|
+
},
|
|
12561
|
+
// GitHub personal access tokens.
|
|
12562
|
+
{ label: "github-pat", pattern: /\bghp_[A-Za-z0-9]{36}\b/g },
|
|
12563
|
+
// GitHub fine-grained PATs.
|
|
12564
|
+
{ label: "github-fine", pattern: /\bgithub_pat_[A-Za-z0-9_]{82}\b/g },
|
|
12565
|
+
// GitHub OAuth.
|
|
12566
|
+
{ label: "github-oauth", pattern: /\bgho_[A-Za-z0-9]{36}\b/g },
|
|
12567
|
+
// GitHub app + refresh.
|
|
12568
|
+
{ label: "github-app", pattern: /\b(?:ghs|ghu|ghr)_[A-Za-z0-9]{36}\b/g },
|
|
12569
|
+
// Slack bot/user/app tokens.
|
|
12570
|
+
{ label: "slack-token", pattern: /\bxox[abopr]-[A-Za-z0-9-]{10,}\b/g },
|
|
12571
|
+
// Slack incoming webhook URL.
|
|
12572
|
+
{ label: "slack-webhook", pattern: /\bhttps:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[A-Za-z0-9]+\b/g },
|
|
12573
|
+
// Stripe live + test keys.
|
|
12574
|
+
{ label: "stripe-key", pattern: /\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{24,}\b/g },
|
|
12575
|
+
// Anthropic.
|
|
12576
|
+
{ label: "anthropic-key", pattern: /\bsk-ant-[a-zA-Z0-9_-]{40,}\b/g },
|
|
12577
|
+
// OpenAI. Two shapes, deliberately kept apart. The classic key is
|
|
12578
|
+
// `sk-` + base62 with NO hyphens; the modern scoped keys carry an explicit
|
|
12579
|
+
// proj/svcacct/admin segment first. Allowing hyphens after a bare `sk-`
|
|
12580
|
+
// (which is what admitted sk-proj- in the first place) also matches ordinary
|
|
12581
|
+
// kebab-case text — `sk-fix-the-login-redirect-bug`, `.sk-button-primary`,
|
|
12582
|
+
// `sk-2024-01-01-backup` — and this corpus is full of branch names and CSS
|
|
12583
|
+
// classes. Requiring the segment keeps sk-proj- coverage without that.
|
|
12584
|
+
{ label: "openai-key", pattern: /\bsk-(?:proj|svcacct|admin)-[A-Za-z0-9_-]{20,}\b|\bsk-[A-Za-z0-9]{20,}\b/g },
|
|
12585
|
+
// Google API key (AIza…).
|
|
12586
|
+
{ label: "google-api-key", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
|
|
12587
|
+
// Generic JWT — three base64url segments.
|
|
12588
|
+
{ label: "jwt", pattern: /\beyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g },
|
|
12589
|
+
// Private key blocks (PEM). The label is a free word run rather than a fixed
|
|
12590
|
+
// list, so ENCRYPTED PRIVATE KEY and PGP PRIVATE KEY BLOCK are covered
|
|
12591
|
+
// without another enumeration, and \1 forces END to name the same kind as
|
|
12592
|
+
// BEGIN.
|
|
12593
|
+
//
|
|
12594
|
+
// The body is [^-], NOT [\s\S]*?. That is a performance boundary, not a
|
|
12595
|
+
// style choice. An unanchored prefix with an unbounded lazy gap re-scans to
|
|
12596
|
+
// end-of-input from every candidate start, so text carrying many BEGIN
|
|
12597
|
+
// markers and no matching END costs O(n^2): 500KB of that measured 810ms
|
|
12598
|
+
// here, and this runs synchronously on the server's event loop over
|
|
12599
|
+
// tenant-supplied text (services/secret-rescan.ts). A PEM body is base64
|
|
12600
|
+
// plus headers and contains no '-', so excluding it makes the scan stop at
|
|
12601
|
+
// the next delimiter instead of at EOF — same matches, linear cost.
|
|
12602
|
+
{ label: "private-key", pattern: /-----BEGIN ([A-Z0-9 ]{0,32})PRIVATE KEY(?: BLOCK)?-----[^-]{0,10000}?-----END \1PRIVATE KEY(?: BLOCK)?-----/g },
|
|
12603
|
+
// PuTTY keys are not PEM. Match the Private-Lines payload — the actual key
|
|
12604
|
+
// material — rather than spanning the whole file, which would need the same
|
|
12605
|
+
// unbounded gap the rule above just removed. Line-anchored and base64-only,
|
|
12606
|
+
// so it cannot run away.
|
|
12607
|
+
{ label: "putty-key", pattern: /^Private-Lines:[ \t]*\d{1,4}[\r\n]+(?:[A-Za-z0-9+/=]{8,120}[\r\n]+){1,400}/gm },
|
|
12608
|
+
// npm tokens (uuid-shaped — overlap with our UUID filter; intentional).
|
|
12609
|
+
{ label: "npm-token", pattern: /\bnpm_[A-Za-z0-9]{36}\b/g },
|
|
12610
|
+
// .npmrc auth lines: //registry.npmjs.org/:_authToken=VALUE (the key is not
|
|
12611
|
+
// ALL-CAPS, so the env-secret rule above never matched it). The leading `:`
|
|
12612
|
+
// is required — it is what makes this npmrc syntax rather than any shell var
|
|
12613
|
+
// ending in _AUTH, which env-secret already owns and labels better.
|
|
12614
|
+
// [^\s"'`]+ so the closing quote is not swallowed, and a ${VAR} placeholder
|
|
12615
|
+
// is left alone — redacting it destroys a config example and hides nothing.
|
|
12616
|
+
// The rule the perf profile caught the wedged daemon inside: 98.94% of samples.
|
|
12617
|
+
{ label: "npmrc-auth", secret: 1, pattern: /:_(?:authToken|password|auth)[ \t]*=[ \t]*(?!\$\{)([^\s"'`]{12,})/gi },
|
|
12618
|
+
// HTTP Authorization headers. env-secret requires an ALL-CAPS name, and
|
|
12619
|
+
// `Authorization` is mixed case, so both Bearer and Basic walked straight
|
|
12620
|
+
// through — including short opaque tokens the contextual pass also misses
|
|
12621
|
+
// (it needs 32+ chars AND mixed-case-plus-digit).
|
|
12622
|
+
// Same two guards as npmrc-auth: stop at a quote, and skip the obvious
|
|
12623
|
+
// placeholders that fill documentation (<YOUR_TOKEN>, ${TOKEN}, xxx…).
|
|
12624
|
+
{ label: "auth-header", secret: 1, pattern: /\bauthorization[ \t]*:[ \t]*(?:bearer|basic|token)[ \t]+(?![<$])([^\s"'`<]{8,})/gi },
|
|
12625
|
+
// Vendor tokens with unambiguous prefixes. Each is a fixed literal, so a
|
|
12626
|
+
// false positive is essentially impossible and the cost of listing is low.
|
|
12627
|
+
{ label: "gitlab-pat", pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
|
|
12628
|
+
{ label: "slack-app-token", pattern: /\bxapp-\d-[A-Z0-9]{8,}-\d{10,}-[a-f0-9]{32,}\b/g },
|
|
12629
|
+
{ label: "sendgrid-key", pattern: /\bSG\.[A-Za-z0-9_-]{20,24}\.[A-Za-z0-9_-]{40,50}\b/g },
|
|
12630
|
+
// (?<![-\w]) so `cache-key-<md5>` is not read as a mailgun key.
|
|
12631
|
+
{ label: "mailgun-key", pattern: /(?<![-\w])key-[a-f0-9]{32}\b/g },
|
|
12632
|
+
{ label: "digitalocean-pat", pattern: /\bdop_v1_[a-f0-9]{64}\b/g },
|
|
12633
|
+
{ label: "huggingface-token", pattern: /\bhf_[A-Za-z0-9]{30,}\b/g },
|
|
12634
|
+
{ label: "shopify-token", pattern: /\bshp(?:at|ca|pa|ss)_[a-fA-F0-9]{32}\b/g },
|
|
12635
|
+
{ label: "pypi-token", pattern: /\bpypi-AgEIcHlwaS5vcmc[A-Za-z0-9_-]{50,}\b/g },
|
|
12636
|
+
// No twilio-sid rule: AC…/SK… are Twilio SIDs, which are public account and
|
|
12637
|
+
// key identifiers, not the auth token. Redacting them hid nothing and
|
|
12638
|
+
// collided with 32-hex etags and MD5 sums.
|
|
12639
|
+
// No discord-bot-token rule either: the shape (word.word.word) matched
|
|
12640
|
+
// ordinary dotted symbols such as a.b.ApplicationContextProviderImpl.
|
|
12641
|
+
{ label: "telegram-bot-token", pattern: /\b\d{8,10}:AA[A-Za-z0-9_-]{32,}\b/g },
|
|
12642
|
+
{ label: "doppler-token", pattern: /\bdp\.(?:pt|st|sa|ct)\.[A-Za-z0-9_-]{20,}\b/g },
|
|
12643
|
+
// Azure Storage SAS signature — the `sig=` parameter is the actual secret.
|
|
12644
|
+
{ label: "azure-sas", secret: 1, pattern: /[?&]sig=([A-Za-z0-9%/+=]{20,})/g }
|
|
12645
|
+
];
|
|
12646
|
+
SECRET_CONTEXT_RE = /\b(?:secret|password|passwd|credential|access[ _-]?key|private[ _-]?key|api[ _-]?key|auth(?:oriz\w*)?|bearer|token)\b/gi;
|
|
12647
|
+
HIGH_ENTROPY_TOKEN_RE = /[A-Za-z0-9/+_-]{32,}/g;
|
|
12648
|
+
cache = null;
|
|
12649
|
+
CANARY = "the quick brown fox jumps over the lazy dog 0123456789 commit 8ba1f109551bd432803012645ac136ddd475d0fb src/index.ts:42";
|
|
12650
|
+
MAX_PACK_RULES = 200;
|
|
12651
|
+
MAX_PATTERN_LEN = 512;
|
|
12652
|
+
serverPack = null;
|
|
12653
|
+
globalRegexCache = /* @__PURE__ */ new Map();
|
|
12654
|
+
privacyCache = null;
|
|
12655
|
+
PATH_REGEX = /(?<![A-Za-z0-9_])(?:\/[^\s'"`<>]+|[A-Za-z]:\\[^\s'"`<>]+)/g;
|
|
12950
12656
|
}
|
|
12951
12657
|
});
|
|
12952
12658
|
|
|
@@ -14929,111 +14635,6 @@ var init_source_registry = __esm({
|
|
|
14929
14635
|
}
|
|
14930
14636
|
});
|
|
14931
14637
|
|
|
14932
|
-
// ../engine/dist/parsers/session-source.js
|
|
14933
|
-
var SessionSource;
|
|
14934
|
-
var init_session_source = __esm({
|
|
14935
|
-
"../engine/dist/parsers/session-source.js"() {
|
|
14936
|
-
"use strict";
|
|
14937
|
-
init_session();
|
|
14938
|
-
init_chunker();
|
|
14939
|
-
init_settings();
|
|
14940
|
-
SessionSource = class {
|
|
14941
|
-
sourceType = "session";
|
|
14942
|
-
claudeDir;
|
|
14943
|
-
constructor(claudeDir) {
|
|
14944
|
-
this.claudeDir = claudeDir;
|
|
14945
|
-
}
|
|
14946
|
-
async *discover() {
|
|
14947
|
-
if (!isSourceEnabled("claude", "sessions"))
|
|
14948
|
-
return;
|
|
14949
|
-
for (const [entry, sessionPath] of getAllSessions(this.claudeDir)) {
|
|
14950
|
-
yield this.entryToItem(entry, sessionPath);
|
|
14951
|
-
}
|
|
14952
|
-
}
|
|
14953
|
-
async parse(item) {
|
|
14954
|
-
const content = await parseSessionFile(item.filePath);
|
|
14955
|
-
const entry = this.itemToEntry(item);
|
|
14956
|
-
const sessionChunks = chunkSession(entry, content);
|
|
14957
|
-
item.extra = {
|
|
14958
|
-
...item.extra || {},
|
|
14959
|
-
...content.metadata
|
|
14960
|
-
};
|
|
14961
|
-
return sessionChunks.map((sc) => ({
|
|
14962
|
-
chunkId: sc.chunkId,
|
|
14963
|
-
itemId: sc.sessionId,
|
|
14964
|
-
sourceType: "session",
|
|
14965
|
-
// Empty title is preferable to "Session abc12345" placeholder text:
|
|
14966
|
-
// the latter pollutes search results and gets surfaced in the UI as
|
|
14967
|
-
// a misleading heading. Downstream renderers fall back to
|
|
14968
|
-
// project path / time when title is empty.
|
|
14969
|
-
title: sc.firstPrompt.slice(0, 100),
|
|
14970
|
-
text: sc.text,
|
|
14971
|
-
chunkType: sc.chunkType,
|
|
14972
|
-
projectPath: sc.projectPath,
|
|
14973
|
-
filePath: sc.sourceFile,
|
|
14974
|
-
mtime: sc.mtime
|
|
14975
|
-
}));
|
|
14976
|
-
}
|
|
14977
|
-
async extractLinks(item) {
|
|
14978
|
-
if (item.filePath) {
|
|
14979
|
-
try {
|
|
14980
|
-
const { detectForkPredecessor: detectForkPredecessor2 } = await Promise.resolve().then(() => (init_raw(), raw_exports));
|
|
14981
|
-
const predecessor = detectForkPredecessor2(item.filePath);
|
|
14982
|
-
if (predecessor) {
|
|
14983
|
-
return [{
|
|
14984
|
-
sourceType: "session",
|
|
14985
|
-
sourceId: item.id,
|
|
14986
|
-
targetType: "session",
|
|
14987
|
-
targetId: predecessor,
|
|
14988
|
-
linkType: "forked_from",
|
|
14989
|
-
confidence: 1
|
|
14990
|
-
}];
|
|
14991
|
-
}
|
|
14992
|
-
} catch {
|
|
14993
|
-
}
|
|
14994
|
-
}
|
|
14995
|
-
return [];
|
|
14996
|
-
}
|
|
14997
|
-
entryToItem(entry, sessionPath) {
|
|
14998
|
-
return {
|
|
14999
|
-
id: entry.sessionId,
|
|
15000
|
-
sourceType: "session",
|
|
15001
|
-
// Empty title when there's no first prompt — the UI then knows to
|
|
15002
|
-
// fall back to summary or project path instead of rendering the
|
|
15003
|
-
// useless "Session abc12345" placeholder as a heading.
|
|
15004
|
-
title: entry.firstPrompt ? entry.firstPrompt.replace(/\n/g, " ").trim().slice(0, 100) : "",
|
|
15005
|
-
projectPath: entry.projectPath,
|
|
15006
|
-
filePath: sessionPath,
|
|
15007
|
-
mtime: entry.fileMtime,
|
|
15008
|
-
contentPreview: entry.firstPrompt?.slice(0, 200),
|
|
15009
|
-
extra: {
|
|
15010
|
-
messageCount: entry.messageCount,
|
|
15011
|
-
gitBranch: entry.gitBranch,
|
|
15012
|
-
created: entry.created,
|
|
15013
|
-
modified: entry.modified,
|
|
15014
|
-
isSidechain: entry.isSidechain
|
|
15015
|
-
}
|
|
15016
|
-
};
|
|
15017
|
-
}
|
|
15018
|
-
itemToEntry(item) {
|
|
15019
|
-
const extra = item.extra || {};
|
|
15020
|
-
return {
|
|
15021
|
-
sessionId: item.id,
|
|
15022
|
-
fullPath: item.filePath,
|
|
15023
|
-
fileMtime: item.mtime,
|
|
15024
|
-
firstPrompt: item.contentPreview || "",
|
|
15025
|
-
messageCount: extra.messageCount || 0,
|
|
15026
|
-
created: extra.created || "",
|
|
15027
|
-
modified: extra.modified || "",
|
|
15028
|
-
gitBranch: extra.gitBranch || "",
|
|
15029
|
-
projectPath: item.projectPath,
|
|
15030
|
-
isSidechain: extra.isSidechain || false
|
|
15031
|
-
};
|
|
15032
|
-
}
|
|
15033
|
-
};
|
|
15034
|
-
}
|
|
15035
|
-
});
|
|
15036
|
-
|
|
15037
14638
|
// ../engine/dist/core/utils.js
|
|
15038
14639
|
import { existsSync as existsSync21, readdirSync as readdirSync15 } from "fs";
|
|
15039
14640
|
import { homedir as homedir6 } from "os";
|
|
@@ -18390,7 +17991,6 @@ var init_plugins_source = __esm({
|
|
|
18390
17991
|
|
|
18391
17992
|
// ../engine/dist/parsers/all-sources.js
|
|
18392
17993
|
function buildSourceRegistry(registry = new SourceRegistry()) {
|
|
18393
|
-
registry.register(new SessionSource());
|
|
18394
17994
|
registry.register(new PlanSource());
|
|
18395
17995
|
registry.register(new TaskSource());
|
|
18396
17996
|
registry.register(new ClaudeMdSource());
|
|
@@ -18414,7 +18014,6 @@ var init_all_sources = __esm({
|
|
|
18414
18014
|
"../engine/dist/parsers/all-sources.js"() {
|
|
18415
18015
|
"use strict";
|
|
18416
18016
|
init_source_registry();
|
|
18417
|
-
init_session_source();
|
|
18418
18017
|
init_plan_source();
|
|
18419
18018
|
init_task_source();
|
|
18420
18019
|
init_claude_md_source();
|
|
@@ -18858,7 +18457,7 @@ var init_http = __esm({
|
|
|
18858
18457
|
CLI_VERSION = JSON.parse(readFileSync31(new URL("../package.json", import.meta.url), "utf-8")).version || CLI_VERSION;
|
|
18859
18458
|
} catch {
|
|
18860
18459
|
try {
|
|
18861
|
-
if (true) CLI_VERSION = "0.
|
|
18460
|
+
if (true) CLI_VERSION = "0.7.0";
|
|
18862
18461
|
} catch {
|
|
18863
18462
|
}
|
|
18864
18463
|
}
|
|
@@ -19357,7 +18956,7 @@ var init_telemetry = __esm({
|
|
|
19357
18956
|
init_sync_client();
|
|
19358
18957
|
cliVersion2 = () => {
|
|
19359
18958
|
try {
|
|
19360
|
-
return true ? "0.
|
|
18959
|
+
return true ? "0.7.0" : "dev";
|
|
19361
18960
|
} catch {
|
|
19362
18961
|
return "dev";
|
|
19363
18962
|
}
|
|
@@ -21525,7 +21124,7 @@ var init_sync_client = __esm({
|
|
|
21525
21124
|
ownVersion = JSON.parse(readFileSync35(join42(dir, "../package.json"), "utf-8")).version || ownVersion;
|
|
21526
21125
|
} catch {
|
|
21527
21126
|
try {
|
|
21528
|
-
if (true) ownVersion = "0.
|
|
21127
|
+
if (true) ownVersion = "0.7.0";
|
|
21529
21128
|
} catch {
|
|
21530
21129
|
}
|
|
21531
21130
|
}
|
|
@@ -25641,7 +25240,7 @@ var init_intent_drain = __esm({
|
|
|
25641
25240
|
ownVersion2 = JSON.parse(readFileSync45(join56(dir, "../package.json"), "utf-8")).version || ownVersion2;
|
|
25642
25241
|
} catch {
|
|
25643
25242
|
try {
|
|
25644
|
-
if (true) ownVersion2 = "0.
|
|
25243
|
+
if (true) ownVersion2 = "0.7.0";
|
|
25645
25244
|
} catch {
|
|
25646
25245
|
}
|
|
25647
25246
|
}
|
|
@@ -28013,6 +27612,7 @@ var DEFAULT_ALLOW = [
|
|
|
28013
27612
|
"recall_user_prompts",
|
|
28014
27613
|
"recall_decision_record",
|
|
28015
27614
|
"recall_decisions",
|
|
27615
|
+
"recall_decision_scan",
|
|
28016
27616
|
"recall_analytics_summary",
|
|
28017
27617
|
"recall_outcome_summary",
|
|
28018
27618
|
"recall_regenerate_summary",
|