@threadbase-sh/streamer 1.27.1 → 1.27.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +1081 -804
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +51 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +51 -4
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -99922,8 +99922,8 @@ var require_pattern = __commonJS({
|
|
|
99922
99922
|
}
|
|
99923
99923
|
exports2.endsWithSlashGlobStar = endsWithSlashGlobStar;
|
|
99924
99924
|
function isAffectDepthOfReadingPattern(pattern) {
|
|
99925
|
-
const
|
|
99926
|
-
return endsWithSlashGlobStar(pattern) || isStaticPattern(
|
|
99925
|
+
const basename12 = path2.basename(pattern);
|
|
99926
|
+
return endsWithSlashGlobStar(pattern) || isStaticPattern(basename12);
|
|
99927
99927
|
}
|
|
99928
99928
|
exports2.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
|
|
99929
99929
|
function expandPatternsWithBraceExpansion(patterns2) {
|
|
@@ -100397,11 +100397,11 @@ var require_out = __commonJS({
|
|
|
100397
100397
|
async.read(path2, getSettings(optionsOrSettingsOrCallback), callback);
|
|
100398
100398
|
}
|
|
100399
100399
|
exports2.stat = stat10;
|
|
100400
|
-
function
|
|
100400
|
+
function statSync10(path2, optionsOrSettings) {
|
|
100401
100401
|
const settings = getSettings(optionsOrSettings);
|
|
100402
100402
|
return sync.read(path2, settings);
|
|
100403
100403
|
}
|
|
100404
|
-
exports2.statSync =
|
|
100404
|
+
exports2.statSync = statSync10;
|
|
100405
100405
|
function getSettings(settingsOrOptions = {}) {
|
|
100406
100406
|
if (settingsOrOptions instanceof settings_1.default) {
|
|
100407
100407
|
return settingsOrOptions;
|
|
@@ -123750,14 +123750,14 @@ __export(prompt_exports, {
|
|
|
123750
123750
|
interactivePermissionModePrompt: () => interactivePermissionModePrompt,
|
|
123751
123751
|
interactivePrompt: () => interactivePrompt
|
|
123752
123752
|
});
|
|
123753
|
-
var import_node_process2,
|
|
123753
|
+
var import_node_process2, import_promises20, interactivePrompt, interactivePermissionModePrompt;
|
|
123754
123754
|
var init_prompt = __esm({
|
|
123755
123755
|
"src/lifecycle/prompt.ts"() {
|
|
123756
123756
|
"use strict";
|
|
123757
123757
|
import_node_process2 = require("process");
|
|
123758
|
-
|
|
123758
|
+
import_promises20 = require("readline/promises");
|
|
123759
123759
|
interactivePrompt = async ({ prodPort, suggestedAltPort, prodActive }) => {
|
|
123760
|
-
const rl = (0,
|
|
123760
|
+
const rl = (0, import_promises20.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
|
|
123761
123761
|
try {
|
|
123762
123762
|
if (!prodActive) {
|
|
123763
123763
|
import_node_process2.stdout.write(
|
|
@@ -123792,7 +123792,7 @@ The supervised prod streamer is already holding port ${prodPort}.
|
|
|
123792
123792
|
}
|
|
123793
123793
|
};
|
|
123794
123794
|
interactivePermissionModePrompt = async () => {
|
|
123795
|
-
const rl = (0,
|
|
123795
|
+
const rl = (0, import_promises20.createInterface)({ input: import_node_process2.stdin, output: import_node_process2.stdout });
|
|
123796
123796
|
try {
|
|
123797
123797
|
import_node_process2.stdout.write(
|
|
123798
123798
|
"\nWhich permission mode should spawned Claude Code sessions use?\n [a] acceptEdits \u2014 auto-approve file edits, still prompt for shell commands (default)\n [m] manual \u2014 prompt for every edit and command\n"
|
|
@@ -128528,35 +128528,39 @@ var flexsearch_bundle_module_min_default = { Index: N, Document: U, Worker: S, r
|
|
|
128528
128528
|
|
|
128529
128529
|
// node_modules/@threadbase-sh/scanner/dist/index.js
|
|
128530
128530
|
var import_fs5 = require("fs");
|
|
128531
|
-
var import_promises4 = require("fs/promises");
|
|
128532
|
-
var import_os4 = require("os");
|
|
128533
128531
|
var import_path3 = require("path");
|
|
128534
|
-
var import_fast_glob = __toESM(require_out4(), 1);
|
|
128535
|
-
var import_fs6 = require("fs");
|
|
128536
|
-
var import_promises5 = require("fs/promises");
|
|
128537
|
-
var import_path4 = require("path");
|
|
128538
128532
|
var import_readline = require("readline");
|
|
128539
|
-
var
|
|
128540
|
-
var
|
|
128533
|
+
var import_path4 = require("path");
|
|
128534
|
+
var import_fs6 = require("fs");
|
|
128535
|
+
var import_promises4 = require("fs/promises");
|
|
128536
|
+
var import_os4 = require("os");
|
|
128541
128537
|
var import_path5 = require("path");
|
|
128538
|
+
var import_fast_glob = __toESM(require_out4(), 1);
|
|
128542
128539
|
var import_fs7 = require("fs");
|
|
128540
|
+
var import_promises5 = require("fs/promises");
|
|
128543
128541
|
var import_path6 = require("path");
|
|
128544
128542
|
var import_readline2 = require("readline");
|
|
128543
|
+
var import_fast_glob2 = __toESM(require_out4(), 1);
|
|
128544
|
+
var import_promises6 = require("fs/promises");
|
|
128545
128545
|
var import_events2 = require("events");
|
|
128546
128546
|
var import_fs8 = require("fs");
|
|
128547
128547
|
var import_os5 = require("os");
|
|
128548
128548
|
var import_path7 = require("path");
|
|
128549
|
-
var
|
|
128549
|
+
var import_path8 = require("path");
|
|
128550
128550
|
var import_fs9 = require("fs");
|
|
128551
|
+
var import_promises7 = require("timers/promises");
|
|
128551
128552
|
var import_fs10 = require("fs");
|
|
128552
|
-
var
|
|
128553
|
-
var
|
|
128553
|
+
var import_promises8 = require("timers/promises");
|
|
128554
|
+
var import_crypto2 = require("crypto");
|
|
128554
128555
|
var import_fs11 = require("fs");
|
|
128555
|
-
var import_path8 = require("path");
|
|
128556
|
-
var import_promises7 = require("fs/promises");
|
|
128557
128556
|
var import_fs12 = require("fs");
|
|
128558
128557
|
var import_fs13 = require("fs");
|
|
128558
|
+
var import_readline3 = require("readline");
|
|
128559
|
+
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
128560
|
+
var import_fs14 = require("fs");
|
|
128559
128561
|
var import_path9 = require("path");
|
|
128562
|
+
var import_promises9 = require("fs/promises");
|
|
128563
|
+
var import_path10 = require("path");
|
|
128560
128564
|
|
|
128561
128565
|
// node_modules/@threadbase-sh/scanner/node_modules/chokidar/esm/index.js
|
|
128562
128566
|
var import_fs3 = require("fs");
|
|
@@ -128711,10 +128715,10 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
128711
128715
|
}
|
|
128712
128716
|
async _formatEntry(dirent, path2) {
|
|
128713
128717
|
let entry;
|
|
128714
|
-
const
|
|
128718
|
+
const basename12 = this._isDirent ? dirent.name : dirent;
|
|
128715
128719
|
try {
|
|
128716
|
-
const fullPath = (0, import_node_path5.resolve)((0, import_node_path5.join)(path2,
|
|
128717
|
-
entry = { path: (0, import_node_path5.relative)(this._root, fullPath), fullPath, basename:
|
|
128720
|
+
const fullPath = (0, import_node_path5.resolve)((0, import_node_path5.join)(path2, basename12));
|
|
128721
|
+
entry = { path: (0, import_node_path5.relative)(this._root, fullPath), fullPath, basename: basename12 };
|
|
128718
128722
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
128719
128723
|
} catch (err) {
|
|
128720
128724
|
this._onError(err);
|
|
@@ -129253,9 +129257,9 @@ var NodeFsHandler = class {
|
|
|
129253
129257
|
_watchWithNodeFs(path2, listener) {
|
|
129254
129258
|
const opts = this.fsw.options;
|
|
129255
129259
|
const directory = sysPath.dirname(path2);
|
|
129256
|
-
const
|
|
129260
|
+
const basename12 = sysPath.basename(path2);
|
|
129257
129261
|
const parent = this.fsw._getWatchedDir(directory);
|
|
129258
|
-
parent.add(
|
|
129262
|
+
parent.add(basename12);
|
|
129259
129263
|
const absolutePath = sysPath.resolve(path2);
|
|
129260
129264
|
const options = {
|
|
129261
129265
|
persistent: opts.persistent
|
|
@@ -129265,7 +129269,7 @@ var NodeFsHandler = class {
|
|
|
129265
129269
|
let closer;
|
|
129266
129270
|
if (opts.usePolling) {
|
|
129267
129271
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
129268
|
-
options.interval = enableBin && isBinaryPath(
|
|
129272
|
+
options.interval = enableBin && isBinaryPath(basename12) ? opts.binaryInterval : opts.interval;
|
|
129269
129273
|
closer = setFsWatchFileListener(path2, absolutePath, options, {
|
|
129270
129274
|
listener,
|
|
129271
129275
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -129288,10 +129292,10 @@ var NodeFsHandler = class {
|
|
|
129288
129292
|
return;
|
|
129289
129293
|
}
|
|
129290
129294
|
const dirname17 = sysPath.dirname(file2);
|
|
129291
|
-
const
|
|
129295
|
+
const basename12 = sysPath.basename(file2);
|
|
129292
129296
|
const parent = this.fsw._getWatchedDir(dirname17);
|
|
129293
129297
|
let prevStats = stats;
|
|
129294
|
-
if (parent.has(
|
|
129298
|
+
if (parent.has(basename12))
|
|
129295
129299
|
return;
|
|
129296
129300
|
const listener = async (path2, newStats) => {
|
|
129297
129301
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
@@ -129316,9 +129320,9 @@ var NodeFsHandler = class {
|
|
|
129316
129320
|
prevStats = newStats2;
|
|
129317
129321
|
}
|
|
129318
129322
|
} catch (error51) {
|
|
129319
|
-
this.fsw._remove(dirname17,
|
|
129323
|
+
this.fsw._remove(dirname17, basename12);
|
|
129320
129324
|
}
|
|
129321
|
-
} else if (parent.has(
|
|
129325
|
+
} else if (parent.has(basename12)) {
|
|
129322
129326
|
const at2 = newStats.atimeMs;
|
|
129323
129327
|
const mt2 = newStats.mtimeMs;
|
|
129324
129328
|
if (!at2 || at2 <= mt2 || mt2 !== prevStats.mtimeMs) {
|
|
@@ -130514,6 +130518,435 @@ var SearchIndexer = class {
|
|
|
130514
130518
|
getLogger2().trace("indexer: cleared");
|
|
130515
130519
|
}
|
|
130516
130520
|
};
|
|
130521
|
+
var CLAUDE_CODE_PROVIDER = "claude-code";
|
|
130522
|
+
var CODEX_CLI_PROVIDER = "codex-cli";
|
|
130523
|
+
function initialReducerState() {
|
|
130524
|
+
return {
|
|
130525
|
+
sessionId: "",
|
|
130526
|
+
sessionName: "",
|
|
130527
|
+
latestTimestamp: "",
|
|
130528
|
+
cwd: "",
|
|
130529
|
+
teamName: "",
|
|
130530
|
+
model: null,
|
|
130531
|
+
messageCount: 0,
|
|
130532
|
+
lastMessageSender: "user",
|
|
130533
|
+
isTeammate: false,
|
|
130534
|
+
firstUserSeen: false,
|
|
130535
|
+
firstMessage: null,
|
|
130536
|
+
lastMessage: null,
|
|
130537
|
+
lastPrompt: "",
|
|
130538
|
+
pageMessageCount: 0,
|
|
130539
|
+
toolNames: [],
|
|
130540
|
+
previewParts: [],
|
|
130541
|
+
snippetParts: [],
|
|
130542
|
+
previewLength: 0,
|
|
130543
|
+
snippetLength: 0,
|
|
130544
|
+
badJsonLines: 0
|
|
130545
|
+
};
|
|
130546
|
+
}
|
|
130547
|
+
function reduceLine(state, entry, tier) {
|
|
130548
|
+
if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
|
|
130549
|
+
if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
|
|
130550
|
+
if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
|
|
130551
|
+
if (entry.teamName && !state.teamName) state.teamName = entry.teamName;
|
|
130552
|
+
if (entry.timestamp) {
|
|
130553
|
+
const ts2 = entry.timestamp;
|
|
130554
|
+
if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
|
|
130555
|
+
}
|
|
130556
|
+
const type = entry.type;
|
|
130557
|
+
if (type === "last-prompt") {
|
|
130558
|
+
if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
|
|
130559
|
+
return;
|
|
130560
|
+
}
|
|
130561
|
+
if (type !== "user" && type !== "assistant") return;
|
|
130562
|
+
if (entry.isMeta) return;
|
|
130563
|
+
const msg = entry.message;
|
|
130564
|
+
if (state.model === null && msg?.model) state.model = msg.model;
|
|
130565
|
+
if (type === "user" && !state.firstUserSeen) {
|
|
130566
|
+
state.firstUserSeen = true;
|
|
130567
|
+
if (isTeammateContent(msg?.content)) state.isTeammate = true;
|
|
130568
|
+
}
|
|
130569
|
+
const content = extractTextContent(msg?.content);
|
|
130570
|
+
const hasToolUseResult = type === "user" && entry.toolUseResult != null;
|
|
130571
|
+
const isOnlyToolResult = hasToolUseResult && isOnlyToolResultContent(msg?.content);
|
|
130572
|
+
const toolSet = new Set(state.toolNames);
|
|
130573
|
+
collectToolNames(msg?.content, toolSet);
|
|
130574
|
+
state.toolNames = Array.from(toolSet);
|
|
130575
|
+
const toolUseBlocks = extractToolUseBlocks(msg?.content);
|
|
130576
|
+
const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
|
|
130577
|
+
const hasThinking = !!(thinking?.content || thinking?.signature);
|
|
130578
|
+
if (content || isOnlyToolResult || toolUseBlocks.length > 0 || hasThinking) {
|
|
130579
|
+
state.pageMessageCount++;
|
|
130580
|
+
}
|
|
130581
|
+
if (content || isOnlyToolResult) {
|
|
130582
|
+
state.messageCount++;
|
|
130583
|
+
state.lastMessageSender = type;
|
|
130584
|
+
if (content) {
|
|
130585
|
+
const ts2 = entry.timestamp || "";
|
|
130586
|
+
if (!state.firstMessage) state.firstMessage = { text: content.slice(0, 200), timestamp: ts2 };
|
|
130587
|
+
state.lastMessage = { text: content.slice(0, 200), timestamp: ts2 };
|
|
130588
|
+
if (state.previewLength < tier.previewMax) {
|
|
130589
|
+
state.previewParts.push(content);
|
|
130590
|
+
state.previewLength += content.length;
|
|
130591
|
+
}
|
|
130592
|
+
if (state.snippetLength < tier.snippetMax) {
|
|
130593
|
+
const remaining = tier.snippetMax - state.snippetLength;
|
|
130594
|
+
const chunk = content.length > remaining ? content.slice(0, remaining) : content;
|
|
130595
|
+
state.snippetParts.push(chunk);
|
|
130596
|
+
state.snippetLength += chunk.length;
|
|
130597
|
+
}
|
|
130598
|
+
}
|
|
130599
|
+
}
|
|
130600
|
+
}
|
|
130601
|
+
function finalizeMeta(state, filePath, account, tier) {
|
|
130602
|
+
if (state.messageCount === 0) return null;
|
|
130603
|
+
const isSubagent = filePath.includes("/subagents/");
|
|
130604
|
+
let parentSessionId = null;
|
|
130605
|
+
if (isSubagent) {
|
|
130606
|
+
const uuidDir = (0, import_path4.dirname)((0, import_path4.dirname)(filePath));
|
|
130607
|
+
parentSessionId = (0, import_path4.join)((0, import_path4.dirname)(uuidDir), `${(0, import_path4.basename)(uuidDir)}.jsonl`);
|
|
130608
|
+
}
|
|
130609
|
+
const projectPath = state.cwd;
|
|
130610
|
+
return {
|
|
130611
|
+
id: filePath,
|
|
130612
|
+
filePath,
|
|
130613
|
+
provider: CLAUDE_CODE_PROVIDER,
|
|
130614
|
+
sessionId: state.sessionId || (0, import_path4.basename)(filePath, ".jsonl"),
|
|
130615
|
+
sessionName: state.sessionName,
|
|
130616
|
+
projectPath,
|
|
130617
|
+
projectName: getShortProjectName(projectPath),
|
|
130618
|
+
account,
|
|
130619
|
+
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
130620
|
+
messageCount: state.messageCount,
|
|
130621
|
+
lastMessageSender: state.lastMessageSender,
|
|
130622
|
+
preview: state.previewParts.join(" ").slice(0, tier.previewMax),
|
|
130623
|
+
contentSnippet: state.snippetParts.join(" "),
|
|
130624
|
+
gitBranch: null,
|
|
130625
|
+
model: state.model,
|
|
130626
|
+
isSubagent,
|
|
130627
|
+
parentSessionId,
|
|
130628
|
+
isTeammate: state.isTeammate,
|
|
130629
|
+
teamName: state.teamName || null,
|
|
130630
|
+
toolNames: state.toolNames,
|
|
130631
|
+
firstMessage: state.firstMessage,
|
|
130632
|
+
lastMessage: state.lastMessage,
|
|
130633
|
+
lastPrompt: state.lastPrompt || void 0
|
|
130634
|
+
};
|
|
130635
|
+
}
|
|
130636
|
+
function getShortProjectName(fullPath) {
|
|
130637
|
+
const parts = fullPath.split("/").filter(Boolean);
|
|
130638
|
+
return parts.slice(-3).join("/");
|
|
130639
|
+
}
|
|
130640
|
+
var SYSTEM_TAGS = [
|
|
130641
|
+
"system-reminder",
|
|
130642
|
+
"command-name",
|
|
130643
|
+
"command-message",
|
|
130644
|
+
"command-args",
|
|
130645
|
+
"ide_selection",
|
|
130646
|
+
"ide_opened_file",
|
|
130647
|
+
"local-command-stdout",
|
|
130648
|
+
"local-command-caveat",
|
|
130649
|
+
"retrieval_status",
|
|
130650
|
+
"task_id",
|
|
130651
|
+
"task_type",
|
|
130652
|
+
"task-id",
|
|
130653
|
+
"task-notification",
|
|
130654
|
+
"fast_mode_info",
|
|
130655
|
+
"persisted-output",
|
|
130656
|
+
"tool_use_error",
|
|
130657
|
+
"user-prompt-submit-hook",
|
|
130658
|
+
"thinking",
|
|
130659
|
+
"ask_user",
|
|
130660
|
+
"teammate-message"
|
|
130661
|
+
];
|
|
130662
|
+
var SYSTEM_TAG_RE = new RegExp(`<(${SYSTEM_TAGS.join("|")})[^>]*>[\\s\\S]*?<\\/\\1>`, "g");
|
|
130663
|
+
function cleanSystemTags(text) {
|
|
130664
|
+
return text.replace(SYSTEM_TAG_RE, "").replace(/[^\S\n]+/g, " ").replace(/\n{3,}/g, "\n\n").trim();
|
|
130665
|
+
}
|
|
130666
|
+
async function parseMeta(filePath, account, tier) {
|
|
130667
|
+
const log8 = getLogger2();
|
|
130668
|
+
log8.trace({ filePath, account, tier: tier.name }, "parseMeta: start");
|
|
130669
|
+
const state = initialReducerState();
|
|
130670
|
+
const fileStream = (0, import_fs5.createReadStream)(filePath);
|
|
130671
|
+
const rl = (0, import_readline.createInterface)({ input: fileStream, crlfDelay: Infinity });
|
|
130672
|
+
try {
|
|
130673
|
+
for await (const line of rl) {
|
|
130674
|
+
if (!line.trim()) continue;
|
|
130675
|
+
let entry;
|
|
130676
|
+
try {
|
|
130677
|
+
entry = JSON.parse(line);
|
|
130678
|
+
} catch {
|
|
130679
|
+
state.badJsonLines++;
|
|
130680
|
+
continue;
|
|
130681
|
+
}
|
|
130682
|
+
reduceLine(state, entry, tier);
|
|
130683
|
+
}
|
|
130684
|
+
} catch (err) {
|
|
130685
|
+
log8.warn({ filePath, err }, "parseMeta: read failed");
|
|
130686
|
+
return null;
|
|
130687
|
+
}
|
|
130688
|
+
if (state.badJsonLines > 0) {
|
|
130689
|
+
log8.warn(
|
|
130690
|
+
{ filePath, badJsonLines: state.badJsonLines },
|
|
130691
|
+
"parseMeta: skipped malformed JSON lines"
|
|
130692
|
+
);
|
|
130693
|
+
}
|
|
130694
|
+
const meta3 = finalizeMeta(state, filePath, account, tier);
|
|
130695
|
+
if (!meta3) log8.trace({ filePath }, "parseMeta: no messages");
|
|
130696
|
+
return meta3;
|
|
130697
|
+
}
|
|
130698
|
+
async function parseConversation(filePath, account) {
|
|
130699
|
+
const log8 = getLogger2();
|
|
130700
|
+
log8.trace({ filePath, account }, "parseConversation: start");
|
|
130701
|
+
const messages = [];
|
|
130702
|
+
let badJsonLines = 0;
|
|
130703
|
+
const textParts = [];
|
|
130704
|
+
const turnDurations = [];
|
|
130705
|
+
const state = initialConvState();
|
|
130706
|
+
const fileStream = (0, import_fs5.createReadStream)(filePath);
|
|
130707
|
+
const rl = (0, import_readline.createInterface)({ input: fileStream, crlfDelay: Infinity });
|
|
130708
|
+
try {
|
|
130709
|
+
for await (const line of rl) {
|
|
130710
|
+
if (!line.trim()) continue;
|
|
130711
|
+
let entry;
|
|
130712
|
+
try {
|
|
130713
|
+
entry = JSON.parse(line);
|
|
130714
|
+
} catch {
|
|
130715
|
+
badJsonLines++;
|
|
130716
|
+
continue;
|
|
130717
|
+
}
|
|
130718
|
+
if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
|
|
130719
|
+
turnDurations.push({
|
|
130720
|
+
durationMs: entry.durationMs,
|
|
130721
|
+
messageCount: entry.messageCount || 0,
|
|
130722
|
+
uuid: entry.uuid
|
|
130723
|
+
});
|
|
130724
|
+
continue;
|
|
130725
|
+
}
|
|
130726
|
+
const message = reduceConvLine(state, entry);
|
|
130727
|
+
if (message) {
|
|
130728
|
+
messages.push(message);
|
|
130729
|
+
if (message.text) textParts.push(message.text);
|
|
130730
|
+
}
|
|
130731
|
+
}
|
|
130732
|
+
} catch (err) {
|
|
130733
|
+
log8.warn({ filePath, err }, "parseConversation: read failed");
|
|
130734
|
+
return null;
|
|
130735
|
+
}
|
|
130736
|
+
if (badJsonLines > 0) {
|
|
130737
|
+
log8.warn({ filePath, badJsonLines }, "parseConversation: skipped malformed JSON lines");
|
|
130738
|
+
}
|
|
130739
|
+
if (messages.length === 0) {
|
|
130740
|
+
log8.trace({ filePath }, "parseConversation: no messages");
|
|
130741
|
+
return null;
|
|
130742
|
+
}
|
|
130743
|
+
log8.debug({ filePath, messageCount: messages.length }, "parseConversation: complete");
|
|
130744
|
+
applyTeamInfo(messages, state);
|
|
130745
|
+
return {
|
|
130746
|
+
id: filePath,
|
|
130747
|
+
filePath,
|
|
130748
|
+
projectPath: state.cwd,
|
|
130749
|
+
projectName: getShortProjectName2(state.cwd),
|
|
130750
|
+
sessionId: state.sessionId || (0, import_path3.basename)(filePath, ".jsonl"),
|
|
130751
|
+
sessionName: state.sessionName,
|
|
130752
|
+
messages,
|
|
130753
|
+
fullText: textParts.join(" "),
|
|
130754
|
+
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
130755
|
+
messageCount: messages.length,
|
|
130756
|
+
account,
|
|
130757
|
+
turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
|
|
130758
|
+
lastPrompt: state.lastPrompt || void 0
|
|
130759
|
+
};
|
|
130760
|
+
}
|
|
130761
|
+
function extractTextContent(content) {
|
|
130762
|
+
if (!content) return "";
|
|
130763
|
+
if (typeof content === "string") return cleanSystemTags(content);
|
|
130764
|
+
if (Array.isArray(content)) {
|
|
130765
|
+
return content.map((item) => {
|
|
130766
|
+
if (typeof item === "string") return item;
|
|
130767
|
+
if (item?.type === "text" && item?.text) return item.text;
|
|
130768
|
+
if (item?.type === "tool_result" && typeof item?.content === "string") return item.content;
|
|
130769
|
+
return "";
|
|
130770
|
+
}).filter(Boolean).map(cleanSystemTags).join(" ");
|
|
130771
|
+
}
|
|
130772
|
+
return "";
|
|
130773
|
+
}
|
|
130774
|
+
function extractToolUseNames(content) {
|
|
130775
|
+
if (!Array.isArray(content)) return [];
|
|
130776
|
+
return content.filter((item) => item?.type === "tool_use" && item?.name).map((item) => item.name);
|
|
130777
|
+
}
|
|
130778
|
+
function extractToolUseBlocks(content) {
|
|
130779
|
+
if (!Array.isArray(content)) return [];
|
|
130780
|
+
return content.filter((item) => item?.type === "tool_use" && item?.name && item?.id).map((item) => ({
|
|
130781
|
+
id: item.id,
|
|
130782
|
+
name: item.name,
|
|
130783
|
+
input: item.input || {}
|
|
130784
|
+
}));
|
|
130785
|
+
}
|
|
130786
|
+
var TOOL_NAME_TO_TYPE = {
|
|
130787
|
+
Edit: "edit",
|
|
130788
|
+
Write: "write",
|
|
130789
|
+
Read: "read",
|
|
130790
|
+
Bash: "bash",
|
|
130791
|
+
Grep: "grep",
|
|
130792
|
+
Glob: "glob",
|
|
130793
|
+
Agent: "taskAgent",
|
|
130794
|
+
TaskCreate: "taskCreate",
|
|
130795
|
+
TaskUpdate: "taskUpdate"
|
|
130796
|
+
};
|
|
130797
|
+
function extractToolResultBlocks(content, pendingToolUses) {
|
|
130798
|
+
if (!Array.isArray(content)) return [];
|
|
130799
|
+
return content.filter((item) => item?.type === "tool_result" && item?.tool_use_id).map((item) => {
|
|
130800
|
+
const toolName = pendingToolUses.get(item.tool_use_id)?.name ?? "";
|
|
130801
|
+
return {
|
|
130802
|
+
toolUseId: item.tool_use_id,
|
|
130803
|
+
type: TOOL_NAME_TO_TYPE[toolName] ?? "generic",
|
|
130804
|
+
content: typeof item.content === "string" ? { text: item.content } : item.content ?? {},
|
|
130805
|
+
isError: typeof item.is_error === "boolean" ? item.is_error : void 0
|
|
130806
|
+
};
|
|
130807
|
+
});
|
|
130808
|
+
}
|
|
130809
|
+
function collectToolNames(content, toolSet) {
|
|
130810
|
+
if (!Array.isArray(content)) return;
|
|
130811
|
+
for (const item of content) {
|
|
130812
|
+
if (item?.type === "tool_use" && item?.name) {
|
|
130813
|
+
toolSet.add(item.name);
|
|
130814
|
+
}
|
|
130815
|
+
}
|
|
130816
|
+
}
|
|
130817
|
+
function isOnlyToolResultContent(content) {
|
|
130818
|
+
if (!Array.isArray(content)) return false;
|
|
130819
|
+
return content.length > 0 && content.every((item) => item?.type === "tool_result");
|
|
130820
|
+
}
|
|
130821
|
+
function isTeammateContent(content) {
|
|
130822
|
+
const raw2 = typeof content === "string" ? content : Array.isArray(content) ? content.map(
|
|
130823
|
+
(item) => typeof item === "string" ? item : item?.type === "text" ? item.text ?? "" : ""
|
|
130824
|
+
).join("") : "";
|
|
130825
|
+
return raw2.includes("<teammate-message");
|
|
130826
|
+
}
|
|
130827
|
+
function extractThinking(content) {
|
|
130828
|
+
if (!Array.isArray(content)) return { content: "", signature: "" };
|
|
130829
|
+
const blocks = content.filter((item) => item?.type === "thinking");
|
|
130830
|
+
return {
|
|
130831
|
+
content: blocks.map((b2) => b2.thinking).filter(Boolean).join("\n\n"),
|
|
130832
|
+
signature: blocks.map((b2) => b2.signature).filter(Boolean).join("")
|
|
130833
|
+
};
|
|
130834
|
+
}
|
|
130835
|
+
function hasImageBlocks(content) {
|
|
130836
|
+
if (!Array.isArray(content)) return false;
|
|
130837
|
+
return content.some(
|
|
130838
|
+
(item) => item?.type === "image" && (item?.source?.type === "base64" || item?.file?.base64 !== void 0)
|
|
130839
|
+
);
|
|
130840
|
+
}
|
|
130841
|
+
function parseTeammateMessageTag(content) {
|
|
130842
|
+
const match2 = content.match(/<teammate-message\s+([^>]*)>/);
|
|
130843
|
+
if (!match2) return null;
|
|
130844
|
+
const attrs = match2[1];
|
|
130845
|
+
const id = attrs.match(/teammate_id="([^"]*)"/)?.[1];
|
|
130846
|
+
if (!id) return null;
|
|
130847
|
+
const summary = attrs.match(/summary="([^"]*)"/)?.[1];
|
|
130848
|
+
const color = attrs.match(/color="([^"]*)"/)?.[1];
|
|
130849
|
+
return { teammateId: id, summary, color };
|
|
130850
|
+
}
|
|
130851
|
+
function getShortProjectName2(fullPath) {
|
|
130852
|
+
const parts = fullPath.split("/").filter(Boolean);
|
|
130853
|
+
return parts.slice(-3).join("/");
|
|
130854
|
+
}
|
|
130855
|
+
function initialConvState() {
|
|
130856
|
+
return {
|
|
130857
|
+
cwd: "",
|
|
130858
|
+
sessionId: "",
|
|
130859
|
+
sessionName: "",
|
|
130860
|
+
latestTimestamp: "",
|
|
130861
|
+
lastPrompt: "",
|
|
130862
|
+
pendingToolUses: {},
|
|
130863
|
+
teamInfo: {}
|
|
130864
|
+
};
|
|
130865
|
+
}
|
|
130866
|
+
function reduceConvLine(state, entry) {
|
|
130867
|
+
if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
|
|
130868
|
+
if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
|
|
130869
|
+
if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
|
|
130870
|
+
if (entry.timestamp) {
|
|
130871
|
+
const ts2 = entry.timestamp;
|
|
130872
|
+
if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
|
|
130873
|
+
}
|
|
130874
|
+
const type = entry.type;
|
|
130875
|
+
if (type === "last-prompt") {
|
|
130876
|
+
if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
|
|
130877
|
+
return null;
|
|
130878
|
+
}
|
|
130879
|
+
if (type !== "user" && type !== "assistant") return null;
|
|
130880
|
+
if (entry.isMeta) return null;
|
|
130881
|
+
const msg = entry.message;
|
|
130882
|
+
const toolUseBlocks = extractToolUseBlocks(msg?.content);
|
|
130883
|
+
for (const block of toolUseBlocks) state.pendingToolUses[block.id] = block;
|
|
130884
|
+
const hasToolUseResult = type === "user" && entry.toolUseResult != null;
|
|
130885
|
+
const isToolResultOnly = hasToolUseResult && isOnlyToolResultContent(msg?.content);
|
|
130886
|
+
const content = extractTextContent(msg?.content);
|
|
130887
|
+
const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
|
|
130888
|
+
const hasThinking = !!(thinking?.content || thinking?.signature);
|
|
130889
|
+
if (!(content || isToolResultOnly || toolUseBlocks.length > 0 || hasThinking)) return null;
|
|
130890
|
+
const metadata = {};
|
|
130891
|
+
if (msg?.model) metadata.model = msg.model;
|
|
130892
|
+
if (msg?.stop_reason !== void 0) metadata.stopReason = msg.stop_reason;
|
|
130893
|
+
if (entry.gitBranch) metadata.gitBranch = entry.gitBranch;
|
|
130894
|
+
if (entry.version) metadata.version = entry.version;
|
|
130895
|
+
const usage = msg?.usage;
|
|
130896
|
+
if (usage) {
|
|
130897
|
+
if (usage.input_tokens) metadata.inputTokens = usage.input_tokens;
|
|
130898
|
+
if (usage.output_tokens) metadata.outputTokens = usage.output_tokens;
|
|
130899
|
+
if (usage.cache_read_input_tokens) metadata.cacheReadTokens = usage.cache_read_input_tokens;
|
|
130900
|
+
if (usage.cache_creation_input_tokens)
|
|
130901
|
+
metadata.cacheCreationTokens = usage.cache_creation_input_tokens;
|
|
130902
|
+
}
|
|
130903
|
+
const toolUseNames = extractToolUseNames(msg?.content);
|
|
130904
|
+
if (toolUseNames.length > 0) metadata.toolUses = toolUseNames;
|
|
130905
|
+
if (toolUseBlocks.length > 0) metadata.toolUseBlocks = toolUseBlocks;
|
|
130906
|
+
if (isToolResultOnly) {
|
|
130907
|
+
const pending = new Map(Object.entries(state.pendingToolUses));
|
|
130908
|
+
const toolResultBlocks = extractToolResultBlocks(msg?.content, pending);
|
|
130909
|
+
if (toolResultBlocks.length > 0) {
|
|
130910
|
+
metadata.toolResults = toolResultBlocks;
|
|
130911
|
+
for (const block of toolResultBlocks) delete state.pendingToolUses[block.toolUseId];
|
|
130912
|
+
}
|
|
130913
|
+
}
|
|
130914
|
+
if (entry.teamName) {
|
|
130915
|
+
metadata.teamName = entry.teamName;
|
|
130916
|
+
if (!state.teamInfo[metadata.teamName] && content) {
|
|
130917
|
+
const info = parseTeammateMessageTag(content);
|
|
130918
|
+
if (info) state.teamInfo[metadata.teamName] = info;
|
|
130919
|
+
}
|
|
130920
|
+
}
|
|
130921
|
+
const thinkingContent = thinking?.content || void 0;
|
|
130922
|
+
const thinkingSignature = thinking?.signature || void 0;
|
|
130923
|
+
const hasMetadata = Object.keys(metadata).length > 0;
|
|
130924
|
+
return {
|
|
130925
|
+
role: type,
|
|
130926
|
+
text: content || "",
|
|
130927
|
+
timestamp: entry.timestamp || "",
|
|
130928
|
+
uuid: entry.uuid || void 0,
|
|
130929
|
+
metadata: hasMetadata ? metadata : void 0,
|
|
130930
|
+
isToolResult: isToolResultOnly || void 0,
|
|
130931
|
+
isThinking: thinkingContent || thinkingSignature ? true : void 0,
|
|
130932
|
+
thinkingContent,
|
|
130933
|
+
thinkingSignature,
|
|
130934
|
+
parentUuid: entry.parentUuid !== void 0 ? entry.parentUuid : void 0,
|
|
130935
|
+
requestId: type === "assistant" ? entry.requestId : void 0,
|
|
130936
|
+
promptId: type === "user" ? entry.promptId : void 0,
|
|
130937
|
+
isSidechain: typeof entry.isSidechain === "boolean" ? entry.isSidechain : void 0,
|
|
130938
|
+
permissionMode: type === "user" ? entry.permissionMode : void 0,
|
|
130939
|
+
hasImages: hasImageBlocks(msg?.content) || void 0,
|
|
130940
|
+
attachment: entry.attachment !== void 0 ? entry.attachment : void 0
|
|
130941
|
+
};
|
|
130942
|
+
}
|
|
130943
|
+
function applyTeamInfo(messages, state) {
|
|
130944
|
+
if (Object.keys(state.teamInfo).length === 0) return;
|
|
130945
|
+
for (const m2 of messages) {
|
|
130946
|
+
const name = m2.metadata?.teamName;
|
|
130947
|
+
if (name && state.teamInfo[name] && m2.metadata) m2.metadata.teamInfo = state.teamInfo[name];
|
|
130948
|
+
}
|
|
130949
|
+
}
|
|
130517
130950
|
var SIDECAR_VERSION = 1;
|
|
130518
130951
|
function sidecarPath(jsonlPath) {
|
|
130519
130952
|
return `${jsonlPath}.idx.json`;
|
|
@@ -130539,7 +130972,7 @@ function buildSidecar(meta3, cursor, updatedAt) {
|
|
|
130539
130972
|
}
|
|
130540
130973
|
function writeSidecar(jsonlPath, sidecar) {
|
|
130541
130974
|
try {
|
|
130542
|
-
(0,
|
|
130975
|
+
(0, import_fs6.writeFileSync)(sidecarPath(jsonlPath), JSON.stringify(sidecar, null, 2));
|
|
130543
130976
|
} catch (err) {
|
|
130544
130977
|
getLogger2().warn({ jsonlPath, err }, "sidecar: write failed");
|
|
130545
130978
|
}
|
|
@@ -130549,13 +130982,13 @@ function resolveConfigDir(configDir2) {
|
|
|
130549
130982
|
return configDir2.replace(/^~/, (0, import_os4.homedir)());
|
|
130550
130983
|
}
|
|
130551
130984
|
function getProjectsDir(profile) {
|
|
130552
|
-
return (0,
|
|
130985
|
+
return (0, import_path5.join)(resolveConfigDir(profile.configDir), "projects");
|
|
130553
130986
|
}
|
|
130554
130987
|
async function detectDefaultProfile() {
|
|
130555
130988
|
return {
|
|
130556
130989
|
id: "default",
|
|
130557
130990
|
label: "Default",
|
|
130558
|
-
configDir: (0,
|
|
130991
|
+
configDir: (0, import_path5.join)((0, import_os4.homedir)(), ".claude"),
|
|
130559
130992
|
enabled: true,
|
|
130560
130993
|
emoji: "\u{1F916}"
|
|
130561
130994
|
};
|
|
@@ -130564,7 +130997,7 @@ async function loadProfiles(configPath) {
|
|
|
130564
130997
|
const log8 = getLogger2();
|
|
130565
130998
|
try {
|
|
130566
130999
|
const resolved = resolveConfigDir(configPath);
|
|
130567
|
-
const data = await (0, import_promises4.readFile)((0,
|
|
131000
|
+
const data = await (0, import_promises4.readFile)((0, import_path5.join)(resolved, PROFILES_FILE), "utf-8");
|
|
130568
131001
|
const profiles = JSON.parse(data);
|
|
130569
131002
|
log8.debug({ configPath, count: profiles.length }, "profiles: loaded");
|
|
130570
131003
|
return profiles;
|
|
@@ -130574,34 +131007,6 @@ async function loadProfiles(configPath) {
|
|
|
130574
131007
|
return [defaultProfile];
|
|
130575
131008
|
}
|
|
130576
131009
|
}
|
|
130577
|
-
var SYSTEM_TAGS = [
|
|
130578
|
-
"system-reminder",
|
|
130579
|
-
"command-name",
|
|
130580
|
-
"command-message",
|
|
130581
|
-
"command-args",
|
|
130582
|
-
"ide_selection",
|
|
130583
|
-
"ide_opened_file",
|
|
130584
|
-
"local-command-stdout",
|
|
130585
|
-
"local-command-caveat",
|
|
130586
|
-
"retrieval_status",
|
|
130587
|
-
"task_id",
|
|
130588
|
-
"task_type",
|
|
130589
|
-
"task-id",
|
|
130590
|
-
"task-notification",
|
|
130591
|
-
"fast_mode_info",
|
|
130592
|
-
"persisted-output",
|
|
130593
|
-
"tool_use_error",
|
|
130594
|
-
"user-prompt-submit-hook",
|
|
130595
|
-
"thinking",
|
|
130596
|
-
"ask_user",
|
|
130597
|
-
"teammate-message"
|
|
130598
|
-
];
|
|
130599
|
-
var SYSTEM_TAG_RE = new RegExp(`<(${SYSTEM_TAGS.join("|")})[^>]*>[\\s\\S]*?<\\/\\1>`, "g");
|
|
130600
|
-
function cleanSystemTags(text) {
|
|
130601
|
-
return text.replace(SYSTEM_TAG_RE, "").replace(/[^\S\n]+/g, " ").replace(/\n{3,}/g, "\n\n").trim();
|
|
130602
|
-
}
|
|
130603
|
-
var CLAUDE_CODE_PROVIDER = "claude-code";
|
|
130604
|
-
var CODEX_CLI_PROVIDER = "codex-cli";
|
|
130605
131010
|
var CodexCliProvider = class {
|
|
130606
131011
|
name = CODEX_CLI_PROVIDER;
|
|
130607
131012
|
async discover(roots) {
|
|
@@ -130734,7 +131139,7 @@ function reduceCodexEntry(acc, entry, tier) {
|
|
|
130734
131139
|
}
|
|
130735
131140
|
function finalizeCodexMeta(acc, filePath, account, tier) {
|
|
130736
131141
|
if (acc.messageCount === 0) return null;
|
|
130737
|
-
const sessionId = acc.sessionId || (0,
|
|
131142
|
+
const sessionId = acc.sessionId || (0, import_path6.basename)(filePath, ".jsonl");
|
|
130738
131143
|
const projectPath = acc.cwd;
|
|
130739
131144
|
const kind = acc.lastAssistant === null && acc.toolNames.length > 0 ? "task" : "conversation";
|
|
130740
131145
|
return {
|
|
@@ -130746,7 +131151,7 @@ function finalizeCodexMeta(acc, filePath, account, tier) {
|
|
|
130746
131151
|
sessionId,
|
|
130747
131152
|
sessionName: "",
|
|
130748
131153
|
projectPath,
|
|
130749
|
-
projectName:
|
|
131154
|
+
projectName: getShortProjectName3(projectPath),
|
|
130750
131155
|
account,
|
|
130751
131156
|
timestamp: acc.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
130752
131157
|
messageCount: acc.messageCount,
|
|
@@ -130765,7 +131170,7 @@ function finalizeCodexMeta(acc, filePath, account, tier) {
|
|
|
130765
131170
|
lastPrompt: acc.lastUser?.text || void 0
|
|
130766
131171
|
};
|
|
130767
131172
|
}
|
|
130768
|
-
function
|
|
131173
|
+
function getShortProjectName3(fullPath) {
|
|
130769
131174
|
return fullPath.split("/").filter(Boolean).slice(-3).join("/");
|
|
130770
131175
|
}
|
|
130771
131176
|
async function parseCodexConversation(filePath, account) {
|
|
@@ -130776,7 +131181,7 @@ async function parseCodexConversation(filePath, account) {
|
|
|
130776
131181
|
let cwd = "";
|
|
130777
131182
|
let latestTimestamp = "";
|
|
130778
131183
|
let lastUserText = "";
|
|
130779
|
-
const rl = (0,
|
|
131184
|
+
const rl = (0, import_readline2.createInterface)({ input: (0, import_fs7.createReadStream)(filePath), crlfDelay: Infinity });
|
|
130780
131185
|
try {
|
|
130781
131186
|
for await (const line of rl) {
|
|
130782
131187
|
if (!line.trim()) continue;
|
|
@@ -130813,8 +131218,8 @@ async function parseCodexConversation(filePath, account) {
|
|
|
130813
131218
|
id: filePath,
|
|
130814
131219
|
filePath,
|
|
130815
131220
|
projectPath: cwd,
|
|
130816
|
-
projectName:
|
|
130817
|
-
sessionId: sessionId || (0,
|
|
131221
|
+
projectName: getShortProjectName3(cwd),
|
|
131222
|
+
sessionId: sessionId || (0, import_path6.basename)(filePath, ".jsonl"),
|
|
130818
131223
|
sessionName: "",
|
|
130819
131224
|
messages,
|
|
130820
131225
|
fullText: textParts.join(" "),
|
|
@@ -130886,404 +131291,6 @@ async function discoverJsonlFiles(dirs, onProgress) {
|
|
|
130886
131291
|
log8.debug({ totalFiles: results.length, dirs: dirs.length }, "discovery: complete");
|
|
130887
131292
|
return results;
|
|
130888
131293
|
}
|
|
130889
|
-
function initialConvState() {
|
|
130890
|
-
return {
|
|
130891
|
-
cwd: "",
|
|
130892
|
-
sessionId: "",
|
|
130893
|
-
sessionName: "",
|
|
130894
|
-
latestTimestamp: "",
|
|
130895
|
-
lastPrompt: "",
|
|
130896
|
-
pendingToolUses: {},
|
|
130897
|
-
teamInfo: {}
|
|
130898
|
-
};
|
|
130899
|
-
}
|
|
130900
|
-
function reduceConvLine(state, entry) {
|
|
130901
|
-
if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
|
|
130902
|
-
if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
|
|
130903
|
-
if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
|
|
130904
|
-
if (entry.timestamp) {
|
|
130905
|
-
const ts2 = entry.timestamp;
|
|
130906
|
-
if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
|
|
130907
|
-
}
|
|
130908
|
-
const type = entry.type;
|
|
130909
|
-
if (type === "last-prompt") {
|
|
130910
|
-
if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
|
|
130911
|
-
return null;
|
|
130912
|
-
}
|
|
130913
|
-
if (type !== "user" && type !== "assistant") return null;
|
|
130914
|
-
if (entry.isMeta) return null;
|
|
130915
|
-
const msg = entry.message;
|
|
130916
|
-
const toolUseBlocks = extractToolUseBlocks(msg?.content);
|
|
130917
|
-
for (const block of toolUseBlocks) state.pendingToolUses[block.id] = block;
|
|
130918
|
-
const hasToolUseResult = type === "user" && entry.toolUseResult != null;
|
|
130919
|
-
const isToolResultOnly = hasToolUseResult && isOnlyToolResultContent(msg?.content);
|
|
130920
|
-
const content = extractTextContent(msg?.content);
|
|
130921
|
-
const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
|
|
130922
|
-
const hasThinking = !!(thinking?.content || thinking?.signature);
|
|
130923
|
-
if (!(content || isToolResultOnly || toolUseBlocks.length > 0 || hasThinking)) return null;
|
|
130924
|
-
const metadata = {};
|
|
130925
|
-
if (msg?.model) metadata.model = msg.model;
|
|
130926
|
-
if (msg?.stop_reason !== void 0) metadata.stopReason = msg.stop_reason;
|
|
130927
|
-
if (entry.gitBranch) metadata.gitBranch = entry.gitBranch;
|
|
130928
|
-
if (entry.version) metadata.version = entry.version;
|
|
130929
|
-
const usage = msg?.usage;
|
|
130930
|
-
if (usage) {
|
|
130931
|
-
if (usage.input_tokens) metadata.inputTokens = usage.input_tokens;
|
|
130932
|
-
if (usage.output_tokens) metadata.outputTokens = usage.output_tokens;
|
|
130933
|
-
if (usage.cache_read_input_tokens) metadata.cacheReadTokens = usage.cache_read_input_tokens;
|
|
130934
|
-
if (usage.cache_creation_input_tokens)
|
|
130935
|
-
metadata.cacheCreationTokens = usage.cache_creation_input_tokens;
|
|
130936
|
-
}
|
|
130937
|
-
const toolUseNames = extractToolUseNames(msg?.content);
|
|
130938
|
-
if (toolUseNames.length > 0) metadata.toolUses = toolUseNames;
|
|
130939
|
-
if (toolUseBlocks.length > 0) metadata.toolUseBlocks = toolUseBlocks;
|
|
130940
|
-
if (isToolResultOnly) {
|
|
130941
|
-
const pending = new Map(Object.entries(state.pendingToolUses));
|
|
130942
|
-
const toolResultBlocks = extractToolResultBlocks(msg?.content, pending);
|
|
130943
|
-
if (toolResultBlocks.length > 0) metadata.toolResults = toolResultBlocks;
|
|
130944
|
-
}
|
|
130945
|
-
if (entry.teamName) {
|
|
130946
|
-
metadata.teamName = entry.teamName;
|
|
130947
|
-
if (!state.teamInfo[metadata.teamName] && content) {
|
|
130948
|
-
const info = parseTeammateMessageTag(content);
|
|
130949
|
-
if (info) state.teamInfo[metadata.teamName] = info;
|
|
130950
|
-
}
|
|
130951
|
-
}
|
|
130952
|
-
const thinkingContent = thinking?.content || void 0;
|
|
130953
|
-
const thinkingSignature = thinking?.signature || void 0;
|
|
130954
|
-
const hasMetadata = Object.keys(metadata).length > 0;
|
|
130955
|
-
return {
|
|
130956
|
-
role: type,
|
|
130957
|
-
text: content || "",
|
|
130958
|
-
timestamp: entry.timestamp || "",
|
|
130959
|
-
uuid: entry.uuid || void 0,
|
|
130960
|
-
metadata: hasMetadata ? metadata : void 0,
|
|
130961
|
-
isToolResult: isToolResultOnly || void 0,
|
|
130962
|
-
isThinking: thinkingContent || thinkingSignature ? true : void 0,
|
|
130963
|
-
thinkingContent,
|
|
130964
|
-
thinkingSignature,
|
|
130965
|
-
parentUuid: entry.parentUuid !== void 0 ? entry.parentUuid : void 0,
|
|
130966
|
-
requestId: type === "assistant" ? entry.requestId : void 0,
|
|
130967
|
-
promptId: type === "user" ? entry.promptId : void 0,
|
|
130968
|
-
isSidechain: typeof entry.isSidechain === "boolean" ? entry.isSidechain : void 0,
|
|
130969
|
-
permissionMode: type === "user" ? entry.permissionMode : void 0,
|
|
130970
|
-
hasImages: hasImageBlocks(msg?.content) || void 0,
|
|
130971
|
-
attachment: entry.attachment !== void 0 ? entry.attachment : void 0
|
|
130972
|
-
};
|
|
130973
|
-
}
|
|
130974
|
-
function applyTeamInfo(messages, state) {
|
|
130975
|
-
if (Object.keys(state.teamInfo).length === 0) return;
|
|
130976
|
-
for (const m2 of messages) {
|
|
130977
|
-
const name = m2.metadata?.teamName;
|
|
130978
|
-
if (name && state.teamInfo[name] && m2.metadata) m2.metadata.teamInfo = state.teamInfo[name];
|
|
130979
|
-
}
|
|
130980
|
-
}
|
|
130981
|
-
async function parseMeta(filePath, account, tier) {
|
|
130982
|
-
const log8 = getLogger2();
|
|
130983
|
-
log8.trace({ filePath, account, tier: tier.name }, "parseMeta: start");
|
|
130984
|
-
const state = initialReducerState();
|
|
130985
|
-
const fileStream = (0, import_fs7.createReadStream)(filePath);
|
|
130986
|
-
const rl = (0, import_readline2.createInterface)({ input: fileStream, crlfDelay: Infinity });
|
|
130987
|
-
try {
|
|
130988
|
-
for await (const line of rl) {
|
|
130989
|
-
if (!line.trim()) continue;
|
|
130990
|
-
let entry;
|
|
130991
|
-
try {
|
|
130992
|
-
entry = JSON.parse(line);
|
|
130993
|
-
} catch {
|
|
130994
|
-
state.badJsonLines++;
|
|
130995
|
-
continue;
|
|
130996
|
-
}
|
|
130997
|
-
reduceLine(state, entry, tier);
|
|
130998
|
-
}
|
|
130999
|
-
} catch (err) {
|
|
131000
|
-
log8.warn({ filePath, err }, "parseMeta: read failed");
|
|
131001
|
-
return null;
|
|
131002
|
-
}
|
|
131003
|
-
if (state.badJsonLines > 0) {
|
|
131004
|
-
log8.warn(
|
|
131005
|
-
{ filePath, badJsonLines: state.badJsonLines },
|
|
131006
|
-
"parseMeta: skipped malformed JSON lines"
|
|
131007
|
-
);
|
|
131008
|
-
}
|
|
131009
|
-
const meta3 = finalizeMeta(state, filePath, account, tier);
|
|
131010
|
-
if (!meta3) log8.trace({ filePath }, "parseMeta: no messages");
|
|
131011
|
-
return meta3;
|
|
131012
|
-
}
|
|
131013
|
-
async function parseConversation(filePath, account) {
|
|
131014
|
-
const log8 = getLogger2();
|
|
131015
|
-
log8.trace({ filePath, account }, "parseConversation: start");
|
|
131016
|
-
const messages = [];
|
|
131017
|
-
let badJsonLines = 0;
|
|
131018
|
-
const textParts = [];
|
|
131019
|
-
const turnDurations = [];
|
|
131020
|
-
const state = initialConvState();
|
|
131021
|
-
const fileStream = (0, import_fs7.createReadStream)(filePath);
|
|
131022
|
-
const rl = (0, import_readline2.createInterface)({ input: fileStream, crlfDelay: Infinity });
|
|
131023
|
-
try {
|
|
131024
|
-
for await (const line of rl) {
|
|
131025
|
-
if (!line.trim()) continue;
|
|
131026
|
-
let entry;
|
|
131027
|
-
try {
|
|
131028
|
-
entry = JSON.parse(line);
|
|
131029
|
-
} catch {
|
|
131030
|
-
badJsonLines++;
|
|
131031
|
-
continue;
|
|
131032
|
-
}
|
|
131033
|
-
if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
|
|
131034
|
-
turnDurations.push({
|
|
131035
|
-
durationMs: entry.durationMs,
|
|
131036
|
-
messageCount: entry.messageCount || 0,
|
|
131037
|
-
uuid: entry.uuid
|
|
131038
|
-
});
|
|
131039
|
-
continue;
|
|
131040
|
-
}
|
|
131041
|
-
const message = reduceConvLine(state, entry);
|
|
131042
|
-
if (message) {
|
|
131043
|
-
messages.push(message);
|
|
131044
|
-
if (message.text) textParts.push(message.text);
|
|
131045
|
-
}
|
|
131046
|
-
}
|
|
131047
|
-
} catch (err) {
|
|
131048
|
-
log8.warn({ filePath, err }, "parseConversation: read failed");
|
|
131049
|
-
return null;
|
|
131050
|
-
}
|
|
131051
|
-
if (badJsonLines > 0) {
|
|
131052
|
-
log8.warn({ filePath, badJsonLines }, "parseConversation: skipped malformed JSON lines");
|
|
131053
|
-
}
|
|
131054
|
-
if (messages.length === 0) {
|
|
131055
|
-
log8.trace({ filePath }, "parseConversation: no messages");
|
|
131056
|
-
return null;
|
|
131057
|
-
}
|
|
131058
|
-
log8.debug({ filePath, messageCount: messages.length }, "parseConversation: complete");
|
|
131059
|
-
applyTeamInfo(messages, state);
|
|
131060
|
-
return {
|
|
131061
|
-
id: filePath,
|
|
131062
|
-
filePath,
|
|
131063
|
-
projectPath: state.cwd,
|
|
131064
|
-
projectName: getShortProjectName2(state.cwd),
|
|
131065
|
-
sessionId: state.sessionId || (0, import_path6.basename)(filePath, ".jsonl"),
|
|
131066
|
-
sessionName: state.sessionName,
|
|
131067
|
-
messages,
|
|
131068
|
-
fullText: textParts.join(" "),
|
|
131069
|
-
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
131070
|
-
messageCount: messages.length,
|
|
131071
|
-
account,
|
|
131072
|
-
turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
|
|
131073
|
-
lastPrompt: state.lastPrompt || void 0
|
|
131074
|
-
};
|
|
131075
|
-
}
|
|
131076
|
-
function extractTextContent(content) {
|
|
131077
|
-
if (!content) return "";
|
|
131078
|
-
if (typeof content === "string") return cleanSystemTags(content);
|
|
131079
|
-
if (Array.isArray(content)) {
|
|
131080
|
-
return content.map((item) => {
|
|
131081
|
-
if (typeof item === "string") return item;
|
|
131082
|
-
if (item?.type === "text" && item?.text) return item.text;
|
|
131083
|
-
if (item?.type === "tool_result" && typeof item?.content === "string") return item.content;
|
|
131084
|
-
return "";
|
|
131085
|
-
}).filter(Boolean).map(cleanSystemTags).join(" ");
|
|
131086
|
-
}
|
|
131087
|
-
return "";
|
|
131088
|
-
}
|
|
131089
|
-
function extractToolUseNames(content) {
|
|
131090
|
-
if (!Array.isArray(content)) return [];
|
|
131091
|
-
return content.filter((item) => item?.type === "tool_use" && item?.name).map((item) => item.name);
|
|
131092
|
-
}
|
|
131093
|
-
function extractToolUseBlocks(content) {
|
|
131094
|
-
if (!Array.isArray(content)) return [];
|
|
131095
|
-
return content.filter((item) => item?.type === "tool_use" && item?.name && item?.id).map((item) => ({
|
|
131096
|
-
id: item.id,
|
|
131097
|
-
name: item.name,
|
|
131098
|
-
input: item.input || {}
|
|
131099
|
-
}));
|
|
131100
|
-
}
|
|
131101
|
-
var TOOL_NAME_TO_TYPE = {
|
|
131102
|
-
Edit: "edit",
|
|
131103
|
-
Write: "write",
|
|
131104
|
-
Read: "read",
|
|
131105
|
-
Bash: "bash",
|
|
131106
|
-
Grep: "grep",
|
|
131107
|
-
Glob: "glob",
|
|
131108
|
-
Agent: "taskAgent",
|
|
131109
|
-
TaskCreate: "taskCreate",
|
|
131110
|
-
TaskUpdate: "taskUpdate"
|
|
131111
|
-
};
|
|
131112
|
-
function extractToolResultBlocks(content, pendingToolUses) {
|
|
131113
|
-
if (!Array.isArray(content)) return [];
|
|
131114
|
-
return content.filter((item) => item?.type === "tool_result" && item?.tool_use_id).map((item) => {
|
|
131115
|
-
const toolName = pendingToolUses.get(item.tool_use_id)?.name ?? "";
|
|
131116
|
-
return {
|
|
131117
|
-
toolUseId: item.tool_use_id,
|
|
131118
|
-
type: TOOL_NAME_TO_TYPE[toolName] ?? "generic",
|
|
131119
|
-
content: typeof item.content === "string" ? { text: item.content } : item.content ?? {},
|
|
131120
|
-
isError: typeof item.is_error === "boolean" ? item.is_error : void 0
|
|
131121
|
-
};
|
|
131122
|
-
});
|
|
131123
|
-
}
|
|
131124
|
-
function collectToolNames(content, toolSet) {
|
|
131125
|
-
if (!Array.isArray(content)) return;
|
|
131126
|
-
for (const item of content) {
|
|
131127
|
-
if (item?.type === "tool_use" && item?.name) {
|
|
131128
|
-
toolSet.add(item.name);
|
|
131129
|
-
}
|
|
131130
|
-
}
|
|
131131
|
-
}
|
|
131132
|
-
function isOnlyToolResultContent(content) {
|
|
131133
|
-
if (!Array.isArray(content)) return false;
|
|
131134
|
-
return content.length > 0 && content.every((item) => item?.type === "tool_result");
|
|
131135
|
-
}
|
|
131136
|
-
function isTeammateContent(content) {
|
|
131137
|
-
const raw2 = typeof content === "string" ? content : Array.isArray(content) ? content.map(
|
|
131138
|
-
(item) => typeof item === "string" ? item : item?.type === "text" ? item.text ?? "" : ""
|
|
131139
|
-
).join("") : "";
|
|
131140
|
-
return raw2.includes("<teammate-message");
|
|
131141
|
-
}
|
|
131142
|
-
function extractThinking(content) {
|
|
131143
|
-
if (!Array.isArray(content)) return { content: "", signature: "" };
|
|
131144
|
-
const blocks = content.filter((item) => item?.type === "thinking");
|
|
131145
|
-
return {
|
|
131146
|
-
content: blocks.map((b2) => b2.thinking).filter(Boolean).join("\n\n"),
|
|
131147
|
-
signature: blocks.map((b2) => b2.signature).filter(Boolean).join("")
|
|
131148
|
-
};
|
|
131149
|
-
}
|
|
131150
|
-
function hasImageBlocks(content) {
|
|
131151
|
-
if (!Array.isArray(content)) return false;
|
|
131152
|
-
return content.some(
|
|
131153
|
-
(item) => item?.type === "image" && (item?.source?.type === "base64" || item?.file?.base64 !== void 0)
|
|
131154
|
-
);
|
|
131155
|
-
}
|
|
131156
|
-
function parseTeammateMessageTag(content) {
|
|
131157
|
-
const match2 = content.match(/<teammate-message\s+([^>]*)>/);
|
|
131158
|
-
if (!match2) return null;
|
|
131159
|
-
const attrs = match2[1];
|
|
131160
|
-
const id = attrs.match(/teammate_id="([^"]*)"/)?.[1];
|
|
131161
|
-
if (!id) return null;
|
|
131162
|
-
const summary = attrs.match(/summary="([^"]*)"/)?.[1];
|
|
131163
|
-
const color = attrs.match(/color="([^"]*)"/)?.[1];
|
|
131164
|
-
return { teammateId: id, summary, color };
|
|
131165
|
-
}
|
|
131166
|
-
function getShortProjectName2(fullPath) {
|
|
131167
|
-
const parts = fullPath.split("/").filter(Boolean);
|
|
131168
|
-
return parts.slice(-3).join("/");
|
|
131169
|
-
}
|
|
131170
|
-
function initialReducerState() {
|
|
131171
|
-
return {
|
|
131172
|
-
sessionId: "",
|
|
131173
|
-
sessionName: "",
|
|
131174
|
-
latestTimestamp: "",
|
|
131175
|
-
cwd: "",
|
|
131176
|
-
teamName: "",
|
|
131177
|
-
model: null,
|
|
131178
|
-
messageCount: 0,
|
|
131179
|
-
lastMessageSender: "user",
|
|
131180
|
-
isTeammate: false,
|
|
131181
|
-
firstUserSeen: false,
|
|
131182
|
-
firstMessage: null,
|
|
131183
|
-
lastMessage: null,
|
|
131184
|
-
lastPrompt: "",
|
|
131185
|
-
pageMessageCount: 0,
|
|
131186
|
-
toolNames: [],
|
|
131187
|
-
previewParts: [],
|
|
131188
|
-
snippetParts: [],
|
|
131189
|
-
previewLength: 0,
|
|
131190
|
-
snippetLength: 0,
|
|
131191
|
-
badJsonLines: 0
|
|
131192
|
-
};
|
|
131193
|
-
}
|
|
131194
|
-
function reduceLine(state, entry, tier) {
|
|
131195
|
-
if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
|
|
131196
|
-
if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
|
|
131197
|
-
if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
|
|
131198
|
-
if (entry.teamName && !state.teamName) state.teamName = entry.teamName;
|
|
131199
|
-
if (entry.timestamp) {
|
|
131200
|
-
const ts2 = entry.timestamp;
|
|
131201
|
-
if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
|
|
131202
|
-
}
|
|
131203
|
-
const type = entry.type;
|
|
131204
|
-
if (type === "last-prompt") {
|
|
131205
|
-
if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
|
|
131206
|
-
return;
|
|
131207
|
-
}
|
|
131208
|
-
if (type !== "user" && type !== "assistant") return;
|
|
131209
|
-
if (entry.isMeta) return;
|
|
131210
|
-
const msg = entry.message;
|
|
131211
|
-
if (state.model === null && msg?.model) state.model = msg.model;
|
|
131212
|
-
if (type === "user" && !state.firstUserSeen) {
|
|
131213
|
-
state.firstUserSeen = true;
|
|
131214
|
-
if (isTeammateContent(msg?.content)) state.isTeammate = true;
|
|
131215
|
-
}
|
|
131216
|
-
const content = extractTextContent(msg?.content);
|
|
131217
|
-
const hasToolUseResult = type === "user" && entry.toolUseResult != null;
|
|
131218
|
-
const isOnlyToolResult = hasToolUseResult && isOnlyToolResultContent(msg?.content);
|
|
131219
|
-
const toolSet = new Set(state.toolNames);
|
|
131220
|
-
collectToolNames(msg?.content, toolSet);
|
|
131221
|
-
state.toolNames = Array.from(toolSet);
|
|
131222
|
-
const toolUseBlocks = extractToolUseBlocks(msg?.content);
|
|
131223
|
-
const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
|
|
131224
|
-
const hasThinking = !!(thinking?.content || thinking?.signature);
|
|
131225
|
-
if (content || isOnlyToolResult || toolUseBlocks.length > 0 || hasThinking) {
|
|
131226
|
-
state.pageMessageCount++;
|
|
131227
|
-
}
|
|
131228
|
-
if (content || isOnlyToolResult) {
|
|
131229
|
-
state.messageCount++;
|
|
131230
|
-
state.lastMessageSender = type;
|
|
131231
|
-
if (content) {
|
|
131232
|
-
const ts2 = entry.timestamp || "";
|
|
131233
|
-
if (!state.firstMessage) state.firstMessage = { text: content.slice(0, 200), timestamp: ts2 };
|
|
131234
|
-
state.lastMessage = { text: content.slice(0, 200), timestamp: ts2 };
|
|
131235
|
-
if (state.previewLength < tier.previewMax) {
|
|
131236
|
-
state.previewParts.push(content);
|
|
131237
|
-
state.previewLength += content.length;
|
|
131238
|
-
}
|
|
131239
|
-
if (state.snippetLength < tier.snippetMax) {
|
|
131240
|
-
const remaining = tier.snippetMax - state.snippetLength;
|
|
131241
|
-
const chunk = content.length > remaining ? content.slice(0, remaining) : content;
|
|
131242
|
-
state.snippetParts.push(chunk);
|
|
131243
|
-
state.snippetLength += chunk.length;
|
|
131244
|
-
}
|
|
131245
|
-
}
|
|
131246
|
-
}
|
|
131247
|
-
}
|
|
131248
|
-
function finalizeMeta(state, filePath, account, tier) {
|
|
131249
|
-
if (state.messageCount === 0) return null;
|
|
131250
|
-
const isSubagent = filePath.includes("/subagents/");
|
|
131251
|
-
let parentSessionId = null;
|
|
131252
|
-
if (isSubagent) {
|
|
131253
|
-
const uuidDir = (0, import_path5.dirname)((0, import_path5.dirname)(filePath));
|
|
131254
|
-
parentSessionId = (0, import_path5.join)((0, import_path5.dirname)(uuidDir), `${(0, import_path5.basename)(uuidDir)}.jsonl`);
|
|
131255
|
-
}
|
|
131256
|
-
const projectPath = state.cwd;
|
|
131257
|
-
return {
|
|
131258
|
-
id: filePath,
|
|
131259
|
-
filePath,
|
|
131260
|
-
provider: CLAUDE_CODE_PROVIDER,
|
|
131261
|
-
sessionId: state.sessionId || (0, import_path5.basename)(filePath, ".jsonl"),
|
|
131262
|
-
sessionName: state.sessionName,
|
|
131263
|
-
projectPath,
|
|
131264
|
-
projectName: getShortProjectName3(projectPath),
|
|
131265
|
-
account,
|
|
131266
|
-
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
131267
|
-
messageCount: state.messageCount,
|
|
131268
|
-
lastMessageSender: state.lastMessageSender,
|
|
131269
|
-
preview: state.previewParts.join(" ").slice(0, tier.previewMax),
|
|
131270
|
-
contentSnippet: state.snippetParts.join(" "),
|
|
131271
|
-
gitBranch: null,
|
|
131272
|
-
model: state.model,
|
|
131273
|
-
isSubagent,
|
|
131274
|
-
parentSessionId,
|
|
131275
|
-
isTeammate: state.isTeammate,
|
|
131276
|
-
teamName: state.teamName || null,
|
|
131277
|
-
toolNames: state.toolNames,
|
|
131278
|
-
firstMessage: state.firstMessage,
|
|
131279
|
-
lastMessage: state.lastMessage,
|
|
131280
|
-
lastPrompt: state.lastPrompt || void 0
|
|
131281
|
-
};
|
|
131282
|
-
}
|
|
131283
|
-
function getShortProjectName3(fullPath) {
|
|
131284
|
-
const parts = fullPath.split("/").filter(Boolean);
|
|
131285
|
-
return parts.slice(-3).join("/");
|
|
131286
|
-
}
|
|
131287
131294
|
var ThreadbaseProvider = class {
|
|
131288
131295
|
name = CLAUDE_CODE_PROVIDER;
|
|
131289
131296
|
// Roots are passed as "<projectsDir>\0<account>" so the scanner can carry the
|
|
@@ -131352,32 +131359,219 @@ var LRUCache = class {
|
|
|
131352
131359
|
return this.map.size;
|
|
131353
131360
|
}
|
|
131354
131361
|
};
|
|
131362
|
+
var YIELD_EVERY_LINES = 500;
|
|
131363
|
+
async function tailReduce(filePath, startOffset, startLine, state, tier) {
|
|
131364
|
+
const stream = (0, import_fs10.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
|
|
131365
|
+
let buffer = "";
|
|
131366
|
+
let offset = startOffset;
|
|
131367
|
+
let line = startLine;
|
|
131368
|
+
let parsedLines = 0;
|
|
131369
|
+
let sinceYield = 0;
|
|
131370
|
+
for await (const chunk of stream) {
|
|
131371
|
+
buffer += chunk;
|
|
131372
|
+
let nl;
|
|
131373
|
+
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
131374
|
+
const lineWithNewline = buffer.slice(0, nl + 1);
|
|
131375
|
+
const text = lineWithNewline.trimEnd();
|
|
131376
|
+
buffer = buffer.slice(nl + 1);
|
|
131377
|
+
if (text.length > 0) {
|
|
131378
|
+
try {
|
|
131379
|
+
reduceLine(state, JSON.parse(text), tier);
|
|
131380
|
+
} catch {
|
|
131381
|
+
state.badJsonLines++;
|
|
131382
|
+
}
|
|
131383
|
+
parsedLines++;
|
|
131384
|
+
}
|
|
131385
|
+
offset += Buffer.byteLength(lineWithNewline, "utf8");
|
|
131386
|
+
line++;
|
|
131387
|
+
if (++sinceYield >= YIELD_EVERY_LINES) {
|
|
131388
|
+
sinceYield = 0;
|
|
131389
|
+
await (0, import_promises8.setImmediate)();
|
|
131390
|
+
}
|
|
131391
|
+
}
|
|
131392
|
+
}
|
|
131393
|
+
return { newOffset: offset, newLine: line, parsedLines, badJsonLines: state.badJsonLines };
|
|
131394
|
+
}
|
|
131395
|
+
var CHECKPOINT_INTERVAL = 500;
|
|
131396
|
+
async function streamMessages(filePath, startOffset, startLine, state, onMessage, onEntry) {
|
|
131397
|
+
const stream = (0, import_fs9.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
|
|
131398
|
+
let buffer = "";
|
|
131399
|
+
let offset = startOffset;
|
|
131400
|
+
let line = startLine;
|
|
131401
|
+
let sinceYield = 0;
|
|
131402
|
+
for await (const chunk of stream) {
|
|
131403
|
+
buffer += chunk;
|
|
131404
|
+
let nl;
|
|
131405
|
+
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
131406
|
+
const lineWithNewline = buffer.slice(0, nl + 1);
|
|
131407
|
+
const text = lineWithNewline.trimEnd();
|
|
131408
|
+
buffer = buffer.slice(nl + 1);
|
|
131409
|
+
offset += Buffer.byteLength(lineWithNewline, "utf8");
|
|
131410
|
+
line += 1;
|
|
131411
|
+
if (++sinceYield >= YIELD_EVERY_LINES) {
|
|
131412
|
+
sinceYield = 0;
|
|
131413
|
+
await (0, import_promises7.setImmediate)();
|
|
131414
|
+
}
|
|
131415
|
+
if (text.length === 0) continue;
|
|
131416
|
+
let entry;
|
|
131417
|
+
try {
|
|
131418
|
+
entry = JSON.parse(text);
|
|
131419
|
+
} catch {
|
|
131420
|
+
continue;
|
|
131421
|
+
}
|
|
131422
|
+
if (onEntry?.(entry)) continue;
|
|
131423
|
+
const message = reduceConvLine(state, entry);
|
|
131424
|
+
if (message && onMessage(message, offset, line)) {
|
|
131425
|
+
stream.destroy();
|
|
131426
|
+
return { offset, line };
|
|
131427
|
+
}
|
|
131428
|
+
}
|
|
131429
|
+
}
|
|
131430
|
+
return { offset, line };
|
|
131431
|
+
}
|
|
131432
|
+
async function buildCheckpoints(filePath, interval = CHECKPOINT_INTERVAL, from = null) {
|
|
131433
|
+
const checkpoints = [];
|
|
131434
|
+
const state = from ? from.state : initialConvState();
|
|
131435
|
+
let index = from ? from.messageIndex : 0;
|
|
131436
|
+
await streamMessages(
|
|
131437
|
+
filePath,
|
|
131438
|
+
from?.byteOffset ?? 0,
|
|
131439
|
+
from?.lineNumber ?? 0,
|
|
131440
|
+
state,
|
|
131441
|
+
(_msg, nextOffset, nextLine) => {
|
|
131442
|
+
index += 1;
|
|
131443
|
+
if (index % interval === 0) {
|
|
131444
|
+
checkpoints.push({
|
|
131445
|
+
messageIndex: index,
|
|
131446
|
+
byteOffset: nextOffset,
|
|
131447
|
+
lineNumber: nextLine,
|
|
131448
|
+
state: structuredClone(state)
|
|
131449
|
+
});
|
|
131450
|
+
}
|
|
131451
|
+
return false;
|
|
131452
|
+
}
|
|
131453
|
+
);
|
|
131454
|
+
return checkpoints;
|
|
131455
|
+
}
|
|
131456
|
+
async function readPage(filePath, total, options, floor) {
|
|
131457
|
+
const beforeIndex = options.beforeIndex ?? total;
|
|
131458
|
+
const fromIndex = Math.max(0, beforeIndex - options.limit);
|
|
131459
|
+
const state = floor ? structuredClone(floor.state) : initialConvState();
|
|
131460
|
+
const startOffset = floor ? floor.byteOffset : 0;
|
|
131461
|
+
const startLine = floor ? floor.lineNumber : 0;
|
|
131462
|
+
let index = floor ? floor.messageIndex : 0;
|
|
131463
|
+
const window2 = [];
|
|
131464
|
+
await streamMessages(filePath, startOffset, startLine, state, (message) => {
|
|
131465
|
+
const current = index;
|
|
131466
|
+
index += 1;
|
|
131467
|
+
if (current >= fromIndex && current < beforeIndex) window2.push(message);
|
|
131468
|
+
return index >= beforeIndex;
|
|
131469
|
+
});
|
|
131470
|
+
applyTeamInfo(window2, state);
|
|
131471
|
+
return { messages: window2, total, fromIndex };
|
|
131472
|
+
}
|
|
131473
|
+
async function foldTail(filePath, resume) {
|
|
131474
|
+
const messages = [];
|
|
131475
|
+
const textParts = [];
|
|
131476
|
+
const turnDurations = [];
|
|
131477
|
+
const end = await streamMessages(
|
|
131478
|
+
filePath,
|
|
131479
|
+
resume.offset,
|
|
131480
|
+
resume.line,
|
|
131481
|
+
resume.state,
|
|
131482
|
+
(message) => {
|
|
131483
|
+
messages.push(message);
|
|
131484
|
+
if (message.text) textParts.push(message.text);
|
|
131485
|
+
return false;
|
|
131486
|
+
},
|
|
131487
|
+
(entry) => {
|
|
131488
|
+
if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
|
|
131489
|
+
turnDurations.push({
|
|
131490
|
+
durationMs: entry.durationMs,
|
|
131491
|
+
messageCount: entry.messageCount || 0,
|
|
131492
|
+
uuid: entry.uuid
|
|
131493
|
+
});
|
|
131494
|
+
return true;
|
|
131495
|
+
}
|
|
131496
|
+
return false;
|
|
131497
|
+
}
|
|
131498
|
+
);
|
|
131499
|
+
return { messages, textParts, turnDurations, end };
|
|
131500
|
+
}
|
|
131501
|
+
function assemble(filePath, account, messages, fullText, turnDurations, state) {
|
|
131502
|
+
return {
|
|
131503
|
+
id: filePath,
|
|
131504
|
+
filePath,
|
|
131505
|
+
projectPath: state.cwd,
|
|
131506
|
+
projectName: getShortProjectName2(state.cwd),
|
|
131507
|
+
sessionId: state.sessionId || (0, import_path8.basename)(filePath, ".jsonl"),
|
|
131508
|
+
sessionName: state.sessionName,
|
|
131509
|
+
messages,
|
|
131510
|
+
fullText,
|
|
131511
|
+
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
131512
|
+
messageCount: messages.length,
|
|
131513
|
+
account,
|
|
131514
|
+
turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
|
|
131515
|
+
lastPrompt: state.lastPrompt || void 0
|
|
131516
|
+
};
|
|
131517
|
+
}
|
|
131518
|
+
async function parseConversationResumable(filePath, account) {
|
|
131519
|
+
const resume = { state: initialConvState(), offset: 0, line: 0 };
|
|
131520
|
+
const { messages, textParts, turnDurations, end } = await foldTail(filePath, resume);
|
|
131521
|
+
if (messages.length === 0) return null;
|
|
131522
|
+
applyTeamInfo(messages, resume.state);
|
|
131523
|
+
const conversation = assemble(
|
|
131524
|
+
filePath,
|
|
131525
|
+
account,
|
|
131526
|
+
messages,
|
|
131527
|
+
textParts.join(" "),
|
|
131528
|
+
turnDurations,
|
|
131529
|
+
resume.state
|
|
131530
|
+
);
|
|
131531
|
+
return { conversation, resume: { state: resume.state, offset: end.offset, line: end.line } };
|
|
131532
|
+
}
|
|
131533
|
+
async function extendConversation(previous, resume, filePath, account) {
|
|
131534
|
+
const { messages: fresh, textParts, turnDurations, end } = await foldTail(filePath, resume);
|
|
131535
|
+
const messages = fresh.length > 0 ? previous.messages.concat(fresh) : previous.messages;
|
|
131536
|
+
applyTeamInfo(messages, resume.state);
|
|
131537
|
+
const fullText = textParts.length === 0 ? previous.fullText : previous.fullText ? `${previous.fullText} ${textParts.join(" ")}` : textParts.join(" ");
|
|
131538
|
+
const allTurnDurations = (previous.turnDurations ?? []).concat(turnDurations);
|
|
131539
|
+
const conversation = assemble(
|
|
131540
|
+
filePath,
|
|
131541
|
+
account,
|
|
131542
|
+
messages,
|
|
131543
|
+
fullText,
|
|
131544
|
+
allTurnDurations,
|
|
131545
|
+
resume.state
|
|
131546
|
+
);
|
|
131547
|
+
return { conversation, resume: { state: resume.state, offset: end.offset, line: end.line } };
|
|
131548
|
+
}
|
|
131355
131549
|
var FP_BYTES = 4096;
|
|
131356
131550
|
function fingerprint(filePath, size) {
|
|
131357
131551
|
const hash2 = (0, import_crypto2.createHash)("sha1");
|
|
131358
131552
|
hash2.update(String(size));
|
|
131359
|
-
const fd = (0,
|
|
131553
|
+
const fd = (0, import_fs11.openSync)(filePath, "r");
|
|
131360
131554
|
try {
|
|
131361
131555
|
const head = Buffer.alloc(Math.min(FP_BYTES, size));
|
|
131362
131556
|
if (head.length > 0) {
|
|
131363
|
-
(0,
|
|
131557
|
+
(0, import_fs11.readSync)(fd, head, 0, head.length, 0);
|
|
131364
131558
|
hash2.update(head);
|
|
131365
131559
|
}
|
|
131366
131560
|
if (size > FP_BYTES) {
|
|
131367
131561
|
const tailLen = Math.min(FP_BYTES, size);
|
|
131368
131562
|
const tail = Buffer.alloc(tailLen);
|
|
131369
|
-
(0,
|
|
131563
|
+
(0, import_fs11.readSync)(fd, tail, 0, tailLen, size - tailLen);
|
|
131370
131564
|
hash2.update(tail);
|
|
131371
131565
|
}
|
|
131372
131566
|
} finally {
|
|
131373
|
-
(0,
|
|
131567
|
+
(0, import_fs11.closeSync)(fd);
|
|
131374
131568
|
}
|
|
131375
131569
|
return hash2.digest("hex");
|
|
131376
131570
|
}
|
|
131377
131571
|
function classify(filePath, existing) {
|
|
131378
131572
|
let stat42;
|
|
131379
131573
|
try {
|
|
131380
|
-
const s3 = (0,
|
|
131574
|
+
const s3 = (0, import_fs11.statSync)(filePath);
|
|
131381
131575
|
stat42 = { size: s3.size, mtimeMs: s3.mtimeMs };
|
|
131382
131576
|
} catch {
|
|
131383
131577
|
return { change: "vanished" };
|
|
@@ -131407,7 +131601,7 @@ async function parseMetaWithProvider(provider, filePath, account, tier) {
|
|
|
131407
131601
|
const log8 = getLogger2();
|
|
131408
131602
|
const acc = provider.createEmptyAccumulator();
|
|
131409
131603
|
const rl = (0, import_readline3.createInterface)({
|
|
131410
|
-
input: (0,
|
|
131604
|
+
input: (0, import_fs13.createReadStream)(filePath),
|
|
131411
131605
|
crlfDelay: Infinity
|
|
131412
131606
|
});
|
|
131413
131607
|
try {
|
|
@@ -131630,7 +131824,7 @@ function hasColumn(db, table, column) {
|
|
|
131630
131824
|
}
|
|
131631
131825
|
function openDatabase(dbPath) {
|
|
131632
131826
|
if (dbPath !== ":memory:") {
|
|
131633
|
-
(0,
|
|
131827
|
+
(0, import_fs14.mkdirSync)((0, import_path9.dirname)(dbPath), { recursive: true });
|
|
131634
131828
|
}
|
|
131635
131829
|
const db = new import_better_sqlite3.default(dbPath);
|
|
131636
131830
|
db.pragma("journal_mode = WAL");
|
|
@@ -131656,7 +131850,7 @@ async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
|
|
|
131656
131850
|
for (const projectDir of resolved.entries) {
|
|
131657
131851
|
let dirStat;
|
|
131658
131852
|
try {
|
|
131659
|
-
dirStat = await (0,
|
|
131853
|
+
dirStat = await (0, import_promises9.stat)(projectDir);
|
|
131660
131854
|
} catch {
|
|
131661
131855
|
scannedDirs.remove(projectDir);
|
|
131662
131856
|
continue;
|
|
@@ -131694,7 +131888,7 @@ async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
|
|
|
131694
131888
|
async function resolveProjectDirs(projectsDir, scannedDirs) {
|
|
131695
131889
|
let rootStat;
|
|
131696
131890
|
try {
|
|
131697
|
-
rootStat = await (0,
|
|
131891
|
+
rootStat = await (0, import_promises9.stat)(projectsDir);
|
|
131698
131892
|
} catch {
|
|
131699
131893
|
return null;
|
|
131700
131894
|
}
|
|
@@ -131704,7 +131898,7 @@ async function resolveProjectDirs(projectsDir, scannedDirs) {
|
|
|
131704
131898
|
}
|
|
131705
131899
|
let entries;
|
|
131706
131900
|
try {
|
|
131707
|
-
entries = (await (0,
|
|
131901
|
+
entries = (await (0, import_promises9.readdir)(projectsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => joinPath(projectsDir, e.name));
|
|
131708
131902
|
} catch {
|
|
131709
131903
|
return null;
|
|
131710
131904
|
}
|
|
@@ -131717,98 +131911,6 @@ function dirnameOf(filePath) {
|
|
|
131717
131911
|
function joinPath(dir, name) {
|
|
131718
131912
|
return dir.endsWith("/") ? `${dir}${name}` : `${dir}/${name}`;
|
|
131719
131913
|
}
|
|
131720
|
-
async function tailReduce(filePath, startOffset, startLine, state, tier) {
|
|
131721
|
-
const stream = (0, import_fs12.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
|
|
131722
|
-
let buffer = "";
|
|
131723
|
-
let offset = startOffset;
|
|
131724
|
-
let line = startLine;
|
|
131725
|
-
let parsedLines = 0;
|
|
131726
|
-
for await (const chunk of stream) {
|
|
131727
|
-
buffer += chunk;
|
|
131728
|
-
let nl;
|
|
131729
|
-
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
131730
|
-
const lineWithNewline = buffer.slice(0, nl + 1);
|
|
131731
|
-
const text = lineWithNewline.trimEnd();
|
|
131732
|
-
buffer = buffer.slice(nl + 1);
|
|
131733
|
-
if (text.length > 0) {
|
|
131734
|
-
try {
|
|
131735
|
-
reduceLine(state, JSON.parse(text), tier);
|
|
131736
|
-
} catch {
|
|
131737
|
-
state.badJsonLines++;
|
|
131738
|
-
}
|
|
131739
|
-
parsedLines++;
|
|
131740
|
-
}
|
|
131741
|
-
offset += Buffer.byteLength(lineWithNewline, "utf8");
|
|
131742
|
-
line++;
|
|
131743
|
-
}
|
|
131744
|
-
}
|
|
131745
|
-
return { newOffset: offset, newLine: line, parsedLines, badJsonLines: state.badJsonLines };
|
|
131746
|
-
}
|
|
131747
|
-
var CHECKPOINT_INTERVAL = 500;
|
|
131748
|
-
async function streamMessages(filePath, startOffset, startLine, state, onMessage) {
|
|
131749
|
-
const stream = (0, import_fs13.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
|
|
131750
|
-
let buffer = "";
|
|
131751
|
-
let offset = startOffset;
|
|
131752
|
-
let line = startLine;
|
|
131753
|
-
for await (const chunk of stream) {
|
|
131754
|
-
buffer += chunk;
|
|
131755
|
-
let nl;
|
|
131756
|
-
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
131757
|
-
const lineWithNewline = buffer.slice(0, nl + 1);
|
|
131758
|
-
const text = lineWithNewline.trimEnd();
|
|
131759
|
-
buffer = buffer.slice(nl + 1);
|
|
131760
|
-
offset += Buffer.byteLength(lineWithNewline, "utf8");
|
|
131761
|
-
line += 1;
|
|
131762
|
-
if (text.length === 0) continue;
|
|
131763
|
-
let entry;
|
|
131764
|
-
try {
|
|
131765
|
-
entry = JSON.parse(text);
|
|
131766
|
-
} catch {
|
|
131767
|
-
continue;
|
|
131768
|
-
}
|
|
131769
|
-
const message = reduceConvLine(state, entry);
|
|
131770
|
-
if (message && onMessage(message, offset, line)) {
|
|
131771
|
-
stream.destroy();
|
|
131772
|
-
return;
|
|
131773
|
-
}
|
|
131774
|
-
}
|
|
131775
|
-
}
|
|
131776
|
-
}
|
|
131777
|
-
async function buildCheckpoints(filePath, interval = CHECKPOINT_INTERVAL) {
|
|
131778
|
-
const checkpoints = [];
|
|
131779
|
-
const state = initialConvState();
|
|
131780
|
-
let index = 0;
|
|
131781
|
-
await streamMessages(filePath, 0, 0, state, (_msg, nextOffset, nextLine) => {
|
|
131782
|
-
index += 1;
|
|
131783
|
-
if (index % interval === 0) {
|
|
131784
|
-
checkpoints.push({
|
|
131785
|
-
messageIndex: index,
|
|
131786
|
-
byteOffset: nextOffset,
|
|
131787
|
-
lineNumber: nextLine,
|
|
131788
|
-
state: structuredClone(state)
|
|
131789
|
-
});
|
|
131790
|
-
}
|
|
131791
|
-
return false;
|
|
131792
|
-
});
|
|
131793
|
-
return checkpoints;
|
|
131794
|
-
}
|
|
131795
|
-
async function readPage(filePath, total, options, floor) {
|
|
131796
|
-
const beforeIndex = options.beforeIndex ?? total;
|
|
131797
|
-
const fromIndex = Math.max(0, beforeIndex - options.limit);
|
|
131798
|
-
const state = floor ? structuredClone(floor.state) : initialConvState();
|
|
131799
|
-
const startOffset = floor ? floor.byteOffset : 0;
|
|
131800
|
-
const startLine = floor ? floor.lineNumber : 0;
|
|
131801
|
-
let index = floor ? floor.messageIndex : 0;
|
|
131802
|
-
const window2 = [];
|
|
131803
|
-
await streamMessages(filePath, startOffset, startLine, state, (message) => {
|
|
131804
|
-
const current = index;
|
|
131805
|
-
index += 1;
|
|
131806
|
-
if (current >= fromIndex && current < beforeIndex) window2.push(message);
|
|
131807
|
-
return index >= beforeIndex;
|
|
131808
|
-
});
|
|
131809
|
-
applyTeamInfo(window2, state);
|
|
131810
|
-
return { messages: window2, total, fromIndex };
|
|
131811
|
-
}
|
|
131812
131914
|
var CheckpointsRepo = class {
|
|
131813
131915
|
constructor(db) {
|
|
131814
131916
|
this.db = db;
|
|
@@ -131828,6 +131930,22 @@ var CheckpointsRepo = class {
|
|
|
131828
131930
|
});
|
|
131829
131931
|
tx();
|
|
131830
131932
|
}
|
|
131933
|
+
// Insert checkpoints without touching existing rows. Appends never invalidate
|
|
131934
|
+
// the chain covering the immutable prefix (Kafka sparse-index style); rows are
|
|
131935
|
+
// only ever removed on truncation/replace or deletion.
|
|
131936
|
+
append(sourcePath, checkpoints) {
|
|
131937
|
+
const tx = this.db.transaction(() => {
|
|
131938
|
+
const insert = this.db.prepare(
|
|
131939
|
+
`INSERT INTO message_checkpoints
|
|
131940
|
+
(source_path, message_index, byte_offset, line_number, parser_state)
|
|
131941
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
131942
|
+
);
|
|
131943
|
+
for (const c of checkpoints) {
|
|
131944
|
+
insert.run(sourcePath, c.messageIndex, c.byteOffset, c.lineNumber, JSON.stringify(c.state));
|
|
131945
|
+
}
|
|
131946
|
+
});
|
|
131947
|
+
tx();
|
|
131948
|
+
}
|
|
131831
131949
|
// The latest checkpoint at or before `messageIndex`, or null if none (read
|
|
131832
131950
|
// from the file start). Lets a page seek to the nearest prior anchor.
|
|
131833
131951
|
floor(sourcePath, messageIndex) {
|
|
@@ -131839,6 +131957,17 @@ var CheckpointsRepo = class {
|
|
|
131839
131957
|
).get(sourcePath, messageIndex);
|
|
131840
131958
|
return row ? toCheckpoint(row) : null;
|
|
131841
131959
|
}
|
|
131960
|
+
// The highest-index checkpoint for a file, or null if none. The resume point
|
|
131961
|
+
// for extending the chain after an append.
|
|
131962
|
+
last(sourcePath) {
|
|
131963
|
+
const row = this.db.prepare(
|
|
131964
|
+
`SELECT message_index, byte_offset, line_number, parser_state
|
|
131965
|
+
FROM message_checkpoints
|
|
131966
|
+
WHERE source_path = ?
|
|
131967
|
+
ORDER BY message_index DESC LIMIT 1`
|
|
131968
|
+
).get(sourcePath);
|
|
131969
|
+
return row ? toCheckpoint(row) : null;
|
|
131970
|
+
}
|
|
131842
131971
|
count(sourcePath) {
|
|
131843
131972
|
return this.db.prepare("SELECT COUNT(*) AS n FROM message_checkpoints WHERE source_path = ?").get(sourcePath).n;
|
|
131844
131973
|
}
|
|
@@ -131870,7 +131999,7 @@ var ConversationFilesRepo = class {
|
|
|
131870
131999
|
const info = this.db.prepare(
|
|
131871
132000
|
`INSERT INTO conversation_files (absolute_path, parent_dir, file_name, account)
|
|
131872
132001
|
VALUES (?, ?, ?, ?)`
|
|
131873
|
-
).run(absolutePath, (0,
|
|
132002
|
+
).run(absolutePath, (0, import_path10.dirname)(absolutePath), (0, import_path10.basename)(absolutePath), account);
|
|
131874
132003
|
return Number(info.lastInsertRowid);
|
|
131875
132004
|
}
|
|
131876
132005
|
// Advance the cursor + persisted reducer state after a successful index pass.
|
|
@@ -132221,6 +132350,9 @@ var PersistentEngine = class {
|
|
|
132221
132350
|
// restart just means the first few post-restart scans don't force an early
|
|
132222
132351
|
// backstop pass, which is harmless (watermarks themselves persist in the DB).
|
|
132223
132352
|
scanCount = 0;
|
|
132353
|
+
// In-flight checkpoint build/extension per file, so concurrent getPage
|
|
132354
|
+
// callers share one stream instead of each walking the file.
|
|
132355
|
+
checkpointBuilds = /* @__PURE__ */ new Map();
|
|
132224
132356
|
constructor(dbPath, options = {}) {
|
|
132225
132357
|
this.db = openDatabase(dbPath);
|
|
132226
132358
|
this.files = new ConversationFilesRepo(this.db);
|
|
@@ -132273,7 +132405,7 @@ var PersistentEngine = class {
|
|
|
132273
132405
|
const batch = discovered.slice(i, i + BATCH_SIZE);
|
|
132274
132406
|
const results = await Promise.all(
|
|
132275
132407
|
batch.map(async ({ filePath, account, provider }) => {
|
|
132276
|
-
const meta3 = await this.indexFile(
|
|
132408
|
+
const { meta: meta3 } = await this.indexFile(
|
|
132277
132409
|
filePath,
|
|
132278
132410
|
account,
|
|
132279
132411
|
tier.name,
|
|
@@ -132308,7 +132440,9 @@ var PersistentEngine = class {
|
|
|
132308
132440
|
// unchanged → return the stored summary; appended → resume the fold and read
|
|
132309
132441
|
// only new bytes; reindex/force → fold from offset 0. Writes the summary +
|
|
132310
132442
|
// cursor + reducer state in one transaction so a crash never leaves a
|
|
132311
|
-
// half-written row or an over-advanced cursor.
|
|
132443
|
+
// half-written row or an over-advanced cursor. Returns the classification
|
|
132444
|
+
// alongside the meta so callers (refreshFile) can keep, extend, or evict
|
|
132445
|
+
// their own per-file caches without re-stat'ing the file (racy) themselves.
|
|
132312
132446
|
async indexFile(filePath, account, tierName, customTiers, resolveGitBranch, force = false, provider) {
|
|
132313
132447
|
const log8 = getLogger2();
|
|
132314
132448
|
const tier = resolveTier(tierName, customTiers);
|
|
@@ -132316,13 +132450,21 @@ var PersistentEngine = class {
|
|
|
132316
132450
|
const { change, stat: stat42 } = classify(filePath, existing);
|
|
132317
132451
|
if (change === "vanished" || !stat42) {
|
|
132318
132452
|
this.markDeleted(filePath);
|
|
132319
|
-
return null;
|
|
132453
|
+
return { meta: null, change: "vanished" };
|
|
132320
132454
|
}
|
|
132321
132455
|
if (change === "unchanged" && !force) {
|
|
132322
|
-
return this.conversations.getBySourcePath(filePath);
|
|
132456
|
+
return { meta: this.conversations.getBySourcePath(filePath), change };
|
|
132323
132457
|
}
|
|
132324
132458
|
if (provider && provider.name !== CLAUDE_CODE_PROVIDER) {
|
|
132325
|
-
|
|
132459
|
+
const meta22 = await this.indexFileWithProvider(
|
|
132460
|
+
provider,
|
|
132461
|
+
filePath,
|
|
132462
|
+
account,
|
|
132463
|
+
tier,
|
|
132464
|
+
stat42,
|
|
132465
|
+
resolveGitBranch
|
|
132466
|
+
);
|
|
132467
|
+
return { meta: meta22, change };
|
|
132326
132468
|
}
|
|
132327
132469
|
const resume = change === "appended" && !force && existing?.reducer_state;
|
|
132328
132470
|
const state = resume ? JSON.parse(existing.reducer_state) : initialReducerState();
|
|
@@ -132333,12 +132475,12 @@ var PersistentEngine = class {
|
|
|
132333
132475
|
result = await tailReduce(filePath, startOffset, startLine, state, tier);
|
|
132334
132476
|
} catch (err) {
|
|
132335
132477
|
log8.warn({ filePath, err }, "persistent: tail read failed");
|
|
132336
|
-
return null;
|
|
132478
|
+
return { meta: null, change };
|
|
132337
132479
|
}
|
|
132338
132480
|
const meta3 = finalizeMeta(state, filePath, account, tier);
|
|
132339
132481
|
if (!meta3) {
|
|
132340
132482
|
this.markDeleted(filePath);
|
|
132341
|
-
return null;
|
|
132483
|
+
return { meta: null, change };
|
|
132342
132484
|
}
|
|
132343
132485
|
meta3.gitBranch = resolveGitBranch(meta3.projectPath);
|
|
132344
132486
|
const fp = stat42.size > 0 ? fingerprint(filePath, stat42.size) : null;
|
|
@@ -132346,7 +132488,7 @@ var PersistentEngine = class {
|
|
|
132346
132488
|
const upsert = this.db.transaction(() => {
|
|
132347
132489
|
this.conversations.upsert(fileId, meta3, state.pageMessageCount);
|
|
132348
132490
|
this.fts.upsert(meta3);
|
|
132349
|
-
this.checkpoints.remove(filePath);
|
|
132491
|
+
if (!resume) this.checkpoints.remove(filePath);
|
|
132350
132492
|
this.files.updateCursor(fileId, {
|
|
132351
132493
|
sizeBytes: stat42.size,
|
|
132352
132494
|
mtimeMs: stat42.mtimeMs,
|
|
@@ -132379,7 +132521,7 @@ var PersistentEngine = class {
|
|
|
132379
132521
|
{ filePath, change, bytesRead: result.newOffset - startOffset, msgs: meta3.messageCount },
|
|
132380
132522
|
"persistent: indexed file"
|
|
132381
132523
|
);
|
|
132382
|
-
return meta3;
|
|
132524
|
+
return { meta: meta3, change };
|
|
132383
132525
|
}
|
|
132384
132526
|
// Index a non-Threadbase provider file: full reparse from offset 0 through the
|
|
132385
132527
|
// provider's reducer/finalize, then the same upsert + FTS write + cursor bump
|
|
@@ -132479,15 +132621,40 @@ var PersistentEngine = class {
|
|
|
132479
132621
|
return { messages: messages.slice(fromIndex2, beforeIndex2), total: total2, fromIndex: fromIndex2 };
|
|
132480
132622
|
}
|
|
132481
132623
|
const total = this.conversations.pageMessageCount(filePath);
|
|
132482
|
-
|
|
132483
|
-
const built = await buildCheckpoints(filePath);
|
|
132484
|
-
if (built.length > 0) this.checkpoints.replaceAll(filePath, built);
|
|
132485
|
-
}
|
|
132624
|
+
await this.ensureCheckpoints(filePath, total);
|
|
132486
132625
|
const beforeIndex = options.beforeIndex ?? total;
|
|
132487
132626
|
const fromIndex = Math.max(0, beforeIndex - options.limit);
|
|
132488
|
-
|
|
132627
|
+
let floor = this.checkpoints.floor(filePath, fromIndex);
|
|
132628
|
+
if (floor) {
|
|
132629
|
+
try {
|
|
132630
|
+
if (floor.byteOffset > (0, import_fs12.statSync)(filePath).size) floor = null;
|
|
132631
|
+
} catch {
|
|
132632
|
+
}
|
|
132633
|
+
}
|
|
132489
132634
|
return readPage(filePath, total, options, floor);
|
|
132490
132635
|
}
|
|
132636
|
+
// Build or extend the checkpoint chain so it covers `total` messages. Cold
|
|
132637
|
+
// file → full build; a file that grew → extend from the last persisted
|
|
132638
|
+
// checkpoint (reads only past its offset, never the prefix). Single-flighted
|
|
132639
|
+
// per path: concurrent getPage callers await the same build instead of
|
|
132640
|
+
// streaming the file in parallel.
|
|
132641
|
+
ensureCheckpoints(filePath, total) {
|
|
132642
|
+
if (total <= CHECKPOINT_INTERVAL) return Promise.resolve();
|
|
132643
|
+
const inFlight = this.checkpointBuilds.get(filePath);
|
|
132644
|
+
if (inFlight) return inFlight;
|
|
132645
|
+
const build2 = (async () => {
|
|
132646
|
+
const last = this.checkpoints.last(filePath);
|
|
132647
|
+
if (last && total < last.messageIndex + CHECKPOINT_INTERVAL) return;
|
|
132648
|
+
const fresh = await buildCheckpoints(filePath, CHECKPOINT_INTERVAL, last);
|
|
132649
|
+
if (fresh.length === 0) return;
|
|
132650
|
+
if (last) this.checkpoints.append(filePath, fresh);
|
|
132651
|
+
else this.checkpoints.replaceAll(filePath, fresh);
|
|
132652
|
+
})().finally(() => {
|
|
132653
|
+
if (this.checkpointBuilds.get(filePath) === build2) this.checkpointBuilds.delete(filePath);
|
|
132654
|
+
});
|
|
132655
|
+
this.checkpointBuilds.set(filePath, build2);
|
|
132656
|
+
return build2;
|
|
132657
|
+
}
|
|
132491
132658
|
};
|
|
132492
132659
|
var EXCLUDED_SEGMENTS2 = ["/memory/", "/tool-results/"];
|
|
132493
132660
|
var FileWatcher = class {
|
|
@@ -132586,6 +132753,8 @@ function defaultDbPath() {
|
|
|
132586
132753
|
}
|
|
132587
132754
|
var ConversationScanner = class {
|
|
132588
132755
|
metadataCache = /* @__PURE__ */ new Map();
|
|
132756
|
+
// Parsed conversations plus (persistent claude-code entries only) the resume
|
|
132757
|
+
// point that lets refreshFile extend them in place when the file grows.
|
|
132589
132758
|
conversationLRU;
|
|
132590
132759
|
// session_id is NOT unique, so this maps a sessionId to every active meta that
|
|
132591
132760
|
// carries it. Resolution picks deterministically (newest timestamp, then path
|
|
@@ -132617,7 +132786,9 @@ var ConversationScanner = class {
|
|
|
132617
132786
|
// can't hit a closed DB (the watch-mode half of Bug #4).
|
|
132618
132787
|
inFlightReconcile = null;
|
|
132619
132788
|
constructor(options) {
|
|
132620
|
-
this.conversationLRU = new LRUCache(
|
|
132789
|
+
this.conversationLRU = new LRUCache(
|
|
132790
|
+
options?.conversationCacheSize ?? 5
|
|
132791
|
+
);
|
|
132621
132792
|
if (options?.persistent === false) {
|
|
132622
132793
|
this.dbPath = null;
|
|
132623
132794
|
this.sidecarEnabled = false;
|
|
@@ -132874,7 +133045,7 @@ var ConversationScanner = class {
|
|
|
132874
133045
|
const cached3 = this.conversationLRU.get(id);
|
|
132875
133046
|
if (cached3) {
|
|
132876
133047
|
log8.debug({ id }, "getConversation: cache hit");
|
|
132877
|
-
return cached3;
|
|
133048
|
+
return cached3.conversation;
|
|
132878
133049
|
}
|
|
132879
133050
|
const meta3 = this.persistent ? this.engine().getByIdOrSession(id) : this.metadataCache.get(id) ?? this.resolveSessionId(id);
|
|
132880
133051
|
if (!meta3) {
|
|
@@ -132883,9 +133054,14 @@ var ConversationScanner = class {
|
|
|
132883
133054
|
}
|
|
132884
133055
|
log8.debug({ id, filePath: meta3.filePath }, "getConversation: cache miss, parsing");
|
|
132885
133056
|
try {
|
|
133057
|
+
if (this.persistent && meta3.provider !== CODEX_CLI_PROVIDER) {
|
|
133058
|
+
const parsed = await parseConversationResumable(meta3.filePath, meta3.account);
|
|
133059
|
+
if (parsed) this.conversationLRU.set(id, parsed);
|
|
133060
|
+
return parsed?.conversation ?? null;
|
|
133061
|
+
}
|
|
132886
133062
|
const conversation = meta3.provider === CODEX_CLI_PROVIDER ? await parseCodexConversation(meta3.filePath, meta3.account) : await parseConversation(meta3.filePath, meta3.account);
|
|
132887
133063
|
if (conversation) {
|
|
132888
|
-
this.conversationLRU.set(id, conversation);
|
|
133064
|
+
this.conversationLRU.set(id, { conversation });
|
|
132889
133065
|
}
|
|
132890
133066
|
return conversation;
|
|
132891
133067
|
} catch (err) {
|
|
@@ -132957,20 +133133,30 @@ var ConversationScanner = class {
|
|
|
132957
133133
|
// not seen before. Returns the fresh ConversationMeta, or null when the file
|
|
132958
133134
|
// no longer parses (missing/empty) — in which case any prior entry for it is
|
|
132959
133135
|
// dropped from all indexes.
|
|
132960
|
-
|
|
133136
|
+
//
|
|
133137
|
+
// Single-flighted per path: concurrent callers (stacked client retries, a
|
|
133138
|
+
// watcher tick racing a caller) await the one in-flight refresh instead of
|
|
133139
|
+
// each re-reading the file.
|
|
133140
|
+
refreshesInFlight = /* @__PURE__ */ new Map();
|
|
133141
|
+
refreshFile(filePath, account) {
|
|
133142
|
+
const inFlight = this.refreshesInFlight.get(filePath);
|
|
133143
|
+
if (inFlight) return inFlight;
|
|
133144
|
+
const refresh = this.doRefreshFile(filePath, account).finally(() => {
|
|
133145
|
+
if (this.refreshesInFlight.get(filePath) === refresh) {
|
|
133146
|
+
this.refreshesInFlight.delete(filePath);
|
|
133147
|
+
}
|
|
133148
|
+
});
|
|
133149
|
+
this.refreshesInFlight.set(filePath, refresh);
|
|
133150
|
+
return refresh;
|
|
133151
|
+
}
|
|
133152
|
+
async doRefreshFile(filePath, account) {
|
|
132961
133153
|
const log8 = getLogger2();
|
|
132962
133154
|
if (this.persistent) {
|
|
132963
133155
|
const engine = this.engine();
|
|
132964
133156
|
const previous2 = engine.getByIdOrSession(filePath);
|
|
132965
133157
|
const resolvedAccount2 = account ?? previous2?.account ?? "default";
|
|
132966
|
-
const evict2 = (m2) => {
|
|
132967
|
-
if (!m2) return;
|
|
132968
|
-
this.conversationLRU.delete(m2.id);
|
|
132969
|
-
this.conversationLRU.delete(m2.sessionId);
|
|
132970
|
-
};
|
|
132971
|
-
evict2(previous2);
|
|
132972
133158
|
const provider = await this.resolveProviderForFile(filePath, previous2);
|
|
132973
|
-
const meta22 = await engine.indexFile(
|
|
133159
|
+
const { meta: meta22, change } = await engine.indexFile(
|
|
132974
133160
|
filePath,
|
|
132975
133161
|
resolvedAccount2,
|
|
132976
133162
|
this.lastTier.name,
|
|
@@ -132979,8 +133165,19 @@ var ConversationScanner = class {
|
|
|
132979
133165
|
false,
|
|
132980
133166
|
provider
|
|
132981
133167
|
);
|
|
132982
|
-
|
|
132983
|
-
|
|
133168
|
+
const cacheKeys = /* @__PURE__ */ new Set();
|
|
133169
|
+
for (const m2 of [previous2, meta22]) {
|
|
133170
|
+
if (m2) {
|
|
133171
|
+
cacheKeys.add(m2.id);
|
|
133172
|
+
cacheKeys.add(m2.sessionId);
|
|
133173
|
+
}
|
|
133174
|
+
}
|
|
133175
|
+
if (!meta22 || change === "reindex" || change === "vanished") {
|
|
133176
|
+
for (const key of cacheKeys) this.conversationLRU.delete(key);
|
|
133177
|
+
} else if (change === "appended") {
|
|
133178
|
+
await this.extendCachedConversations(cacheKeys, filePath, meta22.account);
|
|
133179
|
+
}
|
|
133180
|
+
log8.debug({ filePath, change, kept: !!meta22 }, "refreshFile: updated persistent index");
|
|
132984
133181
|
return meta22;
|
|
132985
133182
|
}
|
|
132986
133183
|
const previous = this.metadataCache.get(filePath);
|
|
@@ -133024,6 +133221,39 @@ var ConversationScanner = class {
|
|
|
133024
133221
|
);
|
|
133025
133222
|
return meta3;
|
|
133026
133223
|
}
|
|
133224
|
+
// Advance every cached parse of an appended file by folding only the new
|
|
133225
|
+
// bytes through the conversation reducer — the in-memory analogue of the
|
|
133226
|
+
// persisted metadata fold. Entries without resume state (Codex) and entries
|
|
133227
|
+
// whose extension fails are evicted so the next read re-parses from scratch.
|
|
133228
|
+
async extendCachedConversations(cacheKeys, filePath, account) {
|
|
133229
|
+
const wrappers = /* @__PURE__ */ new Map();
|
|
133230
|
+
for (const key of cacheKeys) {
|
|
133231
|
+
const wrapper = this.conversationLRU.get(key);
|
|
133232
|
+
if (!wrapper) continue;
|
|
133233
|
+
const keys = wrappers.get(wrapper) ?? [];
|
|
133234
|
+
keys.push(key);
|
|
133235
|
+
wrappers.set(wrapper, keys);
|
|
133236
|
+
}
|
|
133237
|
+
for (const [wrapper, keys] of wrappers) {
|
|
133238
|
+
if (!wrapper.resume) {
|
|
133239
|
+
for (const key of keys) this.conversationLRU.delete(key);
|
|
133240
|
+
continue;
|
|
133241
|
+
}
|
|
133242
|
+
try {
|
|
133243
|
+
const extended = await extendConversation(
|
|
133244
|
+
wrapper.conversation,
|
|
133245
|
+
wrapper.resume,
|
|
133246
|
+
filePath,
|
|
133247
|
+
account
|
|
133248
|
+
);
|
|
133249
|
+
wrapper.conversation = extended.conversation;
|
|
133250
|
+
wrapper.resume = extended.resume;
|
|
133251
|
+
} catch (err) {
|
|
133252
|
+
getLogger2().warn({ filePath, err }, "refreshFile: cache extension failed, evicting");
|
|
133253
|
+
for (const key of keys) this.conversationLRU.delete(key);
|
|
133254
|
+
}
|
|
133255
|
+
}
|
|
133256
|
+
}
|
|
133027
133257
|
getMetadataCache() {
|
|
133028
133258
|
if (this.persistent) {
|
|
133029
133259
|
const map2 = /* @__PURE__ */ new Map();
|
|
@@ -133289,11 +133519,11 @@ async function search(query, options, scanner) {
|
|
|
133289
133519
|
|
|
133290
133520
|
// src/server.ts
|
|
133291
133521
|
var import_events3 = require("events");
|
|
133292
|
-
var
|
|
133293
|
-
var
|
|
133522
|
+
var import_fs25 = require("fs");
|
|
133523
|
+
var import_promises17 = require("fs/promises");
|
|
133294
133524
|
var import_http = require("http");
|
|
133295
133525
|
var import_os10 = require("os");
|
|
133296
|
-
var
|
|
133526
|
+
var import_path22 = require("path");
|
|
133297
133527
|
var import_readline4 = require("readline");
|
|
133298
133528
|
|
|
133299
133529
|
// src/agent/agent-client.ts
|
|
@@ -133382,7 +133612,7 @@ function readAgentConfig(env = process.env) {
|
|
|
133382
133612
|
}
|
|
133383
133613
|
|
|
133384
133614
|
// src/agent/conversation-writer.ts
|
|
133385
|
-
var
|
|
133615
|
+
var import_promises10 = require("fs/promises");
|
|
133386
133616
|
var import_node_path6 = require("path");
|
|
133387
133617
|
function createConversationWriter(opts) {
|
|
133388
133618
|
const { baseDir } = opts;
|
|
@@ -133392,7 +133622,7 @@ function createConversationWriter(opts) {
|
|
|
133392
133622
|
throw new Error("ConversationWriter: refusing to write empty assistant turn");
|
|
133393
133623
|
}
|
|
133394
133624
|
const file2 = (0, import_node_path6.join)(baseDir, `${args.sessionId}.jsonl`);
|
|
133395
|
-
await (0,
|
|
133625
|
+
await (0, import_promises10.mkdir)((0, import_node_path6.dirname)(file2), { recursive: true });
|
|
133396
133626
|
const record2 = {
|
|
133397
133627
|
role: "assistant",
|
|
133398
133628
|
turnId: args.turnId,
|
|
@@ -133402,7 +133632,7 @@ function createConversationWriter(opts) {
|
|
|
133402
133632
|
};
|
|
133403
133633
|
const line = `${JSON.stringify(record2)}
|
|
133404
133634
|
`;
|
|
133405
|
-
await (0,
|
|
133635
|
+
await (0, import_promises10.appendFile)(file2, line, { encoding: "utf8" });
|
|
133406
133636
|
}
|
|
133407
133637
|
};
|
|
133408
133638
|
}
|
|
@@ -136383,8 +136613,8 @@ var createHonoApp = (deps, upgradeWebSocket) => {
|
|
|
136383
136613
|
init_auth();
|
|
136384
136614
|
|
|
136385
136615
|
// src/browse.ts
|
|
136386
|
-
var
|
|
136387
|
-
var
|
|
136616
|
+
var import_promises11 = require("fs/promises");
|
|
136617
|
+
var import_path11 = require("path");
|
|
136388
136618
|
var BrowsePathNotFoundError = class extends Error {
|
|
136389
136619
|
constructor(message) {
|
|
136390
136620
|
super(message);
|
|
@@ -136392,20 +136622,20 @@ var BrowsePathNotFoundError = class extends Error {
|
|
|
136392
136622
|
}
|
|
136393
136623
|
};
|
|
136394
136624
|
async function resolveBrowsePath(browseRoot, relativePath) {
|
|
136395
|
-
const normalizedRoot = (0,
|
|
136625
|
+
const normalizedRoot = (0, import_path11.resolve)(browseRoot);
|
|
136396
136626
|
let sanitized;
|
|
136397
136627
|
if (process.platform !== "win32" && relativePath.startsWith("/") && relativePath.length > 1 && relativePath.includes("/", 1)) {
|
|
136398
136628
|
sanitized = relativePath;
|
|
136399
136629
|
} else {
|
|
136400
136630
|
sanitized = relativePath.replace(/^[/\\]+/, "");
|
|
136401
136631
|
}
|
|
136402
|
-
const target = sanitized ? (0,
|
|
136403
|
-
const rootPrefix = normalizedRoot.endsWith(
|
|
136632
|
+
const target = sanitized ? (0, import_path11.resolve)(normalizedRoot, sanitized) : normalizedRoot;
|
|
136633
|
+
const rootPrefix = normalizedRoot.endsWith(import_path11.sep) ? normalizedRoot : `${normalizedRoot}${import_path11.sep}`;
|
|
136404
136634
|
if (!target.startsWith(rootPrefix) && target !== normalizedRoot) {
|
|
136405
136635
|
throw new Error("Path outside browse root");
|
|
136406
136636
|
}
|
|
136407
136637
|
try {
|
|
136408
|
-
await (0,
|
|
136638
|
+
await (0, import_promises11.realpath)(target);
|
|
136409
136639
|
} catch (err) {
|
|
136410
136640
|
if (err?.code === "ENOENT") {
|
|
136411
136641
|
throw new BrowsePathNotFoundError(`Path not found: ${target}`);
|
|
@@ -136415,37 +136645,37 @@ async function resolveBrowsePath(browseRoot, relativePath) {
|
|
|
136415
136645
|
return target;
|
|
136416
136646
|
}
|
|
136417
136647
|
async function listDirectories(absolutePath) {
|
|
136418
|
-
const entries = await (0,
|
|
136648
|
+
const entries = await (0, import_promises11.readdir)(absolutePath, { withFileTypes: true });
|
|
136419
136649
|
return entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name })).sort((a, b2) => a.name.localeCompare(b2.name));
|
|
136420
136650
|
}
|
|
136421
136651
|
async function createDirectory(parentAbsolutePath, name) {
|
|
136422
136652
|
if (name.includes("/") || name.includes("\\") || name === ".." || name === ".") {
|
|
136423
136653
|
throw new Error("Invalid directory name");
|
|
136424
136654
|
}
|
|
136425
|
-
const target = (0,
|
|
136655
|
+
const target = (0, import_path11.join)(parentAbsolutePath, name);
|
|
136426
136656
|
try {
|
|
136427
|
-
const s3 = await (0,
|
|
136657
|
+
const s3 = await (0, import_promises11.stat)(target);
|
|
136428
136658
|
if (s3.isDirectory()) throw new Error("Directory already exists");
|
|
136429
136659
|
} catch (err) {
|
|
136430
136660
|
if (err.code !== "ENOENT") throw err;
|
|
136431
136661
|
}
|
|
136432
|
-
await (0,
|
|
136662
|
+
await (0, import_promises11.mkdir)(target);
|
|
136433
136663
|
return target;
|
|
136434
136664
|
}
|
|
136435
136665
|
|
|
136436
136666
|
// src/conversation-cache.ts
|
|
136437
136667
|
var import_better_sqlite32 = __toESM(require("better-sqlite3"), 1);
|
|
136438
|
-
var
|
|
136439
|
-
var
|
|
136668
|
+
var import_fs17 = require("fs");
|
|
136669
|
+
var import_path13 = require("path");
|
|
136440
136670
|
|
|
136441
136671
|
// src/db/sqlite-migrate.ts
|
|
136442
|
-
var
|
|
136443
|
-
var
|
|
136672
|
+
var import_fs15 = require("fs");
|
|
136673
|
+
var import_path12 = require("path");
|
|
136444
136674
|
var import_url6 = require("url");
|
|
136445
136675
|
var import_meta = {};
|
|
136446
136676
|
function getMigrationsDir() {
|
|
136447
136677
|
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
136448
|
-
return (0,
|
|
136678
|
+
return (0, import_path12.dirname)((0, import_url6.fileURLToPath)(import_meta.url));
|
|
136449
136679
|
}
|
|
136450
136680
|
return __dirname;
|
|
136451
136681
|
}
|
|
@@ -136457,8 +136687,8 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
|
136457
136687
|
`;
|
|
136458
136688
|
function runSqliteMigrations(db, migrationsDir) {
|
|
136459
136689
|
db.exec(SCHEMA_MIGRATIONS_SQL);
|
|
136460
|
-
const dir = migrationsDir ?? (0,
|
|
136461
|
-
const files = (0,
|
|
136690
|
+
const dir = migrationsDir ?? (0, import_path12.join)(getMigrationsDir(), "migrations");
|
|
136691
|
+
const files = (0, import_fs15.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
|
|
136462
136692
|
const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
|
|
136463
136693
|
const appliedSet = new Set(appliedRows.map((r) => r.id));
|
|
136464
136694
|
const recordApplied = db.prepare("INSERT INTO schema_migrations (id, applied_at) VALUES (?, ?)");
|
|
@@ -136469,7 +136699,7 @@ function runSqliteMigrations(db, migrationsDir) {
|
|
|
136469
136699
|
skipped.push(file2);
|
|
136470
136700
|
continue;
|
|
136471
136701
|
}
|
|
136472
|
-
const sql = (0,
|
|
136702
|
+
const sql = (0, import_fs15.readFileSync)((0, import_path12.join)(dir, file2), "utf-8");
|
|
136473
136703
|
const tx = db.transaction(() => {
|
|
136474
136704
|
db.exec(sql);
|
|
136475
136705
|
recordApplied.run(file2, (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -136494,7 +136724,7 @@ function isProviderResumable(_provider, availabilityResumable) {
|
|
|
136494
136724
|
}
|
|
136495
136725
|
|
|
136496
136726
|
// src/services/conversations/isAgentConversation.ts
|
|
136497
|
-
var
|
|
136727
|
+
var import_fs16 = require("fs");
|
|
136498
136728
|
var DEFAULT_AGENT_ENTRYPOINTS = /* @__PURE__ */ new Set(["sdk-cli", "claude-vscode"]);
|
|
136499
136729
|
var CHUNK_BYTES = 64 * 1024;
|
|
136500
136730
|
var ENTRYPOINT_PROBE = `"entrypoint":`;
|
|
@@ -136516,12 +136746,12 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
|
|
|
136516
136746
|
if (cached3 !== void 0) return cached3;
|
|
136517
136747
|
let fd;
|
|
136518
136748
|
try {
|
|
136519
|
-
fd = (0,
|
|
136749
|
+
fd = (0, import_fs16.openSync)(filePath, "r");
|
|
136520
136750
|
} catch {
|
|
136521
136751
|
return false;
|
|
136522
136752
|
}
|
|
136523
136753
|
try {
|
|
136524
|
-
const fileSize = (0,
|
|
136754
|
+
const fileSize = (0, import_fs16.statSync)(filePath).size;
|
|
136525
136755
|
if (fileSize === 0) {
|
|
136526
136756
|
fileDecisionCache.set(key, false);
|
|
136527
136757
|
return false;
|
|
@@ -136532,7 +136762,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
|
|
|
136532
136762
|
let carry = "";
|
|
136533
136763
|
while (offset < fileSize) {
|
|
136534
136764
|
const toRead = Math.min(CHUNK_BYTES, fileSize - offset);
|
|
136535
|
-
const got = (0,
|
|
136765
|
+
const got = (0, import_fs16.readSync)(fd, buf, 0, toRead, offset);
|
|
136536
136766
|
if (got <= 0) break;
|
|
136537
136767
|
const chunk = carry + buf.toString("utf8", 0, got);
|
|
136538
136768
|
for (const marker of markers) {
|
|
@@ -136553,7 +136783,7 @@ function isAgentFile(filePath, entrypoints = DEFAULT_AGENT_ENTRYPOINTS) {
|
|
|
136553
136783
|
} catch {
|
|
136554
136784
|
return false;
|
|
136555
136785
|
} finally {
|
|
136556
|
-
(0,
|
|
136786
|
+
(0, import_fs16.closeSync)(fd);
|
|
136557
136787
|
}
|
|
136558
136788
|
}
|
|
136559
136789
|
function parseAgentEntrypointsEnv(raw2) {
|
|
@@ -136807,14 +137037,14 @@ var ConversationCache = class _ConversationCache {
|
|
|
136807
137037
|
isAgentFileCached(filePath) {
|
|
136808
137038
|
let s3;
|
|
136809
137039
|
try {
|
|
136810
|
-
s3 = (0,
|
|
137040
|
+
s3 = (0, import_fs17.statSync)(filePath);
|
|
136811
137041
|
} catch {
|
|
136812
137042
|
return false;
|
|
136813
137043
|
}
|
|
136814
137044
|
return this.classifyAgentFile(filePath, s3.mtimeMs, s3.size);
|
|
136815
137045
|
}
|
|
136816
137046
|
static open(dbPath, tailSize = 10, migrationsDir, options) {
|
|
136817
|
-
(0,
|
|
137047
|
+
(0, import_fs17.mkdirSync)((0, import_path13.dirname)(dbPath), { recursive: true });
|
|
136818
137048
|
const db = new import_better_sqlite32.default(dbPath);
|
|
136819
137049
|
db.pragma("journal_mode = WAL");
|
|
136820
137050
|
db.pragma("foreign_keys = ON");
|
|
@@ -136995,7 +137225,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
136995
137225
|
let mtimeMs = null;
|
|
136996
137226
|
let fileSize = null;
|
|
136997
137227
|
try {
|
|
136998
|
-
const s3 = (0,
|
|
137228
|
+
const s3 = (0, import_fs17.statSync)(m2.filePath);
|
|
136999
137229
|
mtimeMs = s3.mtimeMs;
|
|
137000
137230
|
fileSize = s3.size;
|
|
137001
137231
|
} catch {
|
|
@@ -137054,8 +137284,8 @@ var ConversationCache = class _ConversationCache {
|
|
|
137054
137284
|
let fileSize;
|
|
137055
137285
|
let fd;
|
|
137056
137286
|
try {
|
|
137057
|
-
fileSize = (0,
|
|
137058
|
-
fd = (0,
|
|
137287
|
+
fileSize = (0, import_fs17.statSync)(filePath).size;
|
|
137288
|
+
fd = (0, import_fs17.openSync)(filePath, "r");
|
|
137059
137289
|
} catch {
|
|
137060
137290
|
return false;
|
|
137061
137291
|
}
|
|
@@ -137068,7 +137298,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
137068
137298
|
while (pos > 0 && lines.length < this.tailSize * 4) {
|
|
137069
137299
|
const toRead = Math.min(CHUNK, pos);
|
|
137070
137300
|
pos -= toRead;
|
|
137071
|
-
(0,
|
|
137301
|
+
(0, import_fs17.readSync)(fd, buf, 0, toRead, pos);
|
|
137072
137302
|
const chunk = buf.subarray(0, toRead).toString("utf8");
|
|
137073
137303
|
const combined = chunk + partial2;
|
|
137074
137304
|
const parts = combined.split("\n");
|
|
@@ -137079,7 +137309,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
137079
137309
|
}
|
|
137080
137310
|
if (partial2) lines.push(partial2);
|
|
137081
137311
|
} finally {
|
|
137082
|
-
(0,
|
|
137312
|
+
(0, import_fs17.closeSync)(fd);
|
|
137083
137313
|
}
|
|
137084
137314
|
const msgs = [];
|
|
137085
137315
|
for (let i = 0; i < lines.length && msgs.length < this.tailSize; i++) {
|
|
@@ -137281,7 +137511,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
137281
137511
|
* `handleGetConversation` can still serve the cached tail even when the
|
|
137282
137512
|
* JSONL has been deleted.
|
|
137283
137513
|
*/
|
|
137284
|
-
pruneGhostFiles(exists =
|
|
137514
|
+
pruneGhostFiles(exists = import_fs17.existsSync) {
|
|
137285
137515
|
const rows = this.stmts.allFilePaths.all();
|
|
137286
137516
|
const ghosts = [];
|
|
137287
137517
|
const prune = this.db.transaction((ids) => {
|
|
@@ -137336,7 +137566,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
137336
137566
|
* Returns the removed IDs.
|
|
137337
137567
|
*/
|
|
137338
137568
|
reconcileDeletions(livePaths, opts) {
|
|
137339
|
-
const exists = opts?.exists ??
|
|
137569
|
+
const exists = opts?.exists ?? import_fs17.existsSync;
|
|
137340
137570
|
const rows = this.stmts.allFilePaths.all();
|
|
137341
137571
|
const removed = [];
|
|
137342
137572
|
const drop = this.db.transaction((ids) => {
|
|
@@ -137394,13 +137624,13 @@ function getDbConfig() {
|
|
|
137394
137624
|
}
|
|
137395
137625
|
|
|
137396
137626
|
// src/db/migrations.ts
|
|
137397
|
-
var
|
|
137398
|
-
var
|
|
137627
|
+
var import_fs18 = require("fs");
|
|
137628
|
+
var import_path14 = require("path");
|
|
137399
137629
|
var import_url7 = require("url");
|
|
137400
137630
|
var import_meta2 = {};
|
|
137401
137631
|
function getMigrationsDir2() {
|
|
137402
137632
|
if (import_meta2.url) {
|
|
137403
|
-
return (0,
|
|
137633
|
+
return (0, import_path14.dirname)((0, import_url7.fileURLToPath)(import_meta2.url));
|
|
137404
137634
|
}
|
|
137405
137635
|
return __dirname;
|
|
137406
137636
|
}
|
|
@@ -137416,11 +137646,11 @@ async function runMigrations2(pool2, migrationsDir) {
|
|
|
137416
137646
|
"SELECT name FROM _migrations ORDER BY name"
|
|
137417
137647
|
);
|
|
137418
137648
|
const appliedSet = new Set(applied.map((r) => r.name));
|
|
137419
|
-
const dir = migrationsDir ?? (0,
|
|
137420
|
-
const files = (0,
|
|
137649
|
+
const dir = migrationsDir ?? (0, import_path14.join)(getMigrationsDir2(), "pg-migrations");
|
|
137650
|
+
const files = (0, import_fs18.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
|
|
137421
137651
|
for (const file2 of files) {
|
|
137422
137652
|
if (appliedSet.has(file2)) continue;
|
|
137423
|
-
const sql = (0,
|
|
137653
|
+
const sql = (0, import_fs18.readFileSync)((0, import_path14.join)(dir, file2), "utf-8");
|
|
137424
137654
|
await pool2.query(sql);
|
|
137425
137655
|
await pool2.query("INSERT INTO _migrations (name) VALUES ($1)", [file2]);
|
|
137426
137656
|
}
|
|
@@ -137655,23 +137885,23 @@ async function recordUpload(pool2, instanceId, row) {
|
|
|
137655
137885
|
}
|
|
137656
137886
|
|
|
137657
137887
|
// src/handlers/handleListProjects.ts
|
|
137658
|
-
var
|
|
137888
|
+
var import_fs19 = require("fs");
|
|
137659
137889
|
var import_os7 = require("os");
|
|
137660
|
-
var
|
|
137890
|
+
var import_path15 = require("path");
|
|
137661
137891
|
function decodeProjectPath(dirName) {
|
|
137662
137892
|
return dirName.replace(/-/g, "/");
|
|
137663
137893
|
}
|
|
137664
137894
|
function handleListProjects(url2, res) {
|
|
137665
137895
|
const limit = Math.max(1, parseInt(url2.searchParams.get("limit") ?? "50", 10) || 50);
|
|
137666
137896
|
const offset = Math.max(0, parseInt(url2.searchParams.get("offset") ?? "0", 10) || 0);
|
|
137667
|
-
const projectsDir = (0,
|
|
137897
|
+
const projectsDir = (0, import_path15.join)((0, import_os7.homedir)(), ".claude", "projects");
|
|
137668
137898
|
let entries;
|
|
137669
137899
|
try {
|
|
137670
|
-
entries = (0,
|
|
137671
|
-
const fullPath = (0,
|
|
137900
|
+
entries = (0, import_fs19.readdirSync)(projectsDir).map((dirName) => {
|
|
137901
|
+
const fullPath = (0, import_path15.join)(projectsDir, dirName);
|
|
137672
137902
|
let mtime = 0;
|
|
137673
137903
|
try {
|
|
137674
|
-
mtime = (0,
|
|
137904
|
+
mtime = (0, import_fs19.statSync)(fullPath).mtimeMs;
|
|
137675
137905
|
} catch {
|
|
137676
137906
|
}
|
|
137677
137907
|
const path2 = decodeProjectPath(dirName);
|
|
@@ -137690,20 +137920,20 @@ function handleListProjects(url2, res) {
|
|
|
137690
137920
|
}
|
|
137691
137921
|
|
|
137692
137922
|
// src/live-session-manager.ts
|
|
137693
|
-
var
|
|
137923
|
+
var import_path19 = require("path");
|
|
137694
137924
|
|
|
137695
137925
|
// src/codex-pty-runner.ts
|
|
137696
137926
|
var import_headless = __toESM(require_xterm_headless(), 1);
|
|
137697
137927
|
var import_crypto6 = require("crypto");
|
|
137698
|
-
var
|
|
137699
|
-
var
|
|
137928
|
+
var import_fs21 = require("fs");
|
|
137929
|
+
var import_path17 = require("path");
|
|
137700
137930
|
init_logger();
|
|
137701
137931
|
|
|
137702
137932
|
// src/platform.ts
|
|
137703
137933
|
var import_child_process = require("child_process");
|
|
137704
|
-
var
|
|
137934
|
+
var import_fs20 = require("fs");
|
|
137705
137935
|
var import_os8 = require("os");
|
|
137706
|
-
var
|
|
137936
|
+
var import_path16 = require("path");
|
|
137707
137937
|
var isWindows2 = (0, import_os8.platform)() === "win32";
|
|
137708
137938
|
var _claudeExe;
|
|
137709
137939
|
function resolveClaudeExe() {
|
|
@@ -137722,16 +137952,16 @@ function resolveClaudeExe() {
|
|
|
137722
137952
|
} catch {
|
|
137723
137953
|
}
|
|
137724
137954
|
const candidates = [
|
|
137725
|
-
(0,
|
|
137726
|
-
(0,
|
|
137727
|
-
process.env.LOCALAPPDATA ?? (0,
|
|
137955
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "claude.exe"),
|
|
137956
|
+
(0, import_path16.join)(
|
|
137957
|
+
process.env.LOCALAPPDATA ?? (0, import_path16.join)((0, import_os8.homedir)(), "AppData", "Local"),
|
|
137728
137958
|
"Microsoft",
|
|
137729
137959
|
"WindowsApps",
|
|
137730
137960
|
"claude.exe"
|
|
137731
137961
|
)
|
|
137732
137962
|
];
|
|
137733
137963
|
for (const p2 of candidates) {
|
|
137734
|
-
if ((0,
|
|
137964
|
+
if ((0, import_fs20.existsSync)(p2)) {
|
|
137735
137965
|
_claudeExe = p2;
|
|
137736
137966
|
return _claudeExe;
|
|
137737
137967
|
}
|
|
@@ -137742,7 +137972,7 @@ function resolveClaudeExe() {
|
|
|
137742
137972
|
encoding: "utf-8",
|
|
137743
137973
|
timeout: 3e3
|
|
137744
137974
|
}).trim().split("\n")[0].trim();
|
|
137745
|
-
if (found && (0,
|
|
137975
|
+
if (found && (0, import_fs20.existsSync)(found)) {
|
|
137746
137976
|
_claudeExe = found;
|
|
137747
137977
|
return _claudeExe;
|
|
137748
137978
|
}
|
|
@@ -137751,10 +137981,10 @@ function resolveClaudeExe() {
|
|
|
137751
137981
|
const candidates = [
|
|
137752
137982
|
"/opt/homebrew/bin/claude",
|
|
137753
137983
|
"/usr/local/bin/claude",
|
|
137754
|
-
(0,
|
|
137984
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "claude")
|
|
137755
137985
|
];
|
|
137756
137986
|
for (const p2 of candidates) {
|
|
137757
|
-
if ((0,
|
|
137987
|
+
if ((0, import_fs20.existsSync)(p2)) {
|
|
137758
137988
|
_claudeExe = p2;
|
|
137759
137989
|
return _claudeExe;
|
|
137760
137990
|
}
|
|
@@ -137780,16 +138010,16 @@ function resolveCodexExe() {
|
|
|
137780
138010
|
} catch {
|
|
137781
138011
|
}
|
|
137782
138012
|
const candidates = [
|
|
137783
|
-
(0,
|
|
137784
|
-
(0,
|
|
137785
|
-
process.env.LOCALAPPDATA ?? (0,
|
|
138013
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "codex.exe"),
|
|
138014
|
+
(0, import_path16.join)(
|
|
138015
|
+
process.env.LOCALAPPDATA ?? (0, import_path16.join)((0, import_os8.homedir)(), "AppData", "Local"),
|
|
137786
138016
|
"Microsoft",
|
|
137787
138017
|
"WindowsApps",
|
|
137788
138018
|
"codex.exe"
|
|
137789
138019
|
)
|
|
137790
138020
|
];
|
|
137791
138021
|
for (const p2 of candidates) {
|
|
137792
|
-
if ((0,
|
|
138022
|
+
if ((0, import_fs20.existsSync)(p2)) {
|
|
137793
138023
|
_codexExe = p2;
|
|
137794
138024
|
return _codexExe;
|
|
137795
138025
|
}
|
|
@@ -137800,7 +138030,7 @@ function resolveCodexExe() {
|
|
|
137800
138030
|
encoding: "utf-8",
|
|
137801
138031
|
timeout: 3e3
|
|
137802
138032
|
}).trim().split("\n")[0].trim();
|
|
137803
|
-
if (found && (0,
|
|
138033
|
+
if (found && (0, import_fs20.existsSync)(found)) {
|
|
137804
138034
|
_codexExe = found;
|
|
137805
138035
|
return _codexExe;
|
|
137806
138036
|
}
|
|
@@ -137809,10 +138039,10 @@ function resolveCodexExe() {
|
|
|
137809
138039
|
const candidates = [
|
|
137810
138040
|
"/opt/homebrew/bin/codex",
|
|
137811
138041
|
"/usr/local/bin/codex",
|
|
137812
|
-
(0,
|
|
138042
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "codex")
|
|
137813
138043
|
];
|
|
137814
138044
|
for (const p2 of candidates) {
|
|
137815
|
-
if ((0,
|
|
138045
|
+
if ((0, import_fs20.existsSync)(p2)) {
|
|
137816
138046
|
_codexExe = p2;
|
|
137817
138047
|
return _codexExe;
|
|
137818
138048
|
}
|
|
@@ -137905,7 +138135,7 @@ var CodexPtyRunner = class {
|
|
|
137905
138135
|
}
|
|
137906
138136
|
async doStart(sessionId, options) {
|
|
137907
138137
|
const nodePty = await loadPty();
|
|
137908
|
-
const projectName = options.projectName ?? (0,
|
|
138138
|
+
const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
|
|
137909
138139
|
const proc = nodePty.spawn(
|
|
137910
138140
|
resolveCodexExe(),
|
|
137911
138141
|
["resume", sessionId, "--cd", options.projectPath, "--no-alt-screen"],
|
|
@@ -137950,7 +138180,7 @@ var CodexPtyRunner = class {
|
|
|
137950
138180
|
async startFresh(options) {
|
|
137951
138181
|
const nodePty = await loadPty();
|
|
137952
138182
|
const sessionId = (0, import_crypto6.randomUUID)();
|
|
137953
|
-
const projectName = options.projectName ?? (0,
|
|
138183
|
+
const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
|
|
137954
138184
|
const args = ["--cd", options.projectPath, "--no-alt-screen"];
|
|
137955
138185
|
if (options.systemPrompt) {
|
|
137956
138186
|
args.push(options.systemPrompt);
|
|
@@ -138242,7 +138472,7 @@ var CodexPtyRunner = class {
|
|
|
138242
138472
|
session.status = "idle";
|
|
138243
138473
|
const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
|
|
138244
138474
|
if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
|
|
138245
|
-
if (!(0,
|
|
138475
|
+
if (!(0, import_fs21.existsSync)(session.projectPath)) {
|
|
138246
138476
|
session.failureReason = `Project directory not found: ${session.projectPath}`;
|
|
138247
138477
|
} else {
|
|
138248
138478
|
session.failureReason = `Codex process exited immediately (code ${exitCode}).`;
|
|
@@ -138279,8 +138509,8 @@ function stripAnsi(str) {
|
|
|
138279
138509
|
// src/pty-manager.ts
|
|
138280
138510
|
var import_headless2 = __toESM(require_xterm_headless(), 1);
|
|
138281
138511
|
var import_crypto7 = require("crypto");
|
|
138282
|
-
var
|
|
138283
|
-
var
|
|
138512
|
+
var import_fs22 = require("fs");
|
|
138513
|
+
var import_path18 = require("path");
|
|
138284
138514
|
init_logger();
|
|
138285
138515
|
|
|
138286
138516
|
// src/services/questions/detectPermissionGate.ts
|
|
@@ -138632,7 +138862,7 @@ var PTYManager = class {
|
|
|
138632
138862
|
}
|
|
138633
138863
|
async doStart(sessionId, options) {
|
|
138634
138864
|
const nodePty = await loadPty2();
|
|
138635
|
-
const projectName = options.projectName ?? (0,
|
|
138865
|
+
const projectName = options.projectName ?? (0, import_path18.basename)(options.projectPath);
|
|
138636
138866
|
const proc = nodePty.spawn(
|
|
138637
138867
|
resolveClaudeExe(),
|
|
138638
138868
|
[
|
|
@@ -138683,7 +138913,7 @@ var PTYManager = class {
|
|
|
138683
138913
|
async startFresh(options) {
|
|
138684
138914
|
const nodePty = await loadPty2();
|
|
138685
138915
|
const sessionId = (0, import_crypto7.randomUUID)();
|
|
138686
|
-
const projectName = options.projectName ?? (0,
|
|
138916
|
+
const projectName = options.projectName ?? (0, import_path18.basename)(options.projectPath);
|
|
138687
138917
|
const args = [
|
|
138688
138918
|
"--permission-mode",
|
|
138689
138919
|
options.permissionMode ?? "acceptEdits",
|
|
@@ -139127,7 +139357,7 @@ var PTYManager = class {
|
|
|
139127
139357
|
session.status = "idle";
|
|
139128
139358
|
const elapsedMs = session.completedAt.getTime() - session.startedAt.getTime();
|
|
139129
139359
|
if (exitCode !== 0 && elapsedMs < 2e3 && session.lastOutput === "") {
|
|
139130
|
-
if (!(0,
|
|
139360
|
+
if (!(0, import_fs22.existsSync)(session.projectPath)) {
|
|
139131
139361
|
session.failureReason = `Project directory not found: ${session.projectPath}`;
|
|
139132
139362
|
} else {
|
|
139133
139363
|
session.failureReason = `Process exited immediately (code ${exitCode}). Check that the Claude binary is installed and accessible.`;
|
|
@@ -139255,7 +139485,7 @@ var LiveSessionManager = class {
|
|
|
139255
139485
|
const runner = this.runners.get(provider);
|
|
139256
139486
|
if (runner) return runner;
|
|
139257
139487
|
const err = new Error(
|
|
139258
|
-
`Live ${provider} sessions are not implemented yet for ${(0,
|
|
139488
|
+
`Live ${provider} sessions are not implemented yet for ${(0, import_path19.basename)(projectPath)}`
|
|
139259
139489
|
);
|
|
139260
139490
|
err.statusCode = 501;
|
|
139261
139491
|
throw err;
|
|
@@ -139322,7 +139552,7 @@ var PairTokenStore = class {
|
|
|
139322
139552
|
// src/process-discovery.ts
|
|
139323
139553
|
var import_child_process2 = require("child_process");
|
|
139324
139554
|
var import_os9 = require("os");
|
|
139325
|
-
var
|
|
139555
|
+
var import_path20 = require("path");
|
|
139326
139556
|
async function discoverClaudeProcesses() {
|
|
139327
139557
|
if ((0, import_os9.platform)() === "win32") return discoverWindows();
|
|
139328
139558
|
return discoverUnix();
|
|
@@ -139341,7 +139571,7 @@ async function discoverUnix() {
|
|
|
139341
139571
|
return {
|
|
139342
139572
|
pid,
|
|
139343
139573
|
projectPath: cwd,
|
|
139344
|
-
projectName: (0,
|
|
139574
|
+
projectName: (0, import_path20.basename)(cwd),
|
|
139345
139575
|
branch: await readGitBranch2(cwd),
|
|
139346
139576
|
conversationId,
|
|
139347
139577
|
startedAt
|
|
@@ -139363,7 +139593,7 @@ async function discoverWindows() {
|
|
|
139363
139593
|
return {
|
|
139364
139594
|
pid,
|
|
139365
139595
|
projectPath: info.cwd,
|
|
139366
|
-
projectName: (0,
|
|
139596
|
+
projectName: (0, import_path20.basename)(info.cwd),
|
|
139367
139597
|
branch: await readGitBranch2(info.cwd),
|
|
139368
139598
|
conversationId: extractResumeId(info.args),
|
|
139369
139599
|
startedAt: info.startedAt
|
|
@@ -139444,7 +139674,7 @@ async function getProcessInfoWindows(pid) {
|
|
|
139444
139674
|
const startedAt = /* @__PURE__ */ new Date(`${year}-${month}-${day}T${hour}:${min}:${sec}`);
|
|
139445
139675
|
if (Number.isNaN(startedAt.getTime())) return null;
|
|
139446
139676
|
const exePath = parts[3] ?? "";
|
|
139447
|
-
const cwd = exePath ? (0,
|
|
139677
|
+
const cwd = exePath ? (0, import_path20.dirname)(exePath) : "";
|
|
139448
139678
|
return { cwd, args, startedAt };
|
|
139449
139679
|
} catch {
|
|
139450
139680
|
return null;
|
|
@@ -139486,11 +139716,11 @@ function seal(plaintext, recipientPublicKeyBase64) {
|
|
|
139486
139716
|
// node_modules/chokidar/index.js
|
|
139487
139717
|
var import_node_events2 = require("events");
|
|
139488
139718
|
var import_node_fs7 = require("fs");
|
|
139489
|
-
var
|
|
139719
|
+
var import_promises14 = require("fs/promises");
|
|
139490
139720
|
var sp2 = __toESM(require("path"), 1);
|
|
139491
139721
|
|
|
139492
139722
|
// node_modules/readdirp/index.js
|
|
139493
|
-
var
|
|
139723
|
+
var import_promises12 = require("fs/promises");
|
|
139494
139724
|
var import_node_path9 = require("path");
|
|
139495
139725
|
var import_node_stream2 = require("stream");
|
|
139496
139726
|
var EntryTypes2 = {
|
|
@@ -139571,7 +139801,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139571
139801
|
const { root, type } = opts;
|
|
139572
139802
|
this._fileFilter = normalizeFilter2(opts.fileFilter);
|
|
139573
139803
|
this._directoryFilter = normalizeFilter2(opts.directoryFilter);
|
|
139574
|
-
const statMethod = opts.lstat ?
|
|
139804
|
+
const statMethod = opts.lstat ? import_promises12.lstat : import_promises12.stat;
|
|
139575
139805
|
if (wantBigintFsStats2) {
|
|
139576
139806
|
this._stat = (path2) => statMethod(path2, { bigint: true });
|
|
139577
139807
|
} else {
|
|
@@ -139642,7 +139872,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139642
139872
|
async _exploreDir(path2, depth) {
|
|
139643
139873
|
let files;
|
|
139644
139874
|
try {
|
|
139645
|
-
files = await (0,
|
|
139875
|
+
files = await (0, import_promises12.readdir)(path2, this._rdOptions);
|
|
139646
139876
|
} catch (error51) {
|
|
139647
139877
|
this._onError(error51);
|
|
139648
139878
|
}
|
|
@@ -139650,10 +139880,10 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139650
139880
|
}
|
|
139651
139881
|
async _formatEntry(dirent, path2) {
|
|
139652
139882
|
let entry;
|
|
139653
|
-
const
|
|
139883
|
+
const basename12 = this._isDirent ? dirent.name : dirent;
|
|
139654
139884
|
try {
|
|
139655
|
-
const fullPath = (0, import_node_path9.resolve)((0, import_node_path9.join)(path2,
|
|
139656
|
-
entry = { path: (0, import_node_path9.relative)(this._root, fullPath), fullPath, basename:
|
|
139885
|
+
const fullPath = (0, import_node_path9.resolve)((0, import_node_path9.join)(path2, basename12));
|
|
139886
|
+
entry = { path: (0, import_node_path9.relative)(this._root, fullPath), fullPath, basename: basename12 };
|
|
139657
139887
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
139658
139888
|
} catch (err) {
|
|
139659
139889
|
this._onError(err);
|
|
@@ -139680,8 +139910,8 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139680
139910
|
if (stats && stats.isSymbolicLink()) {
|
|
139681
139911
|
const full = entry.fullPath;
|
|
139682
139912
|
try {
|
|
139683
|
-
const entryRealPath = await (0,
|
|
139684
|
-
const entryRealPathStats = await (0,
|
|
139913
|
+
const entryRealPath = await (0, import_promises12.realpath)(full);
|
|
139914
|
+
const entryRealPathStats = await (0, import_promises12.lstat)(entryRealPath);
|
|
139685
139915
|
if (entryRealPathStats.isFile()) {
|
|
139686
139916
|
return "file";
|
|
139687
139917
|
}
|
|
@@ -139724,7 +139954,7 @@ function readdirp2(root, options = {}) {
|
|
|
139724
139954
|
|
|
139725
139955
|
// node_modules/chokidar/handler.js
|
|
139726
139956
|
var import_node_fs6 = require("fs");
|
|
139727
|
-
var
|
|
139957
|
+
var import_promises13 = require("fs/promises");
|
|
139728
139958
|
var import_node_os3 = require("os");
|
|
139729
139959
|
var sp = __toESM(require("path"), 1);
|
|
139730
139960
|
var STR_DATA2 = "data";
|
|
@@ -139751,7 +139981,7 @@ var EVENTS2 = {
|
|
|
139751
139981
|
};
|
|
139752
139982
|
var EV2 = EVENTS2;
|
|
139753
139983
|
var THROTTLE_MODE_WATCH2 = "watch";
|
|
139754
|
-
var statMethods2 = { lstat:
|
|
139984
|
+
var statMethods2 = { lstat: import_promises13.lstat, stat: import_promises13.stat };
|
|
139755
139985
|
var KEY_LISTENERS2 = "listeners";
|
|
139756
139986
|
var KEY_ERR2 = "errHandlers";
|
|
139757
139987
|
var KEY_RAW2 = "rawEmitters";
|
|
@@ -140108,7 +140338,7 @@ var setFsWatchListener2 = (path2, fullPath, options, handlers) => {
|
|
|
140108
140338
|
cont.watcherUnusable = true;
|
|
140109
140339
|
if (isWindows3 && error51.code === "EPERM") {
|
|
140110
140340
|
try {
|
|
140111
|
-
const fd = await (0,
|
|
140341
|
+
const fd = await (0, import_promises13.open)(path2, "r");
|
|
140112
140342
|
await fd.close();
|
|
140113
140343
|
broadcastErr(error51);
|
|
140114
140344
|
} catch (err) {
|
|
@@ -140194,9 +140424,9 @@ var NodeFsHandler2 = class {
|
|
|
140194
140424
|
_watchWithNodeFs(path2, listener) {
|
|
140195
140425
|
const opts = this.fsw.options;
|
|
140196
140426
|
const directory = sp.dirname(path2);
|
|
140197
|
-
const
|
|
140427
|
+
const basename12 = sp.basename(path2);
|
|
140198
140428
|
const parent = this.fsw._getWatchedDir(directory);
|
|
140199
|
-
parent.add(
|
|
140429
|
+
parent.add(basename12);
|
|
140200
140430
|
const absolutePath = sp.resolve(path2);
|
|
140201
140431
|
const options = {
|
|
140202
140432
|
persistent: opts.persistent
|
|
@@ -140206,7 +140436,7 @@ var NodeFsHandler2 = class {
|
|
|
140206
140436
|
let closer;
|
|
140207
140437
|
if (opts.usePolling) {
|
|
140208
140438
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
140209
|
-
options.interval = enableBin && isBinaryPath2(
|
|
140439
|
+
options.interval = enableBin && isBinaryPath2(basename12) ? opts.binaryInterval : opts.interval;
|
|
140210
140440
|
closer = setFsWatchFileListener2(path2, absolutePath, options, {
|
|
140211
140441
|
listener,
|
|
140212
140442
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -140229,17 +140459,17 @@ var NodeFsHandler2 = class {
|
|
|
140229
140459
|
return;
|
|
140230
140460
|
}
|
|
140231
140461
|
const dirname17 = sp.dirname(file2);
|
|
140232
|
-
const
|
|
140462
|
+
const basename12 = sp.basename(file2);
|
|
140233
140463
|
const parent = this.fsw._getWatchedDir(dirname17);
|
|
140234
140464
|
let prevStats = stats;
|
|
140235
|
-
if (parent.has(
|
|
140465
|
+
if (parent.has(basename12))
|
|
140236
140466
|
return;
|
|
140237
140467
|
const listener = async (path2, newStats) => {
|
|
140238
140468
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH2, file2, 5))
|
|
140239
140469
|
return;
|
|
140240
140470
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
140241
140471
|
try {
|
|
140242
|
-
const newStats2 = await (0,
|
|
140472
|
+
const newStats2 = await (0, import_promises13.stat)(file2);
|
|
140243
140473
|
if (this.fsw.closed)
|
|
140244
140474
|
return;
|
|
140245
140475
|
const at2 = newStats2.atimeMs;
|
|
@@ -140257,9 +140487,9 @@ var NodeFsHandler2 = class {
|
|
|
140257
140487
|
prevStats = newStats2;
|
|
140258
140488
|
}
|
|
140259
140489
|
} catch (error51) {
|
|
140260
|
-
this.fsw._remove(dirname17,
|
|
140490
|
+
this.fsw._remove(dirname17, basename12);
|
|
140261
140491
|
}
|
|
140262
|
-
} else if (parent.has(
|
|
140492
|
+
} else if (parent.has(basename12)) {
|
|
140263
140493
|
const at2 = newStats.atimeMs;
|
|
140264
140494
|
const mt2 = newStats.mtimeMs;
|
|
140265
140495
|
if (!at2 || at2 <= mt2 || mt2 !== prevStats.mtimeMs) {
|
|
@@ -140294,7 +140524,7 @@ var NodeFsHandler2 = class {
|
|
|
140294
140524
|
this.fsw._incrReadyCount();
|
|
140295
140525
|
let linkPath;
|
|
140296
140526
|
try {
|
|
140297
|
-
linkPath = await (0,
|
|
140527
|
+
linkPath = await (0, import_promises13.realpath)(path2);
|
|
140298
140528
|
} catch (e) {
|
|
140299
140529
|
this.fsw._emitReady();
|
|
140300
140530
|
return true;
|
|
@@ -140443,7 +140673,7 @@ var NodeFsHandler2 = class {
|
|
|
140443
140673
|
let closer;
|
|
140444
140674
|
if (stats.isDirectory()) {
|
|
140445
140675
|
const absPath = sp.resolve(path2);
|
|
140446
|
-
const targetPath = follow ? await (0,
|
|
140676
|
+
const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
|
|
140447
140677
|
if (this.fsw.closed)
|
|
140448
140678
|
return;
|
|
140449
140679
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -140453,7 +140683,7 @@ var NodeFsHandler2 = class {
|
|
|
140453
140683
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
140454
140684
|
}
|
|
140455
140685
|
} else if (stats.isSymbolicLink()) {
|
|
140456
|
-
const targetPath = follow ? await (0,
|
|
140686
|
+
const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
|
|
140457
140687
|
if (this.fsw.closed)
|
|
140458
140688
|
return;
|
|
140459
140689
|
const parent = sp.dirname(wh.watchPath);
|
|
@@ -140613,7 +140843,7 @@ var DirEntry2 = class {
|
|
|
140613
140843
|
return;
|
|
140614
140844
|
const dir = this.path;
|
|
140615
140845
|
try {
|
|
140616
|
-
await (0,
|
|
140846
|
+
await (0, import_promises14.readdir)(dir);
|
|
140617
140847
|
} catch (err) {
|
|
140618
140848
|
if (this._removeWatcher) {
|
|
140619
140849
|
this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
|
|
@@ -140963,7 +141193,7 @@ var FSWatcher2 = class extends import_node_events2.EventEmitter {
|
|
|
140963
141193
|
const fullPath = opts.cwd ? sp2.join(opts.cwd, path2) : path2;
|
|
140964
141194
|
let stats2;
|
|
140965
141195
|
try {
|
|
140966
|
-
stats2 = await (0,
|
|
141196
|
+
stats2 = await (0, import_promises14.stat)(fullPath);
|
|
140967
141197
|
} catch (err) {
|
|
140968
141198
|
}
|
|
140969
141199
|
if (!stats2 || this.closed)
|
|
@@ -141216,8 +141446,8 @@ function watch2(paths, options = {}) {
|
|
|
141216
141446
|
var chokidar_default = { watch: watch2, FSWatcher: FSWatcher2 };
|
|
141217
141447
|
|
|
141218
141448
|
// src/services/conversations/conversationWatcher.ts
|
|
141219
|
-
var
|
|
141220
|
-
var
|
|
141449
|
+
var import_fs23 = require("fs");
|
|
141450
|
+
var import_promises15 = require("fs/promises");
|
|
141221
141451
|
var ConversationWatcher = class {
|
|
141222
141452
|
files = /* @__PURE__ */ new Map();
|
|
141223
141453
|
directories = /* @__PURE__ */ new Map();
|
|
@@ -141237,7 +141467,7 @@ var ConversationWatcher = class {
|
|
|
141237
141467
|
if (this.files.has(filePath)) return;
|
|
141238
141468
|
let offset;
|
|
141239
141469
|
try {
|
|
141240
|
-
offset = (0,
|
|
141470
|
+
offset = (0, import_fs23.statSync)(filePath).size;
|
|
141241
141471
|
} catch {
|
|
141242
141472
|
offset = 0;
|
|
141243
141473
|
}
|
|
@@ -141321,12 +141551,12 @@ var ConversationWatcher = class {
|
|
|
141321
141551
|
entry.reading = true;
|
|
141322
141552
|
try {
|
|
141323
141553
|
for (; ; ) {
|
|
141324
|
-
const st2 = await (0,
|
|
141554
|
+
const st2 = await (0, import_promises15.stat)(filePath);
|
|
141325
141555
|
if (st2.size <= entry.offset) break;
|
|
141326
141556
|
const readFrom = entry.offset;
|
|
141327
141557
|
const bytesToRead = st2.size - readFrom;
|
|
141328
141558
|
const buf = Buffer.alloc(bytesToRead);
|
|
141329
|
-
const fh = await (0,
|
|
141559
|
+
const fh = await (0, import_promises15.open)(filePath, "r");
|
|
141330
141560
|
try {
|
|
141331
141561
|
await fh.read(buf, 0, bytesToRead, readFrom);
|
|
141332
141562
|
} finally {
|
|
@@ -141408,14 +141638,14 @@ function findSearchTarget(messages, query) {
|
|
|
141408
141638
|
}
|
|
141409
141639
|
|
|
141410
141640
|
// src/services/conversations/pruneAgentConversations.ts
|
|
141411
|
-
var
|
|
141641
|
+
var import_fs24 = require("fs");
|
|
141412
141642
|
function pruneAgentConversations(cache) {
|
|
141413
141643
|
const db = cache.getDatabase();
|
|
141414
141644
|
const rows = db.prepare("SELECT id, file_path FROM conversation_meta").all();
|
|
141415
141645
|
let pruned = 0;
|
|
141416
141646
|
let missing = 0;
|
|
141417
141647
|
for (const row of rows) {
|
|
141418
|
-
if (!(0,
|
|
141648
|
+
if (!(0, import_fs24.existsSync)(row.file_path)) {
|
|
141419
141649
|
missing += 1;
|
|
141420
141650
|
continue;
|
|
141421
141651
|
}
|
|
@@ -141775,9 +142005,9 @@ function discoveredToResponse(d, conversationId) {
|
|
|
141775
142005
|
|
|
141776
142006
|
// src/uploads.ts
|
|
141777
142007
|
var import_crypto9 = require("crypto");
|
|
141778
|
-
var
|
|
142008
|
+
var import_promises16 = require("fs/promises");
|
|
141779
142009
|
var import_heic_convert = __toESM(require_heic_convert(), 1);
|
|
141780
|
-
var
|
|
142010
|
+
var import_path21 = require("path");
|
|
141781
142011
|
var UPLOAD_DIR_NAME = ".threadbase-uploads";
|
|
141782
142012
|
var MAX_BYTES = 25 * 1024 * 1024;
|
|
141783
142013
|
var HEIC_MIMES = /* @__PURE__ */ new Set(["image/heic", "image/heif"]);
|
|
@@ -141810,10 +142040,10 @@ async function saveUploadFile(input) {
|
|
|
141810
142040
|
}
|
|
141811
142041
|
const id = `up_${(0, import_crypto9.randomBytes)(8).toString("hex")}`;
|
|
141812
142042
|
const safeName = sanitizeFilename(originalName) || `file${MIME_TO_EXT[mimeType] ?? ""}`;
|
|
141813
|
-
const dir = (0,
|
|
141814
|
-
await (0,
|
|
141815
|
-
const filePath = (0,
|
|
141816
|
-
await (0,
|
|
142043
|
+
const dir = (0, import_path21.join)(input.projectPath, UPLOAD_DIR_NAME, input.sessionId);
|
|
142044
|
+
await (0, import_promises16.mkdir)(dir, { recursive: true });
|
|
142045
|
+
const filePath = (0, import_path21.join)(dir, `${Date.now()}-${id}-${safeName}`);
|
|
142046
|
+
await (0, import_promises16.writeFile)(filePath, buffer);
|
|
141817
142047
|
return {
|
|
141818
142048
|
id,
|
|
141819
142049
|
filePath,
|
|
@@ -142197,6 +142427,7 @@ var WSHub = class {
|
|
|
142197
142427
|
var BROWSE_SYSTEM_PROMPT = (browseRoot) => `You are working within the project boundary: ${browseRoot}. Do not read, write, or execute commands that access files or directories outside this boundary.`;
|
|
142198
142428
|
var DEFAULT_SYSTEM_PROMPT = "When presenting options or choices to the user, limit the options to at most 3.";
|
|
142199
142429
|
var DEFAULT_PTY_GRACE_PERIOD_MS = 27e4;
|
|
142430
|
+
var REFRESH_TTL_MS = 2e3;
|
|
142200
142431
|
var START_READY_TIMEOUT_MS = 15e3;
|
|
142201
142432
|
function parseIncludeAgentsEnv(raw2) {
|
|
142202
142433
|
if (raw2 === void 0) return false;
|
|
@@ -142236,6 +142467,12 @@ var StreamerServer = class {
|
|
|
142236
142467
|
// Set by onConversationChanged while a scan is in-flight; getScanner() does
|
|
142237
142468
|
// a single rescan after the current one completes instead of restarting it.
|
|
142238
142469
|
scannerStale = false;
|
|
142470
|
+
// Single-flight + TTL guard around scanner.refreshFile (see refreshFileGuarded).
|
|
142471
|
+
// A live file's mtime is always newer than the snapshot, so an unguarded
|
|
142472
|
+
// refresh fires on every request and re-parses the whole file from byte 0.
|
|
142473
|
+
// Keyed by filePath; entries drop on settle + TTL expiry, so the map stays
|
|
142474
|
+
// bounded by the active-file set.
|
|
142475
|
+
refreshInFlight = /* @__PURE__ */ new Map();
|
|
142239
142476
|
// True only while bindWithRetry is actively retrying. The persistent
|
|
142240
142477
|
// listener-level 'error' handler demotes EADDRINUSE to debug during this
|
|
142241
142478
|
// window so the self-healing kickstart-relaunch race doesn't spam warn.
|
|
@@ -142313,11 +142550,11 @@ var StreamerServer = class {
|
|
|
142313
142550
|
this.disableDb = config2.disableDb ?? false;
|
|
142314
142551
|
this.scannerPersistenceDisabled = config2.scannerPersistent === false;
|
|
142315
142552
|
this.scanProfiles = config2.scanProfiles;
|
|
142316
|
-
this.codexRoots = config2.codexRoots ?? [(0,
|
|
142553
|
+
this.codexRoots = config2.codexRoots ?? [(0, import_path22.join)((0, import_os10.homedir)(), ".codex", "sessions")];
|
|
142317
142554
|
this.ptyGracePeriodMs = config2.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
|
|
142318
142555
|
this.defaultSystemPrompt = config2.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
142319
142556
|
this.defaultPermissionMode = config2.defaultPermissionMode ?? loadDefaultPermissionMode() ?? "acceptEdits";
|
|
142320
|
-
this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0,
|
|
142557
|
+
this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0, import_path22.join)((0, import_os10.homedir)(), ".threadbase", "cache");
|
|
142321
142558
|
this.tailSize = config2.tailSize ?? loadTailSize() ?? 10;
|
|
142322
142559
|
this.directoryDebounceMs = parseDirScanDebounceEnv(process.env.THREADBASE_DIR_SCAN_DEBOUNCE_MS) ?? config2.directoryScanDebounceMs ?? 1e3;
|
|
142323
142560
|
this.markScannerStaleDebounced = debounce(() => {
|
|
@@ -142328,7 +142565,7 @@ var StreamerServer = class {
|
|
|
142328
142565
|
this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
|
|
142329
142566
|
const rawRoot = process.env.THREADBASE_BROWSE_ROOT ?? loadBrowseRoot() ?? config2.browseRoot;
|
|
142330
142567
|
if (rawRoot) {
|
|
142331
|
-
(0,
|
|
142568
|
+
(0, import_promises17.realpath)(rawRoot).then((resolved) => {
|
|
142332
142569
|
this.browseRoot = resolved;
|
|
142333
142570
|
if (this.verbose) this.log.info(`Browse root: ${resolved}`, { browseRoot: resolved });
|
|
142334
142571
|
}).catch(() => {
|
|
@@ -142434,7 +142671,7 @@ var StreamerServer = class {
|
|
|
142434
142671
|
if (session.status === "waiting_input" || session.status === "idle") {
|
|
142435
142672
|
const filePath = this.sessionFileMap.get(session.id);
|
|
142436
142673
|
if (filePath) {
|
|
142437
|
-
this.getScanner().then((scanner) =>
|
|
142674
|
+
this.getScanner().then((scanner) => this.refreshFileGuarded(scanner, filePath)).then((meta3) => {
|
|
142438
142675
|
this.log.info("scanner.refreshFile: ok", {
|
|
142439
142676
|
event: "scanner.refresh",
|
|
142440
142677
|
sessionId: session.id,
|
|
@@ -142484,7 +142721,7 @@ var StreamerServer = class {
|
|
|
142484
142721
|
temporalClient,
|
|
142485
142722
|
taskQueue: agentConfig.temporal.taskQueue
|
|
142486
142723
|
});
|
|
142487
|
-
const conversationsBaseDir = agentConfig.conversationsDir || (0,
|
|
142724
|
+
const conversationsBaseDir = agentConfig.conversationsDir || (0, import_path22.join)((0, import_path22.dirname)(this.cacheDir), "conversations");
|
|
142488
142725
|
conversationWriter = createConversationWriter({
|
|
142489
142726
|
baseDir: conversationsBaseDir
|
|
142490
142727
|
});
|
|
@@ -142708,7 +142945,7 @@ var StreamerServer = class {
|
|
|
142708
142945
|
});
|
|
142709
142946
|
try {
|
|
142710
142947
|
this.cache = ConversationCache.open(
|
|
142711
|
-
(0,
|
|
142948
|
+
(0, import_path22.join)(this.cacheDir, "cache.db"),
|
|
142712
142949
|
this.tailSize,
|
|
142713
142950
|
void 0,
|
|
142714
142951
|
{
|
|
@@ -142734,11 +142971,11 @@ var StreamerServer = class {
|
|
|
142734
142971
|
if (this.scanProfiles && this.scanProfiles.length > 0) {
|
|
142735
142972
|
for (const profile of this.scanProfiles) {
|
|
142736
142973
|
if (profile.enabled) {
|
|
142737
|
-
this.fileWatcher.watchDirectory((0,
|
|
142974
|
+
this.fileWatcher.watchDirectory((0, import_path22.join)(profile.configDir, "projects"));
|
|
142738
142975
|
}
|
|
142739
142976
|
}
|
|
142740
142977
|
} else {
|
|
142741
|
-
this.fileWatcher.watchDirectory((0,
|
|
142978
|
+
this.fileWatcher.watchDirectory((0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects"));
|
|
142742
142979
|
}
|
|
142743
142980
|
} catch (err) {
|
|
142744
142981
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -142883,6 +143120,34 @@ var StreamerServer = class {
|
|
|
142883
143120
|
this.inFlightCacheWrites.delete(guarded);
|
|
142884
143121
|
});
|
|
142885
143122
|
}
|
|
143123
|
+
// Single-flight + TTL wrapper for scanner.refreshFile. Both call sites (the
|
|
143124
|
+
// detail-stale branch and the per-turn refresh) route through here so that
|
|
143125
|
+
// N stacked retries on a live, actively-appended file cost one parse, not N:
|
|
143126
|
+
// - a refresh already in flight for the path → await the same promise;
|
|
143127
|
+
// - a refresh that settled within REFRESH_TTL_MS → skip, return null (the
|
|
143128
|
+
// caller keeps serving the current snapshot);
|
|
143129
|
+
// - otherwise start one, cache the promise, and stamp completedAt on settle.
|
|
143130
|
+
// The map is bounded by the active-file set (entries only live while a
|
|
143131
|
+
// refresh is in flight or within its TTL and are overwritten on the next
|
|
143132
|
+
// refresh of the same path).
|
|
143133
|
+
refreshFileGuarded(scanner, filePath) {
|
|
143134
|
+
const existing = this.refreshInFlight.get(filePath);
|
|
143135
|
+
if (existing) {
|
|
143136
|
+
const settled = existing.completedAt > 0;
|
|
143137
|
+
if (!settled) {
|
|
143138
|
+
return existing.promise;
|
|
143139
|
+
}
|
|
143140
|
+
if (Date.now() - existing.completedAt < REFRESH_TTL_MS) {
|
|
143141
|
+
return Promise.resolve(null);
|
|
143142
|
+
}
|
|
143143
|
+
}
|
|
143144
|
+
const entry = { promise: Promise.resolve(null), completedAt: 0 };
|
|
143145
|
+
entry.promise = scanner.refreshFile(filePath).finally(() => {
|
|
143146
|
+
entry.completedAt = Date.now();
|
|
143147
|
+
});
|
|
143148
|
+
this.refreshInFlight.set(filePath, entry);
|
|
143149
|
+
return entry.promise;
|
|
143150
|
+
}
|
|
142886
143151
|
async close() {
|
|
142887
143152
|
for (const timer of this.ptyGraceTimers.values()) clearTimeout(timer);
|
|
142888
143153
|
this.ptyGraceTimers.clear();
|
|
@@ -143292,17 +143557,17 @@ var StreamerServer = class {
|
|
|
143292
143557
|
return scanner;
|
|
143293
143558
|
}
|
|
143294
143559
|
findJsonlPath(uuid3) {
|
|
143295
|
-
const projectsDir = (0,
|
|
143296
|
-
if (!(0,
|
|
143560
|
+
const projectsDir = (0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects");
|
|
143561
|
+
if (!(0, import_fs25.existsSync)(projectsDir)) return null;
|
|
143297
143562
|
const filename = `${uuid3}.jsonl`;
|
|
143298
|
-
for (const dir of (0,
|
|
143299
|
-
const fp = (0,
|
|
143300
|
-
if ((0,
|
|
143301
|
-
const projectDir = (0,
|
|
143563
|
+
for (const dir of (0, import_fs25.readdirSync)(projectsDir)) {
|
|
143564
|
+
const fp = (0, import_path22.join)(projectsDir, dir, filename);
|
|
143565
|
+
if ((0, import_fs25.existsSync)(fp)) return fp;
|
|
143566
|
+
const projectDir = (0, import_path22.join)(projectsDir, dir);
|
|
143302
143567
|
try {
|
|
143303
|
-
for (const sub of (0,
|
|
143304
|
-
const subagentPath = (0,
|
|
143305
|
-
if ((0,
|
|
143568
|
+
for (const sub of (0, import_fs25.readdirSync)(projectDir)) {
|
|
143569
|
+
const subagentPath = (0, import_path22.join)(projectDir, sub, "subagents", filename);
|
|
143570
|
+
if ((0, import_fs25.existsSync)(subagentPath)) return subagentPath;
|
|
143306
143571
|
}
|
|
143307
143572
|
} catch {
|
|
143308
143573
|
}
|
|
@@ -143311,7 +143576,7 @@ var StreamerServer = class {
|
|
|
143311
143576
|
}
|
|
143312
143577
|
async readCwdFromJsonl(filePath) {
|
|
143313
143578
|
return new Promise((resolve6) => {
|
|
143314
|
-
const rl = (0, import_readline4.createInterface)({ input: (0,
|
|
143579
|
+
const rl = (0, import_readline4.createInterface)({ input: (0, import_fs25.createReadStream)(filePath), crlfDelay: Infinity });
|
|
143315
143580
|
let found = false;
|
|
143316
143581
|
rl.on("line", (line) => {
|
|
143317
143582
|
if (found) return;
|
|
@@ -143347,10 +143612,22 @@ var StreamerServer = class {
|
|
|
143347
143612
|
const scanner = await this.getScanner(true);
|
|
143348
143613
|
const fromIndex = await scanner.getConversation(uuid3);
|
|
143349
143614
|
if (fromIndex) {
|
|
143615
|
+
if (this.ptyManager.hasSession(uuid3)) {
|
|
143616
|
+
return fromIndex;
|
|
143617
|
+
}
|
|
143350
143618
|
if (fromIndex.filePath && this.isConversationSnapshotStale(fromIndex)) {
|
|
143351
|
-
const
|
|
143352
|
-
|
|
143353
|
-
|
|
143619
|
+
const filePath2 = fromIndex.filePath;
|
|
143620
|
+
this.trackCacheWrite(
|
|
143621
|
+
this.refreshFileGuarded(scanner, filePath2).catch((err) => {
|
|
143622
|
+
this.log.warn("scanner.refreshFile: failed", {
|
|
143623
|
+
event: "scanner.refresh_failed",
|
|
143624
|
+
conversationId: uuid3,
|
|
143625
|
+
filePath: filePath2,
|
|
143626
|
+
trigger: "detail-swr",
|
|
143627
|
+
err
|
|
143628
|
+
});
|
|
143629
|
+
})
|
|
143630
|
+
);
|
|
143354
143631
|
}
|
|
143355
143632
|
return fromIndex;
|
|
143356
143633
|
}
|
|
@@ -143368,7 +143645,7 @@ var StreamerServer = class {
|
|
|
143368
143645
|
if (!conv.filePath) return false;
|
|
143369
143646
|
let mtimeMs = null;
|
|
143370
143647
|
try {
|
|
143371
|
-
mtimeMs = (0,
|
|
143648
|
+
mtimeMs = (0, import_fs25.statSync)(conv.filePath).mtimeMs;
|
|
143372
143649
|
} catch {
|
|
143373
143650
|
return false;
|
|
143374
143651
|
}
|
|
@@ -143698,7 +143975,7 @@ var StreamerServer = class {
|
|
|
143698
143975
|
handleGetSession(sessionId, res) {
|
|
143699
143976
|
const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
|
|
143700
143977
|
if (session) {
|
|
143701
|
-
if (!(0,
|
|
143978
|
+
if (!(0, import_fs25.existsSync)(session.projectPath)) {
|
|
143702
143979
|
session.failureReason = `Project directory not found: ${session.projectPath}`;
|
|
143703
143980
|
}
|
|
143704
143981
|
json2(res, 200, session);
|
|
@@ -144094,7 +144371,7 @@ var StreamerServer = class {
|
|
|
144094
144371
|
sessionStore: this.sessionStore,
|
|
144095
144372
|
// biome-ignore lint/style/noNonNullAssertion: agentClient is set when agentConfig.enabled is true
|
|
144096
144373
|
agentClient: this.agentClient,
|
|
144097
|
-
conversationsDir: this.cacheDir ? (0,
|
|
144374
|
+
conversationsDir: this.cacheDir ? (0, import_path22.join)((0, import_path22.dirname)(this.cacheDir), "conversations") : "",
|
|
144098
144375
|
agentConfig: this.agentConfig
|
|
144099
144376
|
});
|
|
144100
144377
|
json2(res, result.status, result.body);
|
|
@@ -144235,9 +144512,9 @@ var StreamerServer = class {
|
|
|
144235
144512
|
// was passed to Claude via --session-id so the filename matches from the start.
|
|
144236
144513
|
watchForJsonl(sessionId, projectPath) {
|
|
144237
144514
|
const encoded = projectPath.replace(/[/\\:.]/g, "-");
|
|
144238
|
-
const projectsDir = (0,
|
|
144515
|
+
const projectsDir = (0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects", encoded);
|
|
144239
144516
|
const expectedFile = `${sessionId}.jsonl`;
|
|
144240
|
-
const filePath = (0,
|
|
144517
|
+
const filePath = (0, import_path22.join)(projectsDir, expectedFile);
|
|
144241
144518
|
const deadline = Date.now() + 12e4;
|
|
144242
144519
|
let watcher = null;
|
|
144243
144520
|
const cleanup = () => {
|
|
@@ -144255,12 +144532,12 @@ var StreamerServer = class {
|
|
|
144255
144532
|
cleanup();
|
|
144256
144533
|
return;
|
|
144257
144534
|
}
|
|
144258
|
-
let resolvedFilePath = (0,
|
|
144259
|
-
if (!resolvedFilePath && (0,
|
|
144535
|
+
let resolvedFilePath = (0, import_fs25.existsSync)(filePath) ? filePath : null;
|
|
144536
|
+
if (!resolvedFilePath && (0, import_fs25.existsSync)(projectsDir)) {
|
|
144260
144537
|
try {
|
|
144261
144538
|
const now = Date.now();
|
|
144262
|
-
const recent = (0,
|
|
144263
|
-
if (recent) resolvedFilePath = (0,
|
|
144539
|
+
const recent = (0, import_fs25.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs25.statSync)((0, import_path22.join)(projectsDir, f2)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).sort((a, b2) => b2.mtime - a.mtime)[0];
|
|
144540
|
+
if (recent) resolvedFilePath = (0, import_path22.join)(projectsDir, recent.f);
|
|
144264
144541
|
} catch {
|
|
144265
144542
|
}
|
|
144266
144543
|
}
|
|
@@ -144269,7 +144546,7 @@ var StreamerServer = class {
|
|
|
144269
144546
|
this.sessionFileMap.set(sessionId, resolvedFilePath);
|
|
144270
144547
|
this.fileWatcher.watch(resolvedFilePath);
|
|
144271
144548
|
try {
|
|
144272
|
-
const existing = (0,
|
|
144549
|
+
const existing = (0, import_fs25.readFileSync)(resolvedFilePath, "utf8").split("\n").filter(Boolean);
|
|
144273
144550
|
if (existing.length > 0) {
|
|
144274
144551
|
this.wsHub.broadcast({ type: "conversation_events", sessionId, lines: existing });
|
|
144275
144552
|
for (const line of existing) {
|
|
@@ -144295,7 +144572,7 @@ var StreamerServer = class {
|
|
|
144295
144572
|
if (this.sessionFileMap.has(sessionId)) return;
|
|
144296
144573
|
try {
|
|
144297
144574
|
require("fs").mkdirSync(projectsDir, { recursive: true });
|
|
144298
|
-
watcher = (0,
|
|
144575
|
+
watcher = (0, import_fs25.watch)(projectsDir, tryWire);
|
|
144299
144576
|
watcher.on("error", cleanup);
|
|
144300
144577
|
} catch {
|
|
144301
144578
|
}
|
|
@@ -144311,7 +144588,7 @@ var StreamerServer = class {
|
|
|
144311
144588
|
watchForCodexRollout(sessionId, projectPath) {
|
|
144312
144589
|
const deadline = Date.now() + 12e4;
|
|
144313
144590
|
const now = /* @__PURE__ */ new Date();
|
|
144314
|
-
const dateDir = (0,
|
|
144591
|
+
const dateDir = (0, import_path22.join)(
|
|
144315
144592
|
String(now.getFullYear()),
|
|
144316
144593
|
String(now.getMonth() + 1).padStart(2, "0"),
|
|
144317
144594
|
String(now.getDate()).padStart(2, "0")
|
|
@@ -144324,7 +144601,7 @@ var StreamerServer = class {
|
|
|
144324
144601
|
};
|
|
144325
144602
|
const matchesProjectPath = (candidatePath) => {
|
|
144326
144603
|
try {
|
|
144327
|
-
const firstLine = (0,
|
|
144604
|
+
const firstLine = (0, import_fs25.readFileSync)(candidatePath, "utf8").split("\n", 1)[0];
|
|
144328
144605
|
if (!firstLine) return null;
|
|
144329
144606
|
const parsed = JSON.parse(firstLine);
|
|
144330
144607
|
if (parsed?.type !== "session_meta") return null;
|
|
@@ -144352,18 +144629,18 @@ var StreamerServer = class {
|
|
|
144352
144629
|
this.sessionStore.listManaged().filter((s3) => s3.id !== sessionId && s3.boundConversationId != null).map((s3) => s3.boundConversationId)
|
|
144353
144630
|
);
|
|
144354
144631
|
for (const root of this.codexRoots) {
|
|
144355
|
-
const sessionsDir = (0,
|
|
144356
|
-
if (!(0,
|
|
144632
|
+
const sessionsDir = (0, import_path22.join)(root, dateDir);
|
|
144633
|
+
if (!(0, import_fs25.existsSync)(sessionsDir)) continue;
|
|
144357
144634
|
let candidateFiles;
|
|
144358
144635
|
try {
|
|
144359
|
-
candidateFiles = (0,
|
|
144636
|
+
candidateFiles = (0, import_fs25.readdirSync)(sessionsDir).filter((f2) => f2.endsWith(".jsonl"));
|
|
144360
144637
|
} catch {
|
|
144361
144638
|
continue;
|
|
144362
144639
|
}
|
|
144363
144640
|
const nowMs = Date.now();
|
|
144364
|
-
const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0,
|
|
144641
|
+
const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs25.statSync)((0, import_path22.join)(sessionsDir, f2)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b2) => b2.mtime - a.mtime);
|
|
144365
144642
|
for (const { f: f2 } of recentCandidates) {
|
|
144366
|
-
const candidatePath = (0,
|
|
144643
|
+
const candidatePath = (0, import_path22.join)(sessionsDir, f2);
|
|
144367
144644
|
const match2 = matchesProjectPath(candidatePath);
|
|
144368
144645
|
if (!match2) continue;
|
|
144369
144646
|
if (boundElsewhere.has(match2.id)) continue;
|
|
@@ -144373,7 +144650,7 @@ var StreamerServer = class {
|
|
|
144373
144650
|
this.sessionFileMap.set(sessionId, candidatePath);
|
|
144374
144651
|
this.fileWatcher.watch(candidatePath);
|
|
144375
144652
|
try {
|
|
144376
|
-
const existing = (0,
|
|
144653
|
+
const existing = (0, import_fs25.readFileSync)(candidatePath, "utf8").split("\n").filter(Boolean);
|
|
144377
144654
|
if (existing.length > 0) {
|
|
144378
144655
|
this.wsHub.broadcast({ type: "conversation_events", sessionId, lines: existing });
|
|
144379
144656
|
for (const line of existing) {
|
|
@@ -144498,7 +144775,7 @@ var StreamerServer = class {
|
|
|
144498
144775
|
};
|
|
144499
144776
|
function classifyResumability(cwd) {
|
|
144500
144777
|
if (!cwd) return { resumable: true };
|
|
144501
|
-
if ((0,
|
|
144778
|
+
if ((0, import_fs25.existsSync)(cwd)) return { resumable: true };
|
|
144502
144779
|
const ranInWorktree = /\/\.worktrees\//.test(cwd) || /\/\.claude\/worktrees\//.test(cwd);
|
|
144503
144780
|
return {
|
|
144504
144781
|
resumable: false,
|
|
@@ -144817,7 +145094,7 @@ function isBrewInstall(scriptPath = process.argv[1] ?? "") {
|
|
|
144817
145094
|
var import_node_crypto4 = require("crypto");
|
|
144818
145095
|
var import_node_fs8 = require("fs");
|
|
144819
145096
|
var import_node_path10 = require("path");
|
|
144820
|
-
var
|
|
145097
|
+
var import_promises18 = require("stream/promises");
|
|
144821
145098
|
|
|
144822
145099
|
// src/updater/manifest.ts
|
|
144823
145100
|
init_zod();
|
|
@@ -144892,7 +145169,7 @@ async function downloadAndVerify(opts) {
|
|
|
144892
145169
|
}
|
|
144893
145170
|
});
|
|
144894
145171
|
try {
|
|
144895
|
-
await (0,
|
|
145172
|
+
await (0, import_promises18.pipeline)(res.body.pipeThrough(measured), out);
|
|
144896
145173
|
} catch (err) {
|
|
144897
145174
|
(0, import_node_fs8.rmSync)(targetPath, { force: true });
|
|
144898
145175
|
throw err;
|
|
@@ -145078,13 +145355,13 @@ var import_node_fs17 = require("fs");
|
|
|
145078
145355
|
|
|
145079
145356
|
// node_modules/tar/dist/esm/index.min.js
|
|
145080
145357
|
var import_events4 = __toESM(require("events"), 1);
|
|
145081
|
-
var
|
|
145358
|
+
var import_fs26 = __toESM(require("fs"), 1);
|
|
145082
145359
|
var import_node_events3 = require("events");
|
|
145083
145360
|
var import_node_stream3 = __toESM(require("stream"), 1);
|
|
145084
145361
|
var import_node_string_decoder = require("string_decoder");
|
|
145085
145362
|
var import_node_path14 = __toESM(require("path"), 1);
|
|
145086
145363
|
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
145087
|
-
var
|
|
145364
|
+
var import_path23 = require("path");
|
|
145088
145365
|
var import_events5 = require("events");
|
|
145089
145366
|
var import_assert = __toESM(require("assert"), 1);
|
|
145090
145367
|
var import_buffer2 = require("buffer");
|
|
@@ -145092,21 +145369,21 @@ var Ps = __toESM(require("zlib"), 1);
|
|
|
145092
145369
|
var import_zlib = __toESM(require("zlib"), 1);
|
|
145093
145370
|
var import_node_path15 = require("path");
|
|
145094
145371
|
var import_node_path16 = require("path");
|
|
145095
|
-
var import_fs26 = __toESM(require("fs"), 1);
|
|
145096
145372
|
var import_fs27 = __toESM(require("fs"), 1);
|
|
145097
|
-
var
|
|
145098
|
-
var import_node_path17 = require("path");
|
|
145373
|
+
var import_fs28 = __toESM(require("fs"), 1);
|
|
145099
145374
|
var import_path24 = __toESM(require("path"), 1);
|
|
145375
|
+
var import_node_path17 = require("path");
|
|
145376
|
+
var import_path25 = __toESM(require("path"), 1);
|
|
145100
145377
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
145101
145378
|
var import_node_assert = __toESM(require("assert"), 1);
|
|
145102
145379
|
var import_node_crypto5 = require("crypto");
|
|
145103
145380
|
var import_node_fs13 = __toESM(require("fs"), 1);
|
|
145104
145381
|
var import_node_path18 = __toESM(require("path"), 1);
|
|
145105
|
-
var
|
|
145382
|
+
var import_fs29 = __toESM(require("fs"), 1);
|
|
145106
145383
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
145107
145384
|
var import_node_path19 = __toESM(require("path"), 1);
|
|
145108
145385
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
145109
|
-
var
|
|
145386
|
+
var import_promises19 = __toESM(require("fs/promises"), 1);
|
|
145110
145387
|
var import_node_path20 = __toESM(require("path"), 1);
|
|
145111
145388
|
var import_node_path21 = require("path");
|
|
145112
145389
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
@@ -145454,7 +145731,7 @@ var A = class extends import_node_events3.EventEmitter {
|
|
|
145454
145731
|
return Wr;
|
|
145455
145732
|
}
|
|
145456
145733
|
};
|
|
145457
|
-
var Jr =
|
|
145734
|
+
var Jr = import_fs26.default.writev;
|
|
145458
145735
|
var ht = /* @__PURE__ */ Symbol("_autoClose");
|
|
145459
145736
|
var H = /* @__PURE__ */ Symbol("_close");
|
|
145460
145737
|
var te = /* @__PURE__ */ Symbol("_ended");
|
|
@@ -145509,7 +145786,7 @@ var _t = class extends A {
|
|
|
145509
145786
|
throw new TypeError("this is a readable stream");
|
|
145510
145787
|
}
|
|
145511
145788
|
[at]() {
|
|
145512
|
-
|
|
145789
|
+
import_fs26.default.open(this[U2], "r", (t2, e) => this[Ht](t2, e));
|
|
145513
145790
|
}
|
|
145514
145791
|
[Ht](t2, e) {
|
|
145515
145792
|
t2 ? this[Ut](t2) : (this[u2] = e, this.emit("open", e), this[zt]());
|
|
@@ -145522,7 +145799,7 @@ var _t = class extends A {
|
|
|
145522
145799
|
this[j] = true;
|
|
145523
145800
|
let t2 = this[vi]();
|
|
145524
145801
|
if (t2.length === 0) return process.nextTick(() => this[Ii](null, 0, t2));
|
|
145525
|
-
|
|
145802
|
+
import_fs26.default.read(this[u2], t2, 0, t2.length, null, (e, i, r) => this[Ii](e, i, r));
|
|
145526
145803
|
}
|
|
145527
145804
|
}
|
|
145528
145805
|
[Ii](t2, e, i) {
|
|
@@ -145531,7 +145808,7 @@ var _t = class extends A {
|
|
|
145531
145808
|
[H]() {
|
|
145532
145809
|
if (this[ht] && typeof this[u2] == "number") {
|
|
145533
145810
|
let t2 = this[u2];
|
|
145534
|
-
this[u2] = void 0,
|
|
145811
|
+
this[u2] = void 0, import_fs26.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
|
|
145535
145812
|
}
|
|
145536
145813
|
}
|
|
145537
145814
|
[Ut](t2) {
|
|
@@ -145559,7 +145836,7 @@ var Be = class extends _t {
|
|
|
145559
145836
|
[at]() {
|
|
145560
145837
|
let t2 = true;
|
|
145561
145838
|
try {
|
|
145562
|
-
this[Ht](null,
|
|
145839
|
+
this[Ht](null, import_fs26.default.openSync(this[U2], "r")), t2 = false;
|
|
145563
145840
|
} finally {
|
|
145564
145841
|
t2 && this[H]();
|
|
145565
145842
|
}
|
|
@@ -145570,7 +145847,7 @@ var Be = class extends _t {
|
|
|
145570
145847
|
if (!this[j]) {
|
|
145571
145848
|
this[j] = true;
|
|
145572
145849
|
do {
|
|
145573
|
-
let e = this[vi](), i = e.length === 0 ? 0 :
|
|
145850
|
+
let e = this[vi](), i = e.length === 0 ? 0 : import_fs26.default.readSync(this[u2], e, 0, e.length, null);
|
|
145574
145851
|
if (!this[ki](i, e)) break;
|
|
145575
145852
|
} while (true);
|
|
145576
145853
|
this[j] = false;
|
|
@@ -145583,7 +145860,7 @@ var Be = class extends _t {
|
|
|
145583
145860
|
[H]() {
|
|
145584
145861
|
if (this[ht] && typeof this[u2] == "number") {
|
|
145585
145862
|
let t2 = this[u2];
|
|
145586
|
-
this[u2] = void 0,
|
|
145863
|
+
this[u2] = void 0, import_fs26.default.closeSync(t2), this.emit("close");
|
|
145587
145864
|
}
|
|
145588
145865
|
}
|
|
145589
145866
|
};
|
|
@@ -145625,7 +145902,7 @@ var et = class extends import_events4.default {
|
|
|
145625
145902
|
this[H](), this[gt] = true, this.emit("error", t2);
|
|
145626
145903
|
}
|
|
145627
145904
|
[at]() {
|
|
145628
|
-
|
|
145905
|
+
import_fs26.default.open(this[U2], this[tt], this[ie], (t2, e) => this[Ht](t2, e));
|
|
145629
145906
|
}
|
|
145630
145907
|
[Ht](t2, e) {
|
|
145631
145908
|
this[Me] && this[tt] === "r+" && t2 && t2.code === "ENOENT" ? (this[tt] = "w", this[at]()) : t2 ? this[Ut](t2) : (this[u2] = e, this.emit("open", e), this[gt] || this[Ai]());
|
|
@@ -145637,7 +145914,7 @@ var et = class extends import_events4.default {
|
|
|
145637
145914
|
return typeof t2 == "string" && (t2 = Buffer.from(t2, e)), this[te] ? (this.emit("error", new Error("write() after end()")), false) : this[u2] === void 0 || this[gt] || this[Y2].length ? (this[Y2].push(t2), this[ke] = true, false) : (this[gt] = true, this[ve](t2), true);
|
|
145638
145915
|
}
|
|
145639
145916
|
[ve](t2) {
|
|
145640
|
-
|
|
145917
|
+
import_fs26.default.write(this[u2], t2, 0, t2.length, this[ot], (e, i) => this[Pt](e, i));
|
|
145641
145918
|
}
|
|
145642
145919
|
[Pt](t2, e) {
|
|
145643
145920
|
t2 ? this[Ut](t2) : (this[ot] !== void 0 && typeof e == "number" && (this[ot] += e), this[Y2].length ? this[Ai]() : (this[gt] = false, this[te] && !this[Ni] ? (this[Ni] = true, this[H](), this.emit("finish")) : this[ke] && (this[ke] = false, this.emit("drain"))));
|
|
@@ -145653,7 +145930,7 @@ var et = class extends import_events4.default {
|
|
|
145653
145930
|
[H]() {
|
|
145654
145931
|
if (this[ht] && typeof this[u2] == "number") {
|
|
145655
145932
|
let t2 = this[u2];
|
|
145656
|
-
this[u2] = void 0,
|
|
145933
|
+
this[u2] = void 0, import_fs26.default.close(t2, (e) => e ? this.emit("error", e) : this.emit("close"));
|
|
145657
145934
|
}
|
|
145658
145935
|
}
|
|
145659
145936
|
};
|
|
@@ -145661,24 +145938,24 @@ var Wt = class extends et {
|
|
|
145661
145938
|
[at]() {
|
|
145662
145939
|
let t2;
|
|
145663
145940
|
if (this[Me] && this[tt] === "r+") try {
|
|
145664
|
-
t2 =
|
|
145941
|
+
t2 = import_fs26.default.openSync(this[U2], this[tt], this[ie]);
|
|
145665
145942
|
} catch (e) {
|
|
145666
145943
|
if (e?.code === "ENOENT") return this[tt] = "w", this[at]();
|
|
145667
145944
|
throw e;
|
|
145668
145945
|
}
|
|
145669
|
-
else t2 =
|
|
145946
|
+
else t2 = import_fs26.default.openSync(this[U2], this[tt], this[ie]);
|
|
145670
145947
|
this[Ht](null, t2);
|
|
145671
145948
|
}
|
|
145672
145949
|
[H]() {
|
|
145673
145950
|
if (this[ht] && typeof this[u2] == "number") {
|
|
145674
145951
|
let t2 = this[u2];
|
|
145675
|
-
this[u2] = void 0,
|
|
145952
|
+
this[u2] = void 0, import_fs26.default.closeSync(t2), this.emit("close");
|
|
145676
145953
|
}
|
|
145677
145954
|
}
|
|
145678
145955
|
[ve](t2) {
|
|
145679
145956
|
let e = true;
|
|
145680
145957
|
try {
|
|
145681
|
-
this[Pt](null,
|
|
145958
|
+
this[Pt](null, import_fs26.default.writeSync(this[u2], t2, 0, t2.length, this[ot])), e = false;
|
|
145682
145959
|
} finally {
|
|
145683
145960
|
if (e) try {
|
|
145684
145961
|
this[H]();
|
|
@@ -146461,11 +146738,11 @@ var vn = (s3) => {
|
|
|
146461
146738
|
};
|
|
146462
146739
|
var Qi = (s3, t2) => {
|
|
146463
146740
|
let e = new Map(t2.map((n) => [ut(n), true])), i = s3.filter, r = (n, o = "") => {
|
|
146464
|
-
let h = o || (0,
|
|
146741
|
+
let h = o || (0, import_path23.parse)(n).root || ".", a;
|
|
146465
146742
|
if (n === h) a = false;
|
|
146466
146743
|
else {
|
|
146467
146744
|
let l = e.get(n);
|
|
146468
|
-
a = l !== void 0 ? l : r((0,
|
|
146745
|
+
a = l !== void 0 ? l : r((0, import_path23.dirname)(n), h);
|
|
146469
146746
|
}
|
|
146470
146747
|
return e.set(n, a), a;
|
|
146471
146748
|
};
|
|
@@ -146585,7 +146862,7 @@ var de = class extends A {
|
|
|
146585
146862
|
let [o, h] = ce(this.path);
|
|
146586
146863
|
o && typeof h == "string" && (this.path = h, r = o);
|
|
146587
146864
|
}
|
|
146588
|
-
this.win32 = !!i.win32 || process.platform === "win32", this.win32 && (this.path = Qs(this.path.replaceAll(/\\/g, "/")), t2 = t2.replaceAll(/\\/g, "/")), this.absolute = f(i.absolute ||
|
|
146865
|
+
this.win32 = !!i.win32 || process.platform === "win32", this.win32 && (this.path = Qs(this.path.replaceAll(/\\/g, "/")), t2 = t2.replaceAll(/\\/g, "/")), this.absolute = f(i.absolute || import_path24.default.resolve(this.cwd, t2)), this.path === "" && (this.path = "./"), r && this.warn("TAR_ENTRY_INFO", `stripping ${r} from absolute path`, { entry: this, path: r + this.path });
|
|
146589
146866
|
let n = this.statCache.get(this.absolute);
|
|
146590
146867
|
n ? this[si](n) : this[ss]();
|
|
146591
146868
|
}
|
|
@@ -146596,7 +146873,7 @@ var de = class extends A {
|
|
|
146596
146873
|
return t2 === "error" && (this.#t = true), super.emit(t2, ...e);
|
|
146597
146874
|
}
|
|
146598
146875
|
[ss]() {
|
|
146599
|
-
|
|
146876
|
+
import_fs28.default.lstat(this.absolute, (t2, e) => {
|
|
146600
146877
|
if (t2) return this.emit("error", t2);
|
|
146601
146878
|
this[si](e);
|
|
146602
146879
|
});
|
|
@@ -146634,7 +146911,7 @@ var de = class extends A {
|
|
|
146634
146911
|
this.path.slice(-1) !== "/" && (this.path += "/"), this.stat.size = 0, this[fe](), this.end();
|
|
146635
146912
|
}
|
|
146636
146913
|
[is]() {
|
|
146637
|
-
|
|
146914
|
+
import_fs28.default.readlink(this.absolute, (t2, e) => {
|
|
146638
146915
|
if (t2) return this.emit("error", t2);
|
|
146639
146916
|
this[ns](e);
|
|
146640
146917
|
});
|
|
@@ -146644,7 +146921,7 @@ var de = class extends A {
|
|
|
146644
146921
|
}
|
|
146645
146922
|
[sr](t2) {
|
|
146646
146923
|
if (!this.stat) throw new Error("cannot create link entry without stat");
|
|
146647
|
-
this.type = "Link", this.linkpath = f(
|
|
146924
|
+
this.type = "Link", this.linkpath = f(import_path24.default.relative(this.cwd, t2)), this.stat.size = 0, this[fe](), this.end();
|
|
146648
146925
|
}
|
|
146649
146926
|
[er]() {
|
|
146650
146927
|
if (!this.stat) throw new Error("cannot create file entry without stat");
|
|
@@ -146657,7 +146934,7 @@ var de = class extends A {
|
|
|
146657
146934
|
this[os]();
|
|
146658
146935
|
}
|
|
146659
146936
|
[os]() {
|
|
146660
|
-
|
|
146937
|
+
import_fs28.default.open(this.absolute, "r", (t2, e) => {
|
|
146661
146938
|
if (t2) return this.emit("error", t2);
|
|
146662
146939
|
this[hs](e);
|
|
146663
146940
|
});
|
|
@@ -146672,14 +146949,14 @@ var de = class extends A {
|
|
|
146672
146949
|
[ii]() {
|
|
146673
146950
|
let { fd: t2, buf: e, offset: i, length: r, pos: n } = this;
|
|
146674
146951
|
if (t2 === void 0 || e === void 0) throw new Error("cannot read file without first opening");
|
|
146675
|
-
|
|
146952
|
+
import_fs28.default.read(t2, e, i, r, n, (o, h) => {
|
|
146676
146953
|
if (o) return this[pt](() => this.emit("error", o));
|
|
146677
146954
|
this[rs](h);
|
|
146678
146955
|
});
|
|
146679
146956
|
}
|
|
146680
146957
|
[pt](t2 = () => {
|
|
146681
146958
|
}) {
|
|
146682
|
-
this.fd !== void 0 &&
|
|
146959
|
+
this.fd !== void 0 && import_fs28.default.close(this.fd, t2);
|
|
146683
146960
|
}
|
|
146684
146961
|
[rs](t2) {
|
|
146685
146962
|
if (t2 <= 0 && this.remain > 0) {
|
|
@@ -146714,20 +146991,20 @@ var de = class extends A {
|
|
|
146714
146991
|
var ni = class extends de {
|
|
146715
146992
|
sync = true;
|
|
146716
146993
|
[ss]() {
|
|
146717
|
-
this[si](
|
|
146994
|
+
this[si](import_fs28.default.lstatSync(this.absolute));
|
|
146718
146995
|
}
|
|
146719
146996
|
[is]() {
|
|
146720
|
-
this[ns](
|
|
146997
|
+
this[ns](import_fs28.default.readlinkSync(this.absolute));
|
|
146721
146998
|
}
|
|
146722
146999
|
[os]() {
|
|
146723
|
-
this[hs](
|
|
147000
|
+
this[hs](import_fs28.default.openSync(this.absolute, "r"));
|
|
146724
147001
|
}
|
|
146725
147002
|
[ii]() {
|
|
146726
147003
|
let t2 = true;
|
|
146727
147004
|
try {
|
|
146728
147005
|
let { fd: e, buf: i, offset: r, length: n, pos: o } = this;
|
|
146729
147006
|
if (e === void 0 || i === void 0) throw new Error("fd and buf must be set in READ method");
|
|
146730
|
-
let h =
|
|
147007
|
+
let h = import_fs28.default.readSync(e, i, r, n, o);
|
|
146731
147008
|
this[rs](h), t2 = false;
|
|
146732
147009
|
} finally {
|
|
146733
147010
|
if (t2) try {
|
|
@@ -146742,7 +147019,7 @@ var ni = class extends de {
|
|
|
146742
147019
|
}
|
|
146743
147020
|
[pt](t2 = () => {
|
|
146744
147021
|
}) {
|
|
146745
|
-
this.fd !== void 0 &&
|
|
147022
|
+
this.fd !== void 0 && import_fs28.default.closeSync(this.fd), t2();
|
|
146746
147023
|
}
|
|
146747
147024
|
};
|
|
146748
147025
|
var oi = class extends A {
|
|
@@ -147058,7 +147335,7 @@ var wt = class extends A {
|
|
|
147058
147335
|
return typeof t2 == "string" ? this[ci](t2) : this[or](t2), this.flowing;
|
|
147059
147336
|
}
|
|
147060
147337
|
[or](t2) {
|
|
147061
|
-
let e = f(
|
|
147338
|
+
let e = f(import_path25.default.resolve(this.cwd, t2.path));
|
|
147062
147339
|
if (!this.filter(t2.path, t2)) t2.resume();
|
|
147063
147340
|
else {
|
|
147064
147341
|
let i = new pi(t2.path, e);
|
|
@@ -147067,13 +147344,13 @@ var wt = class extends A {
|
|
|
147067
147344
|
this[Ft]();
|
|
147068
147345
|
}
|
|
147069
147346
|
[ci](t2) {
|
|
147070
|
-
let e = f(
|
|
147347
|
+
let e = f(import_path25.default.resolve(this.cwd, t2));
|
|
147071
147348
|
this[W].push(new pi(t2, e)), this[Ft]();
|
|
147072
147349
|
}
|
|
147073
147350
|
[ds](t2) {
|
|
147074
147351
|
t2.pending = true, this[G2] += 1;
|
|
147075
147352
|
let e = this.follow ? "stat" : "lstat";
|
|
147076
|
-
|
|
147353
|
+
import_fs27.default[e](t2.absolute, (i, r) => {
|
|
147077
147354
|
t2.pending = false, this[G2] -= 1, i ? this.emit("error", i) : this[li](t2, r);
|
|
147078
147355
|
});
|
|
147079
147356
|
}
|
|
@@ -147087,7 +147364,7 @@ var wt = class extends A {
|
|
|
147087
147364
|
this[Ft]();
|
|
147088
147365
|
}
|
|
147089
147366
|
[ms](t2) {
|
|
147090
|
-
t2.pending = true, this[G2] += 1,
|
|
147367
|
+
t2.pending = true, this[G2] += 1, import_fs27.default.readdir(t2.absolute, (e, i) => {
|
|
147091
147368
|
if (t2.pending = false, this[G2] -= 1, e) return this.emit("error", e);
|
|
147092
147369
|
this[fi](t2, i);
|
|
147093
147370
|
});
|
|
@@ -147188,10 +147465,10 @@ var kt = class extends wt {
|
|
|
147188
147465
|
}
|
|
147189
147466
|
[ds](t2) {
|
|
147190
147467
|
let e = this.follow ? "statSync" : "lstatSync";
|
|
147191
|
-
this[li](t2,
|
|
147468
|
+
this[li](t2, import_fs27.default[e](t2.absolute));
|
|
147192
147469
|
}
|
|
147193
147470
|
[ms](t2) {
|
|
147194
|
-
this[fi](t2,
|
|
147471
|
+
this[fi](t2, import_fs27.default.readdirSync(t2.absolute));
|
|
147195
147472
|
}
|
|
147196
147473
|
[di](t2) {
|
|
147197
147474
|
let e = t2.entry, i = this.zip;
|
|
@@ -147242,8 +147519,8 @@ var Qn = K2(Vn, $n, Xn, qn, (s3, t2) => {
|
|
|
147242
147519
|
});
|
|
147243
147520
|
var Jn = process.env.__FAKE_PLATFORM__ || process.platform;
|
|
147244
147521
|
var Er = Jn === "win32";
|
|
147245
|
-
var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } =
|
|
147246
|
-
var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) ||
|
|
147522
|
+
var { O_CREAT: wr, O_NOFOLLOW: mr, O_TRUNC: Sr, O_WRONLY: yr } = import_fs29.default.constants;
|
|
147523
|
+
var Rr = Number(process.env.__FAKE_FS_O_FILENAME__) || import_fs29.default.constants.UV_FS_O_FILEMAP || 0;
|
|
147247
147524
|
var jn = Er && !!Rr;
|
|
147248
147525
|
var to = 512 * 1024;
|
|
147249
147526
|
var eo = Rr | Sr | wr | yr;
|
|
@@ -147338,7 +147615,7 @@ var gr = (s3, t2, e) => {
|
|
|
147338
147615
|
E2 ? e(E2) : x2 && a ? Es(x2, o, h, (Le) => S2(Le)) : n ? import_node_fs15.default.chmod(s3, r, e) : e();
|
|
147339
147616
|
};
|
|
147340
147617
|
if (s3 === d) return no(s3, S2);
|
|
147341
|
-
if (l) return
|
|
147618
|
+
if (l) return import_promises19.default.mkdir(s3, { mode: r, recursive: true }).then((E2) => S2(null, E2 ?? void 0), S2);
|
|
147342
147619
|
let D2 = f(import_node_path20.default.relative(d, s3)).split("/");
|
|
147343
147620
|
Ss(d, D2, r, c, d, void 0, S2);
|
|
147344
147621
|
};
|