@threadbase-sh/streamer 1.27.0 → 1.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +938 -712
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +5 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/migrations/008_fix_legacy_threadbase_provider.sql +7 -0
- package/package.json +3 -3
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) {
|
|
@@ -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,38 @@ 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");
|
|
128557
|
+
var import_readline3 = require("readline");
|
|
128558
|
+
var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
|
|
128558
128559
|
var import_fs13 = require("fs");
|
|
128559
128560
|
var import_path9 = require("path");
|
|
128561
|
+
var import_promises9 = require("fs/promises");
|
|
128562
|
+
var import_path10 = require("path");
|
|
128560
128563
|
|
|
128561
128564
|
// node_modules/@threadbase-sh/scanner/node_modules/chokidar/esm/index.js
|
|
128562
128565
|
var import_fs3 = require("fs");
|
|
@@ -128711,10 +128714,10 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
128711
128714
|
}
|
|
128712
128715
|
async _formatEntry(dirent, path2) {
|
|
128713
128716
|
let entry;
|
|
128714
|
-
const
|
|
128717
|
+
const basename12 = this._isDirent ? dirent.name : dirent;
|
|
128715
128718
|
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:
|
|
128719
|
+
const fullPath = (0, import_node_path5.resolve)((0, import_node_path5.join)(path2, basename12));
|
|
128720
|
+
entry = { path: (0, import_node_path5.relative)(this._root, fullPath), fullPath, basename: basename12 };
|
|
128718
128721
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
128719
128722
|
} catch (err) {
|
|
128720
128723
|
this._onError(err);
|
|
@@ -129253,9 +129256,9 @@ var NodeFsHandler = class {
|
|
|
129253
129256
|
_watchWithNodeFs(path2, listener) {
|
|
129254
129257
|
const opts = this.fsw.options;
|
|
129255
129258
|
const directory = sysPath.dirname(path2);
|
|
129256
|
-
const
|
|
129259
|
+
const basename12 = sysPath.basename(path2);
|
|
129257
129260
|
const parent = this.fsw._getWatchedDir(directory);
|
|
129258
|
-
parent.add(
|
|
129261
|
+
parent.add(basename12);
|
|
129259
129262
|
const absolutePath = sysPath.resolve(path2);
|
|
129260
129263
|
const options = {
|
|
129261
129264
|
persistent: opts.persistent
|
|
@@ -129265,7 +129268,7 @@ var NodeFsHandler = class {
|
|
|
129265
129268
|
let closer;
|
|
129266
129269
|
if (opts.usePolling) {
|
|
129267
129270
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
129268
|
-
options.interval = enableBin && isBinaryPath(
|
|
129271
|
+
options.interval = enableBin && isBinaryPath(basename12) ? opts.binaryInterval : opts.interval;
|
|
129269
129272
|
closer = setFsWatchFileListener(path2, absolutePath, options, {
|
|
129270
129273
|
listener,
|
|
129271
129274
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -129288,10 +129291,10 @@ var NodeFsHandler = class {
|
|
|
129288
129291
|
return;
|
|
129289
129292
|
}
|
|
129290
129293
|
const dirname17 = sysPath.dirname(file2);
|
|
129291
|
-
const
|
|
129294
|
+
const basename12 = sysPath.basename(file2);
|
|
129292
129295
|
const parent = this.fsw._getWatchedDir(dirname17);
|
|
129293
129296
|
let prevStats = stats;
|
|
129294
|
-
if (parent.has(
|
|
129297
|
+
if (parent.has(basename12))
|
|
129295
129298
|
return;
|
|
129296
129299
|
const listener = async (path2, newStats) => {
|
|
129297
129300
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
@@ -129316,9 +129319,9 @@ var NodeFsHandler = class {
|
|
|
129316
129319
|
prevStats = newStats2;
|
|
129317
129320
|
}
|
|
129318
129321
|
} catch (error51) {
|
|
129319
|
-
this.fsw._remove(dirname17,
|
|
129322
|
+
this.fsw._remove(dirname17, basename12);
|
|
129320
129323
|
}
|
|
129321
|
-
} else if (parent.has(
|
|
129324
|
+
} else if (parent.has(basename12)) {
|
|
129322
129325
|
const at2 = newStats.atimeMs;
|
|
129323
129326
|
const mt2 = newStats.mtimeMs;
|
|
129324
129327
|
if (!at2 || at2 <= mt2 || mt2 !== prevStats.mtimeMs) {
|
|
@@ -130514,6 +130517,435 @@ var SearchIndexer = class {
|
|
|
130514
130517
|
getLogger2().trace("indexer: cleared");
|
|
130515
130518
|
}
|
|
130516
130519
|
};
|
|
130520
|
+
var CLAUDE_CODE_PROVIDER = "claude-code";
|
|
130521
|
+
var CODEX_CLI_PROVIDER = "codex-cli";
|
|
130522
|
+
function initialReducerState() {
|
|
130523
|
+
return {
|
|
130524
|
+
sessionId: "",
|
|
130525
|
+
sessionName: "",
|
|
130526
|
+
latestTimestamp: "",
|
|
130527
|
+
cwd: "",
|
|
130528
|
+
teamName: "",
|
|
130529
|
+
model: null,
|
|
130530
|
+
messageCount: 0,
|
|
130531
|
+
lastMessageSender: "user",
|
|
130532
|
+
isTeammate: false,
|
|
130533
|
+
firstUserSeen: false,
|
|
130534
|
+
firstMessage: null,
|
|
130535
|
+
lastMessage: null,
|
|
130536
|
+
lastPrompt: "",
|
|
130537
|
+
pageMessageCount: 0,
|
|
130538
|
+
toolNames: [],
|
|
130539
|
+
previewParts: [],
|
|
130540
|
+
snippetParts: [],
|
|
130541
|
+
previewLength: 0,
|
|
130542
|
+
snippetLength: 0,
|
|
130543
|
+
badJsonLines: 0
|
|
130544
|
+
};
|
|
130545
|
+
}
|
|
130546
|
+
function reduceLine(state, entry, tier) {
|
|
130547
|
+
if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
|
|
130548
|
+
if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
|
|
130549
|
+
if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
|
|
130550
|
+
if (entry.teamName && !state.teamName) state.teamName = entry.teamName;
|
|
130551
|
+
if (entry.timestamp) {
|
|
130552
|
+
const ts2 = entry.timestamp;
|
|
130553
|
+
if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
|
|
130554
|
+
}
|
|
130555
|
+
const type = entry.type;
|
|
130556
|
+
if (type === "last-prompt") {
|
|
130557
|
+
if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
|
|
130558
|
+
return;
|
|
130559
|
+
}
|
|
130560
|
+
if (type !== "user" && type !== "assistant") return;
|
|
130561
|
+
if (entry.isMeta) return;
|
|
130562
|
+
const msg = entry.message;
|
|
130563
|
+
if (state.model === null && msg?.model) state.model = msg.model;
|
|
130564
|
+
if (type === "user" && !state.firstUserSeen) {
|
|
130565
|
+
state.firstUserSeen = true;
|
|
130566
|
+
if (isTeammateContent(msg?.content)) state.isTeammate = true;
|
|
130567
|
+
}
|
|
130568
|
+
const content = extractTextContent(msg?.content);
|
|
130569
|
+
const hasToolUseResult = type === "user" && entry.toolUseResult != null;
|
|
130570
|
+
const isOnlyToolResult = hasToolUseResult && isOnlyToolResultContent(msg?.content);
|
|
130571
|
+
const toolSet = new Set(state.toolNames);
|
|
130572
|
+
collectToolNames(msg?.content, toolSet);
|
|
130573
|
+
state.toolNames = Array.from(toolSet);
|
|
130574
|
+
const toolUseBlocks = extractToolUseBlocks(msg?.content);
|
|
130575
|
+
const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
|
|
130576
|
+
const hasThinking = !!(thinking?.content || thinking?.signature);
|
|
130577
|
+
if (content || isOnlyToolResult || toolUseBlocks.length > 0 || hasThinking) {
|
|
130578
|
+
state.pageMessageCount++;
|
|
130579
|
+
}
|
|
130580
|
+
if (content || isOnlyToolResult) {
|
|
130581
|
+
state.messageCount++;
|
|
130582
|
+
state.lastMessageSender = type;
|
|
130583
|
+
if (content) {
|
|
130584
|
+
const ts2 = entry.timestamp || "";
|
|
130585
|
+
if (!state.firstMessage) state.firstMessage = { text: content.slice(0, 200), timestamp: ts2 };
|
|
130586
|
+
state.lastMessage = { text: content.slice(0, 200), timestamp: ts2 };
|
|
130587
|
+
if (state.previewLength < tier.previewMax) {
|
|
130588
|
+
state.previewParts.push(content);
|
|
130589
|
+
state.previewLength += content.length;
|
|
130590
|
+
}
|
|
130591
|
+
if (state.snippetLength < tier.snippetMax) {
|
|
130592
|
+
const remaining = tier.snippetMax - state.snippetLength;
|
|
130593
|
+
const chunk = content.length > remaining ? content.slice(0, remaining) : content;
|
|
130594
|
+
state.snippetParts.push(chunk);
|
|
130595
|
+
state.snippetLength += chunk.length;
|
|
130596
|
+
}
|
|
130597
|
+
}
|
|
130598
|
+
}
|
|
130599
|
+
}
|
|
130600
|
+
function finalizeMeta(state, filePath, account, tier) {
|
|
130601
|
+
if (state.messageCount === 0) return null;
|
|
130602
|
+
const isSubagent = filePath.includes("/subagents/");
|
|
130603
|
+
let parentSessionId = null;
|
|
130604
|
+
if (isSubagent) {
|
|
130605
|
+
const uuidDir = (0, import_path4.dirname)((0, import_path4.dirname)(filePath));
|
|
130606
|
+
parentSessionId = (0, import_path4.join)((0, import_path4.dirname)(uuidDir), `${(0, import_path4.basename)(uuidDir)}.jsonl`);
|
|
130607
|
+
}
|
|
130608
|
+
const projectPath = state.cwd;
|
|
130609
|
+
return {
|
|
130610
|
+
id: filePath,
|
|
130611
|
+
filePath,
|
|
130612
|
+
provider: CLAUDE_CODE_PROVIDER,
|
|
130613
|
+
sessionId: state.sessionId || (0, import_path4.basename)(filePath, ".jsonl"),
|
|
130614
|
+
sessionName: state.sessionName,
|
|
130615
|
+
projectPath,
|
|
130616
|
+
projectName: getShortProjectName(projectPath),
|
|
130617
|
+
account,
|
|
130618
|
+
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
130619
|
+
messageCount: state.messageCount,
|
|
130620
|
+
lastMessageSender: state.lastMessageSender,
|
|
130621
|
+
preview: state.previewParts.join(" ").slice(0, tier.previewMax),
|
|
130622
|
+
contentSnippet: state.snippetParts.join(" "),
|
|
130623
|
+
gitBranch: null,
|
|
130624
|
+
model: state.model,
|
|
130625
|
+
isSubagent,
|
|
130626
|
+
parentSessionId,
|
|
130627
|
+
isTeammate: state.isTeammate,
|
|
130628
|
+
teamName: state.teamName || null,
|
|
130629
|
+
toolNames: state.toolNames,
|
|
130630
|
+
firstMessage: state.firstMessage,
|
|
130631
|
+
lastMessage: state.lastMessage,
|
|
130632
|
+
lastPrompt: state.lastPrompt || void 0
|
|
130633
|
+
};
|
|
130634
|
+
}
|
|
130635
|
+
function getShortProjectName(fullPath) {
|
|
130636
|
+
const parts = fullPath.split("/").filter(Boolean);
|
|
130637
|
+
return parts.slice(-3).join("/");
|
|
130638
|
+
}
|
|
130639
|
+
var SYSTEM_TAGS = [
|
|
130640
|
+
"system-reminder",
|
|
130641
|
+
"command-name",
|
|
130642
|
+
"command-message",
|
|
130643
|
+
"command-args",
|
|
130644
|
+
"ide_selection",
|
|
130645
|
+
"ide_opened_file",
|
|
130646
|
+
"local-command-stdout",
|
|
130647
|
+
"local-command-caveat",
|
|
130648
|
+
"retrieval_status",
|
|
130649
|
+
"task_id",
|
|
130650
|
+
"task_type",
|
|
130651
|
+
"task-id",
|
|
130652
|
+
"task-notification",
|
|
130653
|
+
"fast_mode_info",
|
|
130654
|
+
"persisted-output",
|
|
130655
|
+
"tool_use_error",
|
|
130656
|
+
"user-prompt-submit-hook",
|
|
130657
|
+
"thinking",
|
|
130658
|
+
"ask_user",
|
|
130659
|
+
"teammate-message"
|
|
130660
|
+
];
|
|
130661
|
+
var SYSTEM_TAG_RE = new RegExp(`<(${SYSTEM_TAGS.join("|")})[^>]*>[\\s\\S]*?<\\/\\1>`, "g");
|
|
130662
|
+
function cleanSystemTags(text) {
|
|
130663
|
+
return text.replace(SYSTEM_TAG_RE, "").replace(/[^\S\n]+/g, " ").replace(/\n{3,}/g, "\n\n").trim();
|
|
130664
|
+
}
|
|
130665
|
+
async function parseMeta(filePath, account, tier) {
|
|
130666
|
+
const log8 = getLogger2();
|
|
130667
|
+
log8.trace({ filePath, account, tier: tier.name }, "parseMeta: start");
|
|
130668
|
+
const state = initialReducerState();
|
|
130669
|
+
const fileStream = (0, import_fs5.createReadStream)(filePath);
|
|
130670
|
+
const rl = (0, import_readline.createInterface)({ input: fileStream, crlfDelay: Infinity });
|
|
130671
|
+
try {
|
|
130672
|
+
for await (const line of rl) {
|
|
130673
|
+
if (!line.trim()) continue;
|
|
130674
|
+
let entry;
|
|
130675
|
+
try {
|
|
130676
|
+
entry = JSON.parse(line);
|
|
130677
|
+
} catch {
|
|
130678
|
+
state.badJsonLines++;
|
|
130679
|
+
continue;
|
|
130680
|
+
}
|
|
130681
|
+
reduceLine(state, entry, tier);
|
|
130682
|
+
}
|
|
130683
|
+
} catch (err) {
|
|
130684
|
+
log8.warn({ filePath, err }, "parseMeta: read failed");
|
|
130685
|
+
return null;
|
|
130686
|
+
}
|
|
130687
|
+
if (state.badJsonLines > 0) {
|
|
130688
|
+
log8.warn(
|
|
130689
|
+
{ filePath, badJsonLines: state.badJsonLines },
|
|
130690
|
+
"parseMeta: skipped malformed JSON lines"
|
|
130691
|
+
);
|
|
130692
|
+
}
|
|
130693
|
+
const meta3 = finalizeMeta(state, filePath, account, tier);
|
|
130694
|
+
if (!meta3) log8.trace({ filePath }, "parseMeta: no messages");
|
|
130695
|
+
return meta3;
|
|
130696
|
+
}
|
|
130697
|
+
async function parseConversation(filePath, account) {
|
|
130698
|
+
const log8 = getLogger2();
|
|
130699
|
+
log8.trace({ filePath, account }, "parseConversation: start");
|
|
130700
|
+
const messages = [];
|
|
130701
|
+
let badJsonLines = 0;
|
|
130702
|
+
const textParts = [];
|
|
130703
|
+
const turnDurations = [];
|
|
130704
|
+
const state = initialConvState();
|
|
130705
|
+
const fileStream = (0, import_fs5.createReadStream)(filePath);
|
|
130706
|
+
const rl = (0, import_readline.createInterface)({ input: fileStream, crlfDelay: Infinity });
|
|
130707
|
+
try {
|
|
130708
|
+
for await (const line of rl) {
|
|
130709
|
+
if (!line.trim()) continue;
|
|
130710
|
+
let entry;
|
|
130711
|
+
try {
|
|
130712
|
+
entry = JSON.parse(line);
|
|
130713
|
+
} catch {
|
|
130714
|
+
badJsonLines++;
|
|
130715
|
+
continue;
|
|
130716
|
+
}
|
|
130717
|
+
if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
|
|
130718
|
+
turnDurations.push({
|
|
130719
|
+
durationMs: entry.durationMs,
|
|
130720
|
+
messageCount: entry.messageCount || 0,
|
|
130721
|
+
uuid: entry.uuid
|
|
130722
|
+
});
|
|
130723
|
+
continue;
|
|
130724
|
+
}
|
|
130725
|
+
const message = reduceConvLine(state, entry);
|
|
130726
|
+
if (message) {
|
|
130727
|
+
messages.push(message);
|
|
130728
|
+
if (message.text) textParts.push(message.text);
|
|
130729
|
+
}
|
|
130730
|
+
}
|
|
130731
|
+
} catch (err) {
|
|
130732
|
+
log8.warn({ filePath, err }, "parseConversation: read failed");
|
|
130733
|
+
return null;
|
|
130734
|
+
}
|
|
130735
|
+
if (badJsonLines > 0) {
|
|
130736
|
+
log8.warn({ filePath, badJsonLines }, "parseConversation: skipped malformed JSON lines");
|
|
130737
|
+
}
|
|
130738
|
+
if (messages.length === 0) {
|
|
130739
|
+
log8.trace({ filePath }, "parseConversation: no messages");
|
|
130740
|
+
return null;
|
|
130741
|
+
}
|
|
130742
|
+
log8.debug({ filePath, messageCount: messages.length }, "parseConversation: complete");
|
|
130743
|
+
applyTeamInfo(messages, state);
|
|
130744
|
+
return {
|
|
130745
|
+
id: filePath,
|
|
130746
|
+
filePath,
|
|
130747
|
+
projectPath: state.cwd,
|
|
130748
|
+
projectName: getShortProjectName2(state.cwd),
|
|
130749
|
+
sessionId: state.sessionId || (0, import_path3.basename)(filePath, ".jsonl"),
|
|
130750
|
+
sessionName: state.sessionName,
|
|
130751
|
+
messages,
|
|
130752
|
+
fullText: textParts.join(" "),
|
|
130753
|
+
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
130754
|
+
messageCount: messages.length,
|
|
130755
|
+
account,
|
|
130756
|
+
turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
|
|
130757
|
+
lastPrompt: state.lastPrompt || void 0
|
|
130758
|
+
};
|
|
130759
|
+
}
|
|
130760
|
+
function extractTextContent(content) {
|
|
130761
|
+
if (!content) return "";
|
|
130762
|
+
if (typeof content === "string") return cleanSystemTags(content);
|
|
130763
|
+
if (Array.isArray(content)) {
|
|
130764
|
+
return content.map((item) => {
|
|
130765
|
+
if (typeof item === "string") return item;
|
|
130766
|
+
if (item?.type === "text" && item?.text) return item.text;
|
|
130767
|
+
if (item?.type === "tool_result" && typeof item?.content === "string") return item.content;
|
|
130768
|
+
return "";
|
|
130769
|
+
}).filter(Boolean).map(cleanSystemTags).join(" ");
|
|
130770
|
+
}
|
|
130771
|
+
return "";
|
|
130772
|
+
}
|
|
130773
|
+
function extractToolUseNames(content) {
|
|
130774
|
+
if (!Array.isArray(content)) return [];
|
|
130775
|
+
return content.filter((item) => item?.type === "tool_use" && item?.name).map((item) => item.name);
|
|
130776
|
+
}
|
|
130777
|
+
function extractToolUseBlocks(content) {
|
|
130778
|
+
if (!Array.isArray(content)) return [];
|
|
130779
|
+
return content.filter((item) => item?.type === "tool_use" && item?.name && item?.id).map((item) => ({
|
|
130780
|
+
id: item.id,
|
|
130781
|
+
name: item.name,
|
|
130782
|
+
input: item.input || {}
|
|
130783
|
+
}));
|
|
130784
|
+
}
|
|
130785
|
+
var TOOL_NAME_TO_TYPE = {
|
|
130786
|
+
Edit: "edit",
|
|
130787
|
+
Write: "write",
|
|
130788
|
+
Read: "read",
|
|
130789
|
+
Bash: "bash",
|
|
130790
|
+
Grep: "grep",
|
|
130791
|
+
Glob: "glob",
|
|
130792
|
+
Agent: "taskAgent",
|
|
130793
|
+
TaskCreate: "taskCreate",
|
|
130794
|
+
TaskUpdate: "taskUpdate"
|
|
130795
|
+
};
|
|
130796
|
+
function extractToolResultBlocks(content, pendingToolUses) {
|
|
130797
|
+
if (!Array.isArray(content)) return [];
|
|
130798
|
+
return content.filter((item) => item?.type === "tool_result" && item?.tool_use_id).map((item) => {
|
|
130799
|
+
const toolName = pendingToolUses.get(item.tool_use_id)?.name ?? "";
|
|
130800
|
+
return {
|
|
130801
|
+
toolUseId: item.tool_use_id,
|
|
130802
|
+
type: TOOL_NAME_TO_TYPE[toolName] ?? "generic",
|
|
130803
|
+
content: typeof item.content === "string" ? { text: item.content } : item.content ?? {},
|
|
130804
|
+
isError: typeof item.is_error === "boolean" ? item.is_error : void 0
|
|
130805
|
+
};
|
|
130806
|
+
});
|
|
130807
|
+
}
|
|
130808
|
+
function collectToolNames(content, toolSet) {
|
|
130809
|
+
if (!Array.isArray(content)) return;
|
|
130810
|
+
for (const item of content) {
|
|
130811
|
+
if (item?.type === "tool_use" && item?.name) {
|
|
130812
|
+
toolSet.add(item.name);
|
|
130813
|
+
}
|
|
130814
|
+
}
|
|
130815
|
+
}
|
|
130816
|
+
function isOnlyToolResultContent(content) {
|
|
130817
|
+
if (!Array.isArray(content)) return false;
|
|
130818
|
+
return content.length > 0 && content.every((item) => item?.type === "tool_result");
|
|
130819
|
+
}
|
|
130820
|
+
function isTeammateContent(content) {
|
|
130821
|
+
const raw2 = typeof content === "string" ? content : Array.isArray(content) ? content.map(
|
|
130822
|
+
(item) => typeof item === "string" ? item : item?.type === "text" ? item.text ?? "" : ""
|
|
130823
|
+
).join("") : "";
|
|
130824
|
+
return raw2.includes("<teammate-message");
|
|
130825
|
+
}
|
|
130826
|
+
function extractThinking(content) {
|
|
130827
|
+
if (!Array.isArray(content)) return { content: "", signature: "" };
|
|
130828
|
+
const blocks = content.filter((item) => item?.type === "thinking");
|
|
130829
|
+
return {
|
|
130830
|
+
content: blocks.map((b2) => b2.thinking).filter(Boolean).join("\n\n"),
|
|
130831
|
+
signature: blocks.map((b2) => b2.signature).filter(Boolean).join("")
|
|
130832
|
+
};
|
|
130833
|
+
}
|
|
130834
|
+
function hasImageBlocks(content) {
|
|
130835
|
+
if (!Array.isArray(content)) return false;
|
|
130836
|
+
return content.some(
|
|
130837
|
+
(item) => item?.type === "image" && (item?.source?.type === "base64" || item?.file?.base64 !== void 0)
|
|
130838
|
+
);
|
|
130839
|
+
}
|
|
130840
|
+
function parseTeammateMessageTag(content) {
|
|
130841
|
+
const match2 = content.match(/<teammate-message\s+([^>]*)>/);
|
|
130842
|
+
if (!match2) return null;
|
|
130843
|
+
const attrs = match2[1];
|
|
130844
|
+
const id = attrs.match(/teammate_id="([^"]*)"/)?.[1];
|
|
130845
|
+
if (!id) return null;
|
|
130846
|
+
const summary = attrs.match(/summary="([^"]*)"/)?.[1];
|
|
130847
|
+
const color = attrs.match(/color="([^"]*)"/)?.[1];
|
|
130848
|
+
return { teammateId: id, summary, color };
|
|
130849
|
+
}
|
|
130850
|
+
function getShortProjectName2(fullPath) {
|
|
130851
|
+
const parts = fullPath.split("/").filter(Boolean);
|
|
130852
|
+
return parts.slice(-3).join("/");
|
|
130853
|
+
}
|
|
130854
|
+
function initialConvState() {
|
|
130855
|
+
return {
|
|
130856
|
+
cwd: "",
|
|
130857
|
+
sessionId: "",
|
|
130858
|
+
sessionName: "",
|
|
130859
|
+
latestTimestamp: "",
|
|
130860
|
+
lastPrompt: "",
|
|
130861
|
+
pendingToolUses: {},
|
|
130862
|
+
teamInfo: {}
|
|
130863
|
+
};
|
|
130864
|
+
}
|
|
130865
|
+
function reduceConvLine(state, entry) {
|
|
130866
|
+
if (entry.cwd && !state.cwd) state.cwd = entry.cwd;
|
|
130867
|
+
if (entry.sessionId && !state.sessionId) state.sessionId = entry.sessionId;
|
|
130868
|
+
if (entry.slug && !state.sessionName) state.sessionName = entry.slug;
|
|
130869
|
+
if (entry.timestamp) {
|
|
130870
|
+
const ts2 = entry.timestamp;
|
|
130871
|
+
if (!state.latestTimestamp || ts2 > state.latestTimestamp) state.latestTimestamp = ts2;
|
|
130872
|
+
}
|
|
130873
|
+
const type = entry.type;
|
|
130874
|
+
if (type === "last-prompt") {
|
|
130875
|
+
if (entry.lastPrompt && !state.lastPrompt) state.lastPrompt = entry.lastPrompt;
|
|
130876
|
+
return null;
|
|
130877
|
+
}
|
|
130878
|
+
if (type !== "user" && type !== "assistant") return null;
|
|
130879
|
+
if (entry.isMeta) return null;
|
|
130880
|
+
const msg = entry.message;
|
|
130881
|
+
const toolUseBlocks = extractToolUseBlocks(msg?.content);
|
|
130882
|
+
for (const block of toolUseBlocks) state.pendingToolUses[block.id] = block;
|
|
130883
|
+
const hasToolUseResult = type === "user" && entry.toolUseResult != null;
|
|
130884
|
+
const isToolResultOnly = hasToolUseResult && isOnlyToolResultContent(msg?.content);
|
|
130885
|
+
const content = extractTextContent(msg?.content);
|
|
130886
|
+
const thinking = type === "assistant" ? extractThinking(msg?.content) : null;
|
|
130887
|
+
const hasThinking = !!(thinking?.content || thinking?.signature);
|
|
130888
|
+
if (!(content || isToolResultOnly || toolUseBlocks.length > 0 || hasThinking)) return null;
|
|
130889
|
+
const metadata = {};
|
|
130890
|
+
if (msg?.model) metadata.model = msg.model;
|
|
130891
|
+
if (msg?.stop_reason !== void 0) metadata.stopReason = msg.stop_reason;
|
|
130892
|
+
if (entry.gitBranch) metadata.gitBranch = entry.gitBranch;
|
|
130893
|
+
if (entry.version) metadata.version = entry.version;
|
|
130894
|
+
const usage = msg?.usage;
|
|
130895
|
+
if (usage) {
|
|
130896
|
+
if (usage.input_tokens) metadata.inputTokens = usage.input_tokens;
|
|
130897
|
+
if (usage.output_tokens) metadata.outputTokens = usage.output_tokens;
|
|
130898
|
+
if (usage.cache_read_input_tokens) metadata.cacheReadTokens = usage.cache_read_input_tokens;
|
|
130899
|
+
if (usage.cache_creation_input_tokens)
|
|
130900
|
+
metadata.cacheCreationTokens = usage.cache_creation_input_tokens;
|
|
130901
|
+
}
|
|
130902
|
+
const toolUseNames = extractToolUseNames(msg?.content);
|
|
130903
|
+
if (toolUseNames.length > 0) metadata.toolUses = toolUseNames;
|
|
130904
|
+
if (toolUseBlocks.length > 0) metadata.toolUseBlocks = toolUseBlocks;
|
|
130905
|
+
if (isToolResultOnly) {
|
|
130906
|
+
const pending = new Map(Object.entries(state.pendingToolUses));
|
|
130907
|
+
const toolResultBlocks = extractToolResultBlocks(msg?.content, pending);
|
|
130908
|
+
if (toolResultBlocks.length > 0) {
|
|
130909
|
+
metadata.toolResults = toolResultBlocks;
|
|
130910
|
+
for (const block of toolResultBlocks) delete state.pendingToolUses[block.toolUseId];
|
|
130911
|
+
}
|
|
130912
|
+
}
|
|
130913
|
+
if (entry.teamName) {
|
|
130914
|
+
metadata.teamName = entry.teamName;
|
|
130915
|
+
if (!state.teamInfo[metadata.teamName] && content) {
|
|
130916
|
+
const info = parseTeammateMessageTag(content);
|
|
130917
|
+
if (info) state.teamInfo[metadata.teamName] = info;
|
|
130918
|
+
}
|
|
130919
|
+
}
|
|
130920
|
+
const thinkingContent = thinking?.content || void 0;
|
|
130921
|
+
const thinkingSignature = thinking?.signature || void 0;
|
|
130922
|
+
const hasMetadata = Object.keys(metadata).length > 0;
|
|
130923
|
+
return {
|
|
130924
|
+
role: type,
|
|
130925
|
+
text: content || "",
|
|
130926
|
+
timestamp: entry.timestamp || "",
|
|
130927
|
+
uuid: entry.uuid || void 0,
|
|
130928
|
+
metadata: hasMetadata ? metadata : void 0,
|
|
130929
|
+
isToolResult: isToolResultOnly || void 0,
|
|
130930
|
+
isThinking: thinkingContent || thinkingSignature ? true : void 0,
|
|
130931
|
+
thinkingContent,
|
|
130932
|
+
thinkingSignature,
|
|
130933
|
+
parentUuid: entry.parentUuid !== void 0 ? entry.parentUuid : void 0,
|
|
130934
|
+
requestId: type === "assistant" ? entry.requestId : void 0,
|
|
130935
|
+
promptId: type === "user" ? entry.promptId : void 0,
|
|
130936
|
+
isSidechain: typeof entry.isSidechain === "boolean" ? entry.isSidechain : void 0,
|
|
130937
|
+
permissionMode: type === "user" ? entry.permissionMode : void 0,
|
|
130938
|
+
hasImages: hasImageBlocks(msg?.content) || void 0,
|
|
130939
|
+
attachment: entry.attachment !== void 0 ? entry.attachment : void 0
|
|
130940
|
+
};
|
|
130941
|
+
}
|
|
130942
|
+
function applyTeamInfo(messages, state) {
|
|
130943
|
+
if (Object.keys(state.teamInfo).length === 0) return;
|
|
130944
|
+
for (const m2 of messages) {
|
|
130945
|
+
const name = m2.metadata?.teamName;
|
|
130946
|
+
if (name && state.teamInfo[name] && m2.metadata) m2.metadata.teamInfo = state.teamInfo[name];
|
|
130947
|
+
}
|
|
130948
|
+
}
|
|
130517
130949
|
var SIDECAR_VERSION = 1;
|
|
130518
130950
|
function sidecarPath(jsonlPath) {
|
|
130519
130951
|
return `${jsonlPath}.idx.json`;
|
|
@@ -130539,7 +130971,7 @@ function buildSidecar(meta3, cursor, updatedAt) {
|
|
|
130539
130971
|
}
|
|
130540
130972
|
function writeSidecar(jsonlPath, sidecar) {
|
|
130541
130973
|
try {
|
|
130542
|
-
(0,
|
|
130974
|
+
(0, import_fs6.writeFileSync)(sidecarPath(jsonlPath), JSON.stringify(sidecar, null, 2));
|
|
130543
130975
|
} catch (err) {
|
|
130544
130976
|
getLogger2().warn({ jsonlPath, err }, "sidecar: write failed");
|
|
130545
130977
|
}
|
|
@@ -130549,13 +130981,13 @@ function resolveConfigDir(configDir2) {
|
|
|
130549
130981
|
return configDir2.replace(/^~/, (0, import_os4.homedir)());
|
|
130550
130982
|
}
|
|
130551
130983
|
function getProjectsDir(profile) {
|
|
130552
|
-
return (0,
|
|
130984
|
+
return (0, import_path5.join)(resolveConfigDir(profile.configDir), "projects");
|
|
130553
130985
|
}
|
|
130554
130986
|
async function detectDefaultProfile() {
|
|
130555
130987
|
return {
|
|
130556
130988
|
id: "default",
|
|
130557
130989
|
label: "Default",
|
|
130558
|
-
configDir: (0,
|
|
130990
|
+
configDir: (0, import_path5.join)((0, import_os4.homedir)(), ".claude"),
|
|
130559
130991
|
enabled: true,
|
|
130560
130992
|
emoji: "\u{1F916}"
|
|
130561
130993
|
};
|
|
@@ -130564,7 +130996,7 @@ async function loadProfiles(configPath) {
|
|
|
130564
130996
|
const log8 = getLogger2();
|
|
130565
130997
|
try {
|
|
130566
130998
|
const resolved = resolveConfigDir(configPath);
|
|
130567
|
-
const data = await (0, import_promises4.readFile)((0,
|
|
130999
|
+
const data = await (0, import_promises4.readFile)((0, import_path5.join)(resolved, PROFILES_FILE), "utf-8");
|
|
130568
131000
|
const profiles = JSON.parse(data);
|
|
130569
131001
|
log8.debug({ configPath, count: profiles.length }, "profiles: loaded");
|
|
130570
131002
|
return profiles;
|
|
@@ -130574,34 +131006,6 @@ async function loadProfiles(configPath) {
|
|
|
130574
131006
|
return [defaultProfile];
|
|
130575
131007
|
}
|
|
130576
131008
|
}
|
|
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
131009
|
var CodexCliProvider = class {
|
|
130606
131010
|
name = CODEX_CLI_PROVIDER;
|
|
130607
131011
|
async discover(roots) {
|
|
@@ -130734,7 +131138,7 @@ function reduceCodexEntry(acc, entry, tier) {
|
|
|
130734
131138
|
}
|
|
130735
131139
|
function finalizeCodexMeta(acc, filePath, account, tier) {
|
|
130736
131140
|
if (acc.messageCount === 0) return null;
|
|
130737
|
-
const sessionId = acc.sessionId || (0,
|
|
131141
|
+
const sessionId = acc.sessionId || (0, import_path6.basename)(filePath, ".jsonl");
|
|
130738
131142
|
const projectPath = acc.cwd;
|
|
130739
131143
|
const kind = acc.lastAssistant === null && acc.toolNames.length > 0 ? "task" : "conversation";
|
|
130740
131144
|
return {
|
|
@@ -130746,7 +131150,7 @@ function finalizeCodexMeta(acc, filePath, account, tier) {
|
|
|
130746
131150
|
sessionId,
|
|
130747
131151
|
sessionName: "",
|
|
130748
131152
|
projectPath,
|
|
130749
|
-
projectName:
|
|
131153
|
+
projectName: getShortProjectName3(projectPath),
|
|
130750
131154
|
account,
|
|
130751
131155
|
timestamp: acc.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
130752
131156
|
messageCount: acc.messageCount,
|
|
@@ -130765,7 +131169,7 @@ function finalizeCodexMeta(acc, filePath, account, tier) {
|
|
|
130765
131169
|
lastPrompt: acc.lastUser?.text || void 0
|
|
130766
131170
|
};
|
|
130767
131171
|
}
|
|
130768
|
-
function
|
|
131172
|
+
function getShortProjectName3(fullPath) {
|
|
130769
131173
|
return fullPath.split("/").filter(Boolean).slice(-3).join("/");
|
|
130770
131174
|
}
|
|
130771
131175
|
async function parseCodexConversation(filePath, account) {
|
|
@@ -130776,7 +131180,7 @@ async function parseCodexConversation(filePath, account) {
|
|
|
130776
131180
|
let cwd = "";
|
|
130777
131181
|
let latestTimestamp = "";
|
|
130778
131182
|
let lastUserText = "";
|
|
130779
|
-
const rl = (0,
|
|
131183
|
+
const rl = (0, import_readline2.createInterface)({ input: (0, import_fs7.createReadStream)(filePath), crlfDelay: Infinity });
|
|
130780
131184
|
try {
|
|
130781
131185
|
for await (const line of rl) {
|
|
130782
131186
|
if (!line.trim()) continue;
|
|
@@ -130813,8 +131217,8 @@ async function parseCodexConversation(filePath, account) {
|
|
|
130813
131217
|
id: filePath,
|
|
130814
131218
|
filePath,
|
|
130815
131219
|
projectPath: cwd,
|
|
130816
|
-
projectName:
|
|
130817
|
-
sessionId: sessionId || (0,
|
|
131220
|
+
projectName: getShortProjectName3(cwd),
|
|
131221
|
+
sessionId: sessionId || (0, import_path6.basename)(filePath, ".jsonl"),
|
|
130818
131222
|
sessionName: "",
|
|
130819
131223
|
messages,
|
|
130820
131224
|
fullText: textParts.join(" "),
|
|
@@ -130886,404 +131290,6 @@ async function discoverJsonlFiles(dirs, onProgress) {
|
|
|
130886
131290
|
log8.debug({ totalFiles: results.length, dirs: dirs.length }, "discovery: complete");
|
|
130887
131291
|
return results;
|
|
130888
131292
|
}
|
|
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
131293
|
var ThreadbaseProvider = class {
|
|
131288
131294
|
name = CLAUDE_CODE_PROVIDER;
|
|
131289
131295
|
// Roots are passed as "<projectsDir>\0<account>" so the scanner can carry the
|
|
@@ -131352,32 +131358,219 @@ var LRUCache = class {
|
|
|
131352
131358
|
return this.map.size;
|
|
131353
131359
|
}
|
|
131354
131360
|
};
|
|
131361
|
+
var YIELD_EVERY_LINES = 500;
|
|
131362
|
+
async function tailReduce(filePath, startOffset, startLine, state, tier) {
|
|
131363
|
+
const stream = (0, import_fs10.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
|
|
131364
|
+
let buffer = "";
|
|
131365
|
+
let offset = startOffset;
|
|
131366
|
+
let line = startLine;
|
|
131367
|
+
let parsedLines = 0;
|
|
131368
|
+
let sinceYield = 0;
|
|
131369
|
+
for await (const chunk of stream) {
|
|
131370
|
+
buffer += chunk;
|
|
131371
|
+
let nl;
|
|
131372
|
+
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
131373
|
+
const lineWithNewline = buffer.slice(0, nl + 1);
|
|
131374
|
+
const text = lineWithNewline.trimEnd();
|
|
131375
|
+
buffer = buffer.slice(nl + 1);
|
|
131376
|
+
if (text.length > 0) {
|
|
131377
|
+
try {
|
|
131378
|
+
reduceLine(state, JSON.parse(text), tier);
|
|
131379
|
+
} catch {
|
|
131380
|
+
state.badJsonLines++;
|
|
131381
|
+
}
|
|
131382
|
+
parsedLines++;
|
|
131383
|
+
}
|
|
131384
|
+
offset += Buffer.byteLength(lineWithNewline, "utf8");
|
|
131385
|
+
line++;
|
|
131386
|
+
if (++sinceYield >= YIELD_EVERY_LINES) {
|
|
131387
|
+
sinceYield = 0;
|
|
131388
|
+
await (0, import_promises8.setImmediate)();
|
|
131389
|
+
}
|
|
131390
|
+
}
|
|
131391
|
+
}
|
|
131392
|
+
return { newOffset: offset, newLine: line, parsedLines, badJsonLines: state.badJsonLines };
|
|
131393
|
+
}
|
|
131394
|
+
var CHECKPOINT_INTERVAL = 500;
|
|
131395
|
+
async function streamMessages(filePath, startOffset, startLine, state, onMessage, onEntry) {
|
|
131396
|
+
const stream = (0, import_fs9.createReadStream)(filePath, { start: startOffset, encoding: "utf8" });
|
|
131397
|
+
let buffer = "";
|
|
131398
|
+
let offset = startOffset;
|
|
131399
|
+
let line = startLine;
|
|
131400
|
+
let sinceYield = 0;
|
|
131401
|
+
for await (const chunk of stream) {
|
|
131402
|
+
buffer += chunk;
|
|
131403
|
+
let nl;
|
|
131404
|
+
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
131405
|
+
const lineWithNewline = buffer.slice(0, nl + 1);
|
|
131406
|
+
const text = lineWithNewline.trimEnd();
|
|
131407
|
+
buffer = buffer.slice(nl + 1);
|
|
131408
|
+
offset += Buffer.byteLength(lineWithNewline, "utf8");
|
|
131409
|
+
line += 1;
|
|
131410
|
+
if (++sinceYield >= YIELD_EVERY_LINES) {
|
|
131411
|
+
sinceYield = 0;
|
|
131412
|
+
await (0, import_promises7.setImmediate)();
|
|
131413
|
+
}
|
|
131414
|
+
if (text.length === 0) continue;
|
|
131415
|
+
let entry;
|
|
131416
|
+
try {
|
|
131417
|
+
entry = JSON.parse(text);
|
|
131418
|
+
} catch {
|
|
131419
|
+
continue;
|
|
131420
|
+
}
|
|
131421
|
+
if (onEntry?.(entry)) continue;
|
|
131422
|
+
const message = reduceConvLine(state, entry);
|
|
131423
|
+
if (message && onMessage(message, offset, line)) {
|
|
131424
|
+
stream.destroy();
|
|
131425
|
+
return { offset, line };
|
|
131426
|
+
}
|
|
131427
|
+
}
|
|
131428
|
+
}
|
|
131429
|
+
return { offset, line };
|
|
131430
|
+
}
|
|
131431
|
+
async function buildCheckpoints(filePath, interval = CHECKPOINT_INTERVAL, from = null) {
|
|
131432
|
+
const checkpoints = [];
|
|
131433
|
+
const state = from ? from.state : initialConvState();
|
|
131434
|
+
let index = from ? from.messageIndex : 0;
|
|
131435
|
+
await streamMessages(
|
|
131436
|
+
filePath,
|
|
131437
|
+
from?.byteOffset ?? 0,
|
|
131438
|
+
from?.lineNumber ?? 0,
|
|
131439
|
+
state,
|
|
131440
|
+
(_msg, nextOffset, nextLine) => {
|
|
131441
|
+
index += 1;
|
|
131442
|
+
if (index % interval === 0) {
|
|
131443
|
+
checkpoints.push({
|
|
131444
|
+
messageIndex: index,
|
|
131445
|
+
byteOffset: nextOffset,
|
|
131446
|
+
lineNumber: nextLine,
|
|
131447
|
+
state: structuredClone(state)
|
|
131448
|
+
});
|
|
131449
|
+
}
|
|
131450
|
+
return false;
|
|
131451
|
+
}
|
|
131452
|
+
);
|
|
131453
|
+
return checkpoints;
|
|
131454
|
+
}
|
|
131455
|
+
async function readPage(filePath, total, options, floor) {
|
|
131456
|
+
const beforeIndex = options.beforeIndex ?? total;
|
|
131457
|
+
const fromIndex = Math.max(0, beforeIndex - options.limit);
|
|
131458
|
+
const state = floor ? structuredClone(floor.state) : initialConvState();
|
|
131459
|
+
const startOffset = floor ? floor.byteOffset : 0;
|
|
131460
|
+
const startLine = floor ? floor.lineNumber : 0;
|
|
131461
|
+
let index = floor ? floor.messageIndex : 0;
|
|
131462
|
+
const window2 = [];
|
|
131463
|
+
await streamMessages(filePath, startOffset, startLine, state, (message) => {
|
|
131464
|
+
const current = index;
|
|
131465
|
+
index += 1;
|
|
131466
|
+
if (current >= fromIndex && current < beforeIndex) window2.push(message);
|
|
131467
|
+
return index >= beforeIndex;
|
|
131468
|
+
});
|
|
131469
|
+
applyTeamInfo(window2, state);
|
|
131470
|
+
return { messages: window2, total, fromIndex };
|
|
131471
|
+
}
|
|
131472
|
+
async function foldTail(filePath, resume) {
|
|
131473
|
+
const messages = [];
|
|
131474
|
+
const textParts = [];
|
|
131475
|
+
const turnDurations = [];
|
|
131476
|
+
const end = await streamMessages(
|
|
131477
|
+
filePath,
|
|
131478
|
+
resume.offset,
|
|
131479
|
+
resume.line,
|
|
131480
|
+
resume.state,
|
|
131481
|
+
(message) => {
|
|
131482
|
+
messages.push(message);
|
|
131483
|
+
if (message.text) textParts.push(message.text);
|
|
131484
|
+
return false;
|
|
131485
|
+
},
|
|
131486
|
+
(entry) => {
|
|
131487
|
+
if (entry.type === "system" && entry.subtype === "turn_duration" && typeof entry.durationMs === "number") {
|
|
131488
|
+
turnDurations.push({
|
|
131489
|
+
durationMs: entry.durationMs,
|
|
131490
|
+
messageCount: entry.messageCount || 0,
|
|
131491
|
+
uuid: entry.uuid
|
|
131492
|
+
});
|
|
131493
|
+
return true;
|
|
131494
|
+
}
|
|
131495
|
+
return false;
|
|
131496
|
+
}
|
|
131497
|
+
);
|
|
131498
|
+
return { messages, textParts, turnDurations, end };
|
|
131499
|
+
}
|
|
131500
|
+
function assemble(filePath, account, messages, fullText, turnDurations, state) {
|
|
131501
|
+
return {
|
|
131502
|
+
id: filePath,
|
|
131503
|
+
filePath,
|
|
131504
|
+
projectPath: state.cwd,
|
|
131505
|
+
projectName: getShortProjectName2(state.cwd),
|
|
131506
|
+
sessionId: state.sessionId || (0, import_path8.basename)(filePath, ".jsonl"),
|
|
131507
|
+
sessionName: state.sessionName,
|
|
131508
|
+
messages,
|
|
131509
|
+
fullText,
|
|
131510
|
+
timestamp: state.latestTimestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
131511
|
+
messageCount: messages.length,
|
|
131512
|
+
account,
|
|
131513
|
+
turnDurations: turnDurations.length > 0 ? turnDurations : void 0,
|
|
131514
|
+
lastPrompt: state.lastPrompt || void 0
|
|
131515
|
+
};
|
|
131516
|
+
}
|
|
131517
|
+
async function parseConversationResumable(filePath, account) {
|
|
131518
|
+
const resume = { state: initialConvState(), offset: 0, line: 0 };
|
|
131519
|
+
const { messages, textParts, turnDurations, end } = await foldTail(filePath, resume);
|
|
131520
|
+
if (messages.length === 0) return null;
|
|
131521
|
+
applyTeamInfo(messages, resume.state);
|
|
131522
|
+
const conversation = assemble(
|
|
131523
|
+
filePath,
|
|
131524
|
+
account,
|
|
131525
|
+
messages,
|
|
131526
|
+
textParts.join(" "),
|
|
131527
|
+
turnDurations,
|
|
131528
|
+
resume.state
|
|
131529
|
+
);
|
|
131530
|
+
return { conversation, resume: { state: resume.state, offset: end.offset, line: end.line } };
|
|
131531
|
+
}
|
|
131532
|
+
async function extendConversation(previous, resume, filePath, account) {
|
|
131533
|
+
const { messages: fresh, textParts, turnDurations, end } = await foldTail(filePath, resume);
|
|
131534
|
+
const messages = fresh.length > 0 ? previous.messages.concat(fresh) : previous.messages;
|
|
131535
|
+
applyTeamInfo(messages, resume.state);
|
|
131536
|
+
const fullText = textParts.length === 0 ? previous.fullText : previous.fullText ? `${previous.fullText} ${textParts.join(" ")}` : textParts.join(" ");
|
|
131537
|
+
const allTurnDurations = (previous.turnDurations ?? []).concat(turnDurations);
|
|
131538
|
+
const conversation = assemble(
|
|
131539
|
+
filePath,
|
|
131540
|
+
account,
|
|
131541
|
+
messages,
|
|
131542
|
+
fullText,
|
|
131543
|
+
allTurnDurations,
|
|
131544
|
+
resume.state
|
|
131545
|
+
);
|
|
131546
|
+
return { conversation, resume: { state: resume.state, offset: end.offset, line: end.line } };
|
|
131547
|
+
}
|
|
131355
131548
|
var FP_BYTES = 4096;
|
|
131356
131549
|
function fingerprint(filePath, size) {
|
|
131357
131550
|
const hash2 = (0, import_crypto2.createHash)("sha1");
|
|
131358
131551
|
hash2.update(String(size));
|
|
131359
|
-
const fd = (0,
|
|
131552
|
+
const fd = (0, import_fs11.openSync)(filePath, "r");
|
|
131360
131553
|
try {
|
|
131361
131554
|
const head = Buffer.alloc(Math.min(FP_BYTES, size));
|
|
131362
131555
|
if (head.length > 0) {
|
|
131363
|
-
(0,
|
|
131556
|
+
(0, import_fs11.readSync)(fd, head, 0, head.length, 0);
|
|
131364
131557
|
hash2.update(head);
|
|
131365
131558
|
}
|
|
131366
131559
|
if (size > FP_BYTES) {
|
|
131367
131560
|
const tailLen = Math.min(FP_BYTES, size);
|
|
131368
131561
|
const tail = Buffer.alloc(tailLen);
|
|
131369
|
-
(0,
|
|
131562
|
+
(0, import_fs11.readSync)(fd, tail, 0, tailLen, size - tailLen);
|
|
131370
131563
|
hash2.update(tail);
|
|
131371
131564
|
}
|
|
131372
131565
|
} finally {
|
|
131373
|
-
(0,
|
|
131566
|
+
(0, import_fs11.closeSync)(fd);
|
|
131374
131567
|
}
|
|
131375
131568
|
return hash2.digest("hex");
|
|
131376
131569
|
}
|
|
131377
131570
|
function classify(filePath, existing) {
|
|
131378
131571
|
let stat42;
|
|
131379
131572
|
try {
|
|
131380
|
-
const s3 = (0,
|
|
131573
|
+
const s3 = (0, import_fs11.statSync)(filePath);
|
|
131381
131574
|
stat42 = { size: s3.size, mtimeMs: s3.mtimeMs };
|
|
131382
131575
|
} catch {
|
|
131383
131576
|
return { change: "vanished" };
|
|
@@ -131407,7 +131600,7 @@ async function parseMetaWithProvider(provider, filePath, account, tier) {
|
|
|
131407
131600
|
const log8 = getLogger2();
|
|
131408
131601
|
const acc = provider.createEmptyAccumulator();
|
|
131409
131602
|
const rl = (0, import_readline3.createInterface)({
|
|
131410
|
-
input: (0,
|
|
131603
|
+
input: (0, import_fs12.createReadStream)(filePath),
|
|
131411
131604
|
crlfDelay: Infinity
|
|
131412
131605
|
});
|
|
131413
131606
|
try {
|
|
@@ -131630,7 +131823,7 @@ function hasColumn(db, table, column) {
|
|
|
131630
131823
|
}
|
|
131631
131824
|
function openDatabase(dbPath) {
|
|
131632
131825
|
if (dbPath !== ":memory:") {
|
|
131633
|
-
(0,
|
|
131826
|
+
(0, import_fs13.mkdirSync)((0, import_path9.dirname)(dbPath), { recursive: true });
|
|
131634
131827
|
}
|
|
131635
131828
|
const db = new import_better_sqlite3.default(dbPath);
|
|
131636
131829
|
db.pragma("journal_mode = WAL");
|
|
@@ -131656,7 +131849,7 @@ async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
|
|
|
131656
131849
|
for (const projectDir of resolved.entries) {
|
|
131657
131850
|
let dirStat;
|
|
131658
131851
|
try {
|
|
131659
|
-
dirStat = await (0,
|
|
131852
|
+
dirStat = await (0, import_promises9.stat)(projectDir);
|
|
131660
131853
|
} catch {
|
|
131661
131854
|
scannedDirs.remove(projectDir);
|
|
131662
131855
|
continue;
|
|
@@ -131694,7 +131887,7 @@ async function discoverJsonlFilesGated(dirs, files, scannedDirs, options = {}) {
|
|
|
131694
131887
|
async function resolveProjectDirs(projectsDir, scannedDirs) {
|
|
131695
131888
|
let rootStat;
|
|
131696
131889
|
try {
|
|
131697
|
-
rootStat = await (0,
|
|
131890
|
+
rootStat = await (0, import_promises9.stat)(projectsDir);
|
|
131698
131891
|
} catch {
|
|
131699
131892
|
return null;
|
|
131700
131893
|
}
|
|
@@ -131704,7 +131897,7 @@ async function resolveProjectDirs(projectsDir, scannedDirs) {
|
|
|
131704
131897
|
}
|
|
131705
131898
|
let entries;
|
|
131706
131899
|
try {
|
|
131707
|
-
entries = (await (0,
|
|
131900
|
+
entries = (await (0, import_promises9.readdir)(projectsDir, { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => joinPath(projectsDir, e.name));
|
|
131708
131901
|
} catch {
|
|
131709
131902
|
return null;
|
|
131710
131903
|
}
|
|
@@ -131717,98 +131910,6 @@ function dirnameOf(filePath) {
|
|
|
131717
131910
|
function joinPath(dir, name) {
|
|
131718
131911
|
return dir.endsWith("/") ? `${dir}${name}` : `${dir}/${name}`;
|
|
131719
131912
|
}
|
|
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
131913
|
var CheckpointsRepo = class {
|
|
131813
131914
|
constructor(db) {
|
|
131814
131915
|
this.db = db;
|
|
@@ -131828,6 +131929,22 @@ var CheckpointsRepo = class {
|
|
|
131828
131929
|
});
|
|
131829
131930
|
tx();
|
|
131830
131931
|
}
|
|
131932
|
+
// Insert checkpoints without touching existing rows. Appends never invalidate
|
|
131933
|
+
// the chain covering the immutable prefix (Kafka sparse-index style); rows are
|
|
131934
|
+
// only ever removed on truncation/replace or deletion.
|
|
131935
|
+
append(sourcePath, checkpoints) {
|
|
131936
|
+
const tx = this.db.transaction(() => {
|
|
131937
|
+
const insert = this.db.prepare(
|
|
131938
|
+
`INSERT INTO message_checkpoints
|
|
131939
|
+
(source_path, message_index, byte_offset, line_number, parser_state)
|
|
131940
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
131941
|
+
);
|
|
131942
|
+
for (const c of checkpoints) {
|
|
131943
|
+
insert.run(sourcePath, c.messageIndex, c.byteOffset, c.lineNumber, JSON.stringify(c.state));
|
|
131944
|
+
}
|
|
131945
|
+
});
|
|
131946
|
+
tx();
|
|
131947
|
+
}
|
|
131831
131948
|
// The latest checkpoint at or before `messageIndex`, or null if none (read
|
|
131832
131949
|
// from the file start). Lets a page seek to the nearest prior anchor.
|
|
131833
131950
|
floor(sourcePath, messageIndex) {
|
|
@@ -131839,6 +131956,17 @@ var CheckpointsRepo = class {
|
|
|
131839
131956
|
).get(sourcePath, messageIndex);
|
|
131840
131957
|
return row ? toCheckpoint(row) : null;
|
|
131841
131958
|
}
|
|
131959
|
+
// The highest-index checkpoint for a file, or null if none. The resume point
|
|
131960
|
+
// for extending the chain after an append.
|
|
131961
|
+
last(sourcePath) {
|
|
131962
|
+
const row = this.db.prepare(
|
|
131963
|
+
`SELECT message_index, byte_offset, line_number, parser_state
|
|
131964
|
+
FROM message_checkpoints
|
|
131965
|
+
WHERE source_path = ?
|
|
131966
|
+
ORDER BY message_index DESC LIMIT 1`
|
|
131967
|
+
).get(sourcePath);
|
|
131968
|
+
return row ? toCheckpoint(row) : null;
|
|
131969
|
+
}
|
|
131842
131970
|
count(sourcePath) {
|
|
131843
131971
|
return this.db.prepare("SELECT COUNT(*) AS n FROM message_checkpoints WHERE source_path = ?").get(sourcePath).n;
|
|
131844
131972
|
}
|
|
@@ -131870,7 +131998,7 @@ var ConversationFilesRepo = class {
|
|
|
131870
131998
|
const info = this.db.prepare(
|
|
131871
131999
|
`INSERT INTO conversation_files (absolute_path, parent_dir, file_name, account)
|
|
131872
132000
|
VALUES (?, ?, ?, ?)`
|
|
131873
|
-
).run(absolutePath, (0,
|
|
132001
|
+
).run(absolutePath, (0, import_path10.dirname)(absolutePath), (0, import_path10.basename)(absolutePath), account);
|
|
131874
132002
|
return Number(info.lastInsertRowid);
|
|
131875
132003
|
}
|
|
131876
132004
|
// Advance the cursor + persisted reducer state after a successful index pass.
|
|
@@ -132221,6 +132349,9 @@ var PersistentEngine = class {
|
|
|
132221
132349
|
// restart just means the first few post-restart scans don't force an early
|
|
132222
132350
|
// backstop pass, which is harmless (watermarks themselves persist in the DB).
|
|
132223
132351
|
scanCount = 0;
|
|
132352
|
+
// In-flight checkpoint build/extension per file, so concurrent getPage
|
|
132353
|
+
// callers share one stream instead of each walking the file.
|
|
132354
|
+
checkpointBuilds = /* @__PURE__ */ new Map();
|
|
132224
132355
|
constructor(dbPath, options = {}) {
|
|
132225
132356
|
this.db = openDatabase(dbPath);
|
|
132226
132357
|
this.files = new ConversationFilesRepo(this.db);
|
|
@@ -132273,7 +132404,7 @@ var PersistentEngine = class {
|
|
|
132273
132404
|
const batch = discovered.slice(i, i + BATCH_SIZE);
|
|
132274
132405
|
const results = await Promise.all(
|
|
132275
132406
|
batch.map(async ({ filePath, account, provider }) => {
|
|
132276
|
-
const meta3 = await this.indexFile(
|
|
132407
|
+
const { meta: meta3 } = await this.indexFile(
|
|
132277
132408
|
filePath,
|
|
132278
132409
|
account,
|
|
132279
132410
|
tier.name,
|
|
@@ -132308,7 +132439,9 @@ var PersistentEngine = class {
|
|
|
132308
132439
|
// unchanged → return the stored summary; appended → resume the fold and read
|
|
132309
132440
|
// only new bytes; reindex/force → fold from offset 0. Writes the summary +
|
|
132310
132441
|
// cursor + reducer state in one transaction so a crash never leaves a
|
|
132311
|
-
// half-written row or an over-advanced cursor.
|
|
132442
|
+
// half-written row or an over-advanced cursor. Returns the classification
|
|
132443
|
+
// alongside the meta so callers (refreshFile) can keep, extend, or evict
|
|
132444
|
+
// their own per-file caches without re-stat'ing the file (racy) themselves.
|
|
132312
132445
|
async indexFile(filePath, account, tierName, customTiers, resolveGitBranch, force = false, provider) {
|
|
132313
132446
|
const log8 = getLogger2();
|
|
132314
132447
|
const tier = resolveTier(tierName, customTiers);
|
|
@@ -132316,13 +132449,21 @@ var PersistentEngine = class {
|
|
|
132316
132449
|
const { change, stat: stat42 } = classify(filePath, existing);
|
|
132317
132450
|
if (change === "vanished" || !stat42) {
|
|
132318
132451
|
this.markDeleted(filePath);
|
|
132319
|
-
return null;
|
|
132452
|
+
return { meta: null, change: "vanished" };
|
|
132320
132453
|
}
|
|
132321
132454
|
if (change === "unchanged" && !force) {
|
|
132322
|
-
return this.conversations.getBySourcePath(filePath);
|
|
132455
|
+
return { meta: this.conversations.getBySourcePath(filePath), change };
|
|
132323
132456
|
}
|
|
132324
132457
|
if (provider && provider.name !== CLAUDE_CODE_PROVIDER) {
|
|
132325
|
-
|
|
132458
|
+
const meta22 = await this.indexFileWithProvider(
|
|
132459
|
+
provider,
|
|
132460
|
+
filePath,
|
|
132461
|
+
account,
|
|
132462
|
+
tier,
|
|
132463
|
+
stat42,
|
|
132464
|
+
resolveGitBranch
|
|
132465
|
+
);
|
|
132466
|
+
return { meta: meta22, change };
|
|
132326
132467
|
}
|
|
132327
132468
|
const resume = change === "appended" && !force && existing?.reducer_state;
|
|
132328
132469
|
const state = resume ? JSON.parse(existing.reducer_state) : initialReducerState();
|
|
@@ -132333,12 +132474,12 @@ var PersistentEngine = class {
|
|
|
132333
132474
|
result = await tailReduce(filePath, startOffset, startLine, state, tier);
|
|
132334
132475
|
} catch (err) {
|
|
132335
132476
|
log8.warn({ filePath, err }, "persistent: tail read failed");
|
|
132336
|
-
return null;
|
|
132477
|
+
return { meta: null, change };
|
|
132337
132478
|
}
|
|
132338
132479
|
const meta3 = finalizeMeta(state, filePath, account, tier);
|
|
132339
132480
|
if (!meta3) {
|
|
132340
132481
|
this.markDeleted(filePath);
|
|
132341
|
-
return null;
|
|
132482
|
+
return { meta: null, change };
|
|
132342
132483
|
}
|
|
132343
132484
|
meta3.gitBranch = resolveGitBranch(meta3.projectPath);
|
|
132344
132485
|
const fp = stat42.size > 0 ? fingerprint(filePath, stat42.size) : null;
|
|
@@ -132346,7 +132487,7 @@ var PersistentEngine = class {
|
|
|
132346
132487
|
const upsert = this.db.transaction(() => {
|
|
132347
132488
|
this.conversations.upsert(fileId, meta3, state.pageMessageCount);
|
|
132348
132489
|
this.fts.upsert(meta3);
|
|
132349
|
-
this.checkpoints.remove(filePath);
|
|
132490
|
+
if (!resume) this.checkpoints.remove(filePath);
|
|
132350
132491
|
this.files.updateCursor(fileId, {
|
|
132351
132492
|
sizeBytes: stat42.size,
|
|
132352
132493
|
mtimeMs: stat42.mtimeMs,
|
|
@@ -132379,7 +132520,7 @@ var PersistentEngine = class {
|
|
|
132379
132520
|
{ filePath, change, bytesRead: result.newOffset - startOffset, msgs: meta3.messageCount },
|
|
132380
132521
|
"persistent: indexed file"
|
|
132381
132522
|
);
|
|
132382
|
-
return meta3;
|
|
132523
|
+
return { meta: meta3, change };
|
|
132383
132524
|
}
|
|
132384
132525
|
// Index a non-Threadbase provider file: full reparse from offset 0 through the
|
|
132385
132526
|
// provider's reducer/finalize, then the same upsert + FTS write + cursor bump
|
|
@@ -132479,15 +132620,34 @@ var PersistentEngine = class {
|
|
|
132479
132620
|
return { messages: messages.slice(fromIndex2, beforeIndex2), total: total2, fromIndex: fromIndex2 };
|
|
132480
132621
|
}
|
|
132481
132622
|
const total = this.conversations.pageMessageCount(filePath);
|
|
132482
|
-
|
|
132483
|
-
const built = await buildCheckpoints(filePath);
|
|
132484
|
-
if (built.length > 0) this.checkpoints.replaceAll(filePath, built);
|
|
132485
|
-
}
|
|
132623
|
+
await this.ensureCheckpoints(filePath, total);
|
|
132486
132624
|
const beforeIndex = options.beforeIndex ?? total;
|
|
132487
132625
|
const fromIndex = Math.max(0, beforeIndex - options.limit);
|
|
132488
132626
|
const floor = this.checkpoints.floor(filePath, fromIndex);
|
|
132489
132627
|
return readPage(filePath, total, options, floor);
|
|
132490
132628
|
}
|
|
132629
|
+
// Build or extend the checkpoint chain so it covers `total` messages. Cold
|
|
132630
|
+
// file → full build; a file that grew → extend from the last persisted
|
|
132631
|
+
// checkpoint (reads only past its offset, never the prefix). Single-flighted
|
|
132632
|
+
// per path: concurrent getPage callers await the same build instead of
|
|
132633
|
+
// streaming the file in parallel.
|
|
132634
|
+
ensureCheckpoints(filePath, total) {
|
|
132635
|
+
if (total <= CHECKPOINT_INTERVAL) return Promise.resolve();
|
|
132636
|
+
const inFlight = this.checkpointBuilds.get(filePath);
|
|
132637
|
+
if (inFlight) return inFlight;
|
|
132638
|
+
const build2 = (async () => {
|
|
132639
|
+
const last = this.checkpoints.last(filePath);
|
|
132640
|
+
if (last && total < last.messageIndex + CHECKPOINT_INTERVAL) return;
|
|
132641
|
+
const fresh = await buildCheckpoints(filePath, CHECKPOINT_INTERVAL, last);
|
|
132642
|
+
if (fresh.length === 0) return;
|
|
132643
|
+
if (last) this.checkpoints.append(filePath, fresh);
|
|
132644
|
+
else this.checkpoints.replaceAll(filePath, fresh);
|
|
132645
|
+
})().finally(() => {
|
|
132646
|
+
if (this.checkpointBuilds.get(filePath) === build2) this.checkpointBuilds.delete(filePath);
|
|
132647
|
+
});
|
|
132648
|
+
this.checkpointBuilds.set(filePath, build2);
|
|
132649
|
+
return build2;
|
|
132650
|
+
}
|
|
132491
132651
|
};
|
|
132492
132652
|
var EXCLUDED_SEGMENTS2 = ["/memory/", "/tool-results/"];
|
|
132493
132653
|
var FileWatcher = class {
|
|
@@ -132586,6 +132746,8 @@ function defaultDbPath() {
|
|
|
132586
132746
|
}
|
|
132587
132747
|
var ConversationScanner = class {
|
|
132588
132748
|
metadataCache = /* @__PURE__ */ new Map();
|
|
132749
|
+
// Parsed conversations plus (persistent claude-code entries only) the resume
|
|
132750
|
+
// point that lets refreshFile extend them in place when the file grows.
|
|
132589
132751
|
conversationLRU;
|
|
132590
132752
|
// session_id is NOT unique, so this maps a sessionId to every active meta that
|
|
132591
132753
|
// carries it. Resolution picks deterministically (newest timestamp, then path
|
|
@@ -132617,7 +132779,9 @@ var ConversationScanner = class {
|
|
|
132617
132779
|
// can't hit a closed DB (the watch-mode half of Bug #4).
|
|
132618
132780
|
inFlightReconcile = null;
|
|
132619
132781
|
constructor(options) {
|
|
132620
|
-
this.conversationLRU = new LRUCache(
|
|
132782
|
+
this.conversationLRU = new LRUCache(
|
|
132783
|
+
options?.conversationCacheSize ?? 5
|
|
132784
|
+
);
|
|
132621
132785
|
if (options?.persistent === false) {
|
|
132622
132786
|
this.dbPath = null;
|
|
132623
132787
|
this.sidecarEnabled = false;
|
|
@@ -132874,7 +133038,7 @@ var ConversationScanner = class {
|
|
|
132874
133038
|
const cached3 = this.conversationLRU.get(id);
|
|
132875
133039
|
if (cached3) {
|
|
132876
133040
|
log8.debug({ id }, "getConversation: cache hit");
|
|
132877
|
-
return cached3;
|
|
133041
|
+
return cached3.conversation;
|
|
132878
133042
|
}
|
|
132879
133043
|
const meta3 = this.persistent ? this.engine().getByIdOrSession(id) : this.metadataCache.get(id) ?? this.resolveSessionId(id);
|
|
132880
133044
|
if (!meta3) {
|
|
@@ -132883,9 +133047,14 @@ var ConversationScanner = class {
|
|
|
132883
133047
|
}
|
|
132884
133048
|
log8.debug({ id, filePath: meta3.filePath }, "getConversation: cache miss, parsing");
|
|
132885
133049
|
try {
|
|
133050
|
+
if (this.persistent && meta3.provider !== CODEX_CLI_PROVIDER) {
|
|
133051
|
+
const parsed = await parseConversationResumable(meta3.filePath, meta3.account);
|
|
133052
|
+
if (parsed) this.conversationLRU.set(id, parsed);
|
|
133053
|
+
return parsed?.conversation ?? null;
|
|
133054
|
+
}
|
|
132886
133055
|
const conversation = meta3.provider === CODEX_CLI_PROVIDER ? await parseCodexConversation(meta3.filePath, meta3.account) : await parseConversation(meta3.filePath, meta3.account);
|
|
132887
133056
|
if (conversation) {
|
|
132888
|
-
this.conversationLRU.set(id, conversation);
|
|
133057
|
+
this.conversationLRU.set(id, { conversation });
|
|
132889
133058
|
}
|
|
132890
133059
|
return conversation;
|
|
132891
133060
|
} catch (err) {
|
|
@@ -132957,20 +133126,30 @@ var ConversationScanner = class {
|
|
|
132957
133126
|
// not seen before. Returns the fresh ConversationMeta, or null when the file
|
|
132958
133127
|
// no longer parses (missing/empty) — in which case any prior entry for it is
|
|
132959
133128
|
// dropped from all indexes.
|
|
132960
|
-
|
|
133129
|
+
//
|
|
133130
|
+
// Single-flighted per path: concurrent callers (stacked client retries, a
|
|
133131
|
+
// watcher tick racing a caller) await the one in-flight refresh instead of
|
|
133132
|
+
// each re-reading the file.
|
|
133133
|
+
refreshesInFlight = /* @__PURE__ */ new Map();
|
|
133134
|
+
refreshFile(filePath, account) {
|
|
133135
|
+
const inFlight = this.refreshesInFlight.get(filePath);
|
|
133136
|
+
if (inFlight) return inFlight;
|
|
133137
|
+
const refresh = this.doRefreshFile(filePath, account).finally(() => {
|
|
133138
|
+
if (this.refreshesInFlight.get(filePath) === refresh) {
|
|
133139
|
+
this.refreshesInFlight.delete(filePath);
|
|
133140
|
+
}
|
|
133141
|
+
});
|
|
133142
|
+
this.refreshesInFlight.set(filePath, refresh);
|
|
133143
|
+
return refresh;
|
|
133144
|
+
}
|
|
133145
|
+
async doRefreshFile(filePath, account) {
|
|
132961
133146
|
const log8 = getLogger2();
|
|
132962
133147
|
if (this.persistent) {
|
|
132963
133148
|
const engine = this.engine();
|
|
132964
133149
|
const previous2 = engine.getByIdOrSession(filePath);
|
|
132965
133150
|
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
133151
|
const provider = await this.resolveProviderForFile(filePath, previous2);
|
|
132973
|
-
const meta22 = await engine.indexFile(
|
|
133152
|
+
const { meta: meta22, change } = await engine.indexFile(
|
|
132974
133153
|
filePath,
|
|
132975
133154
|
resolvedAccount2,
|
|
132976
133155
|
this.lastTier.name,
|
|
@@ -132979,8 +133158,19 @@ var ConversationScanner = class {
|
|
|
132979
133158
|
false,
|
|
132980
133159
|
provider
|
|
132981
133160
|
);
|
|
132982
|
-
|
|
132983
|
-
|
|
133161
|
+
const cacheKeys = /* @__PURE__ */ new Set();
|
|
133162
|
+
for (const m2 of [previous2, meta22]) {
|
|
133163
|
+
if (m2) {
|
|
133164
|
+
cacheKeys.add(m2.id);
|
|
133165
|
+
cacheKeys.add(m2.sessionId);
|
|
133166
|
+
}
|
|
133167
|
+
}
|
|
133168
|
+
if (!meta22 || change === "reindex" || change === "vanished") {
|
|
133169
|
+
for (const key of cacheKeys) this.conversationLRU.delete(key);
|
|
133170
|
+
} else if (change === "appended") {
|
|
133171
|
+
await this.extendCachedConversations(cacheKeys, filePath, meta22.account);
|
|
133172
|
+
}
|
|
133173
|
+
log8.debug({ filePath, change, kept: !!meta22 }, "refreshFile: updated persistent index");
|
|
132984
133174
|
return meta22;
|
|
132985
133175
|
}
|
|
132986
133176
|
const previous = this.metadataCache.get(filePath);
|
|
@@ -133024,6 +133214,39 @@ var ConversationScanner = class {
|
|
|
133024
133214
|
);
|
|
133025
133215
|
return meta3;
|
|
133026
133216
|
}
|
|
133217
|
+
// Advance every cached parse of an appended file by folding only the new
|
|
133218
|
+
// bytes through the conversation reducer — the in-memory analogue of the
|
|
133219
|
+
// persisted metadata fold. Entries without resume state (Codex) and entries
|
|
133220
|
+
// whose extension fails are evicted so the next read re-parses from scratch.
|
|
133221
|
+
async extendCachedConversations(cacheKeys, filePath, account) {
|
|
133222
|
+
const wrappers = /* @__PURE__ */ new Map();
|
|
133223
|
+
for (const key of cacheKeys) {
|
|
133224
|
+
const wrapper = this.conversationLRU.get(key);
|
|
133225
|
+
if (!wrapper) continue;
|
|
133226
|
+
const keys = wrappers.get(wrapper) ?? [];
|
|
133227
|
+
keys.push(key);
|
|
133228
|
+
wrappers.set(wrapper, keys);
|
|
133229
|
+
}
|
|
133230
|
+
for (const [wrapper, keys] of wrappers) {
|
|
133231
|
+
if (!wrapper.resume) {
|
|
133232
|
+
for (const key of keys) this.conversationLRU.delete(key);
|
|
133233
|
+
continue;
|
|
133234
|
+
}
|
|
133235
|
+
try {
|
|
133236
|
+
const extended = await extendConversation(
|
|
133237
|
+
wrapper.conversation,
|
|
133238
|
+
wrapper.resume,
|
|
133239
|
+
filePath,
|
|
133240
|
+
account
|
|
133241
|
+
);
|
|
133242
|
+
wrapper.conversation = extended.conversation;
|
|
133243
|
+
wrapper.resume = extended.resume;
|
|
133244
|
+
} catch (err) {
|
|
133245
|
+
getLogger2().warn({ filePath, err }, "refreshFile: cache extension failed, evicting");
|
|
133246
|
+
for (const key of keys) this.conversationLRU.delete(key);
|
|
133247
|
+
}
|
|
133248
|
+
}
|
|
133249
|
+
}
|
|
133027
133250
|
getMetadataCache() {
|
|
133028
133251
|
if (this.persistent) {
|
|
133029
133252
|
const map2 = /* @__PURE__ */ new Map();
|
|
@@ -133290,10 +133513,10 @@ async function search(query, options, scanner) {
|
|
|
133290
133513
|
// src/server.ts
|
|
133291
133514
|
var import_events3 = require("events");
|
|
133292
133515
|
var import_fs24 = require("fs");
|
|
133293
|
-
var
|
|
133516
|
+
var import_promises17 = require("fs/promises");
|
|
133294
133517
|
var import_http = require("http");
|
|
133295
133518
|
var import_os10 = require("os");
|
|
133296
|
-
var
|
|
133519
|
+
var import_path22 = require("path");
|
|
133297
133520
|
var import_readline4 = require("readline");
|
|
133298
133521
|
|
|
133299
133522
|
// src/agent/agent-client.ts
|
|
@@ -133382,7 +133605,7 @@ function readAgentConfig(env = process.env) {
|
|
|
133382
133605
|
}
|
|
133383
133606
|
|
|
133384
133607
|
// src/agent/conversation-writer.ts
|
|
133385
|
-
var
|
|
133608
|
+
var import_promises10 = require("fs/promises");
|
|
133386
133609
|
var import_node_path6 = require("path");
|
|
133387
133610
|
function createConversationWriter(opts) {
|
|
133388
133611
|
const { baseDir } = opts;
|
|
@@ -133392,7 +133615,7 @@ function createConversationWriter(opts) {
|
|
|
133392
133615
|
throw new Error("ConversationWriter: refusing to write empty assistant turn");
|
|
133393
133616
|
}
|
|
133394
133617
|
const file2 = (0, import_node_path6.join)(baseDir, `${args.sessionId}.jsonl`);
|
|
133395
|
-
await (0,
|
|
133618
|
+
await (0, import_promises10.mkdir)((0, import_node_path6.dirname)(file2), { recursive: true });
|
|
133396
133619
|
const record2 = {
|
|
133397
133620
|
role: "assistant",
|
|
133398
133621
|
turnId: args.turnId,
|
|
@@ -133402,7 +133625,7 @@ function createConversationWriter(opts) {
|
|
|
133402
133625
|
};
|
|
133403
133626
|
const line = `${JSON.stringify(record2)}
|
|
133404
133627
|
`;
|
|
133405
|
-
await (0,
|
|
133628
|
+
await (0, import_promises10.appendFile)(file2, line, { encoding: "utf8" });
|
|
133406
133629
|
}
|
|
133407
133630
|
};
|
|
133408
133631
|
}
|
|
@@ -136383,8 +136606,8 @@ var createHonoApp = (deps, upgradeWebSocket) => {
|
|
|
136383
136606
|
init_auth();
|
|
136384
136607
|
|
|
136385
136608
|
// src/browse.ts
|
|
136386
|
-
var
|
|
136387
|
-
var
|
|
136609
|
+
var import_promises11 = require("fs/promises");
|
|
136610
|
+
var import_path11 = require("path");
|
|
136388
136611
|
var BrowsePathNotFoundError = class extends Error {
|
|
136389
136612
|
constructor(message) {
|
|
136390
136613
|
super(message);
|
|
@@ -136392,20 +136615,20 @@ var BrowsePathNotFoundError = class extends Error {
|
|
|
136392
136615
|
}
|
|
136393
136616
|
};
|
|
136394
136617
|
async function resolveBrowsePath(browseRoot, relativePath) {
|
|
136395
|
-
const normalizedRoot = (0,
|
|
136618
|
+
const normalizedRoot = (0, import_path11.resolve)(browseRoot);
|
|
136396
136619
|
let sanitized;
|
|
136397
136620
|
if (process.platform !== "win32" && relativePath.startsWith("/") && relativePath.length > 1 && relativePath.includes("/", 1)) {
|
|
136398
136621
|
sanitized = relativePath;
|
|
136399
136622
|
} else {
|
|
136400
136623
|
sanitized = relativePath.replace(/^[/\\]+/, "");
|
|
136401
136624
|
}
|
|
136402
|
-
const target = sanitized ? (0,
|
|
136403
|
-
const rootPrefix = normalizedRoot.endsWith(
|
|
136625
|
+
const target = sanitized ? (0, import_path11.resolve)(normalizedRoot, sanitized) : normalizedRoot;
|
|
136626
|
+
const rootPrefix = normalizedRoot.endsWith(import_path11.sep) ? normalizedRoot : `${normalizedRoot}${import_path11.sep}`;
|
|
136404
136627
|
if (!target.startsWith(rootPrefix) && target !== normalizedRoot) {
|
|
136405
136628
|
throw new Error("Path outside browse root");
|
|
136406
136629
|
}
|
|
136407
136630
|
try {
|
|
136408
|
-
await (0,
|
|
136631
|
+
await (0, import_promises11.realpath)(target);
|
|
136409
136632
|
} catch (err) {
|
|
136410
136633
|
if (err?.code === "ENOENT") {
|
|
136411
136634
|
throw new BrowsePathNotFoundError(`Path not found: ${target}`);
|
|
@@ -136415,37 +136638,37 @@ async function resolveBrowsePath(browseRoot, relativePath) {
|
|
|
136415
136638
|
return target;
|
|
136416
136639
|
}
|
|
136417
136640
|
async function listDirectories(absolutePath) {
|
|
136418
|
-
const entries = await (0,
|
|
136641
|
+
const entries = await (0, import_promises11.readdir)(absolutePath, { withFileTypes: true });
|
|
136419
136642
|
return entries.filter((e) => e.isDirectory()).map((e) => ({ name: e.name })).sort((a, b2) => a.name.localeCompare(b2.name));
|
|
136420
136643
|
}
|
|
136421
136644
|
async function createDirectory(parentAbsolutePath, name) {
|
|
136422
136645
|
if (name.includes("/") || name.includes("\\") || name === ".." || name === ".") {
|
|
136423
136646
|
throw new Error("Invalid directory name");
|
|
136424
136647
|
}
|
|
136425
|
-
const target = (0,
|
|
136648
|
+
const target = (0, import_path11.join)(parentAbsolutePath, name);
|
|
136426
136649
|
try {
|
|
136427
|
-
const s3 = await (0,
|
|
136650
|
+
const s3 = await (0, import_promises11.stat)(target);
|
|
136428
136651
|
if (s3.isDirectory()) throw new Error("Directory already exists");
|
|
136429
136652
|
} catch (err) {
|
|
136430
136653
|
if (err.code !== "ENOENT") throw err;
|
|
136431
136654
|
}
|
|
136432
|
-
await (0,
|
|
136655
|
+
await (0, import_promises11.mkdir)(target);
|
|
136433
136656
|
return target;
|
|
136434
136657
|
}
|
|
136435
136658
|
|
|
136436
136659
|
// src/conversation-cache.ts
|
|
136437
136660
|
var import_better_sqlite32 = __toESM(require("better-sqlite3"), 1);
|
|
136438
136661
|
var import_fs16 = require("fs");
|
|
136439
|
-
var
|
|
136662
|
+
var import_path13 = require("path");
|
|
136440
136663
|
|
|
136441
136664
|
// src/db/sqlite-migrate.ts
|
|
136442
136665
|
var import_fs14 = require("fs");
|
|
136443
|
-
var
|
|
136666
|
+
var import_path12 = require("path");
|
|
136444
136667
|
var import_url6 = require("url");
|
|
136445
136668
|
var import_meta = {};
|
|
136446
136669
|
function getMigrationsDir() {
|
|
136447
136670
|
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
136448
|
-
return (0,
|
|
136671
|
+
return (0, import_path12.dirname)((0, import_url6.fileURLToPath)(import_meta.url));
|
|
136449
136672
|
}
|
|
136450
136673
|
return __dirname;
|
|
136451
136674
|
}
|
|
@@ -136457,7 +136680,7 @@ CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
|
136457
136680
|
`;
|
|
136458
136681
|
function runSqliteMigrations(db, migrationsDir) {
|
|
136459
136682
|
db.exec(SCHEMA_MIGRATIONS_SQL);
|
|
136460
|
-
const dir = migrationsDir ?? (0,
|
|
136683
|
+
const dir = migrationsDir ?? (0, import_path12.join)(getMigrationsDir(), "migrations");
|
|
136461
136684
|
const files = (0, import_fs14.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
|
|
136462
136685
|
const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
|
|
136463
136686
|
const appliedSet = new Set(appliedRows.map((r) => r.id));
|
|
@@ -136469,7 +136692,7 @@ function runSqliteMigrations(db, migrationsDir) {
|
|
|
136469
136692
|
skipped.push(file2);
|
|
136470
136693
|
continue;
|
|
136471
136694
|
}
|
|
136472
|
-
const sql = (0, import_fs14.readFileSync)((0,
|
|
136695
|
+
const sql = (0, import_fs14.readFileSync)((0, import_path12.join)(dir, file2), "utf-8");
|
|
136473
136696
|
const tx = db.transaction(() => {
|
|
136474
136697
|
db.exec(sql);
|
|
136475
136698
|
recordApplied.run(file2, (/* @__PURE__ */ new Date()).toISOString());
|
|
@@ -136486,6 +136709,9 @@ var CODEX_CLI_PROVIDER2 = "codex-cli";
|
|
|
136486
136709
|
function isProviderName(value) {
|
|
136487
136710
|
return value === CLAUDE_CODE_PROVIDER2 || value === CODEX_CLI_PROVIDER2;
|
|
136488
136711
|
}
|
|
136712
|
+
function coerceProviderForRunner(value) {
|
|
136713
|
+
return isProviderName(value) ? value : CLAUDE_CODE_PROVIDER2;
|
|
136714
|
+
}
|
|
136489
136715
|
function isProviderResumable(_provider, availabilityResumable) {
|
|
136490
136716
|
return availabilityResumable;
|
|
136491
136717
|
}
|
|
@@ -136811,7 +137037,7 @@ var ConversationCache = class _ConversationCache {
|
|
|
136811
137037
|
return this.classifyAgentFile(filePath, s3.mtimeMs, s3.size);
|
|
136812
137038
|
}
|
|
136813
137039
|
static open(dbPath, tailSize = 10, migrationsDir, options) {
|
|
136814
|
-
(0, import_fs16.mkdirSync)((0,
|
|
137040
|
+
(0, import_fs16.mkdirSync)((0, import_path13.dirname)(dbPath), { recursive: true });
|
|
136815
137041
|
const db = new import_better_sqlite32.default(dbPath);
|
|
136816
137042
|
db.pragma("journal_mode = WAL");
|
|
136817
137043
|
db.pragma("foreign_keys = ON");
|
|
@@ -137392,12 +137618,12 @@ function getDbConfig() {
|
|
|
137392
137618
|
|
|
137393
137619
|
// src/db/migrations.ts
|
|
137394
137620
|
var import_fs17 = require("fs");
|
|
137395
|
-
var
|
|
137621
|
+
var import_path14 = require("path");
|
|
137396
137622
|
var import_url7 = require("url");
|
|
137397
137623
|
var import_meta2 = {};
|
|
137398
137624
|
function getMigrationsDir2() {
|
|
137399
137625
|
if (import_meta2.url) {
|
|
137400
|
-
return (0,
|
|
137626
|
+
return (0, import_path14.dirname)((0, import_url7.fileURLToPath)(import_meta2.url));
|
|
137401
137627
|
}
|
|
137402
137628
|
return __dirname;
|
|
137403
137629
|
}
|
|
@@ -137413,11 +137639,11 @@ async function runMigrations2(pool2, migrationsDir) {
|
|
|
137413
137639
|
"SELECT name FROM _migrations ORDER BY name"
|
|
137414
137640
|
);
|
|
137415
137641
|
const appliedSet = new Set(applied.map((r) => r.name));
|
|
137416
|
-
const dir = migrationsDir ?? (0,
|
|
137642
|
+
const dir = migrationsDir ?? (0, import_path14.join)(getMigrationsDir2(), "pg-migrations");
|
|
137417
137643
|
const files = (0, import_fs17.readdirSync)(dir).filter((f2) => f2.endsWith(".sql")).sort();
|
|
137418
137644
|
for (const file2 of files) {
|
|
137419
137645
|
if (appliedSet.has(file2)) continue;
|
|
137420
|
-
const sql = (0, import_fs17.readFileSync)((0,
|
|
137646
|
+
const sql = (0, import_fs17.readFileSync)((0, import_path14.join)(dir, file2), "utf-8");
|
|
137421
137647
|
await pool2.query(sql);
|
|
137422
137648
|
await pool2.query("INSERT INTO _migrations (name) VALUES ($1)", [file2]);
|
|
137423
137649
|
}
|
|
@@ -137654,18 +137880,18 @@ async function recordUpload(pool2, instanceId, row) {
|
|
|
137654
137880
|
// src/handlers/handleListProjects.ts
|
|
137655
137881
|
var import_fs18 = require("fs");
|
|
137656
137882
|
var import_os7 = require("os");
|
|
137657
|
-
var
|
|
137883
|
+
var import_path15 = require("path");
|
|
137658
137884
|
function decodeProjectPath(dirName) {
|
|
137659
137885
|
return dirName.replace(/-/g, "/");
|
|
137660
137886
|
}
|
|
137661
137887
|
function handleListProjects(url2, res) {
|
|
137662
137888
|
const limit = Math.max(1, parseInt(url2.searchParams.get("limit") ?? "50", 10) || 50);
|
|
137663
137889
|
const offset = Math.max(0, parseInt(url2.searchParams.get("offset") ?? "0", 10) || 0);
|
|
137664
|
-
const projectsDir = (0,
|
|
137890
|
+
const projectsDir = (0, import_path15.join)((0, import_os7.homedir)(), ".claude", "projects");
|
|
137665
137891
|
let entries;
|
|
137666
137892
|
try {
|
|
137667
137893
|
entries = (0, import_fs18.readdirSync)(projectsDir).map((dirName) => {
|
|
137668
|
-
const fullPath = (0,
|
|
137894
|
+
const fullPath = (0, import_path15.join)(projectsDir, dirName);
|
|
137669
137895
|
let mtime = 0;
|
|
137670
137896
|
try {
|
|
137671
137897
|
mtime = (0, import_fs18.statSync)(fullPath).mtimeMs;
|
|
@@ -137687,20 +137913,20 @@ function handleListProjects(url2, res) {
|
|
|
137687
137913
|
}
|
|
137688
137914
|
|
|
137689
137915
|
// src/live-session-manager.ts
|
|
137690
|
-
var
|
|
137916
|
+
var import_path19 = require("path");
|
|
137691
137917
|
|
|
137692
137918
|
// src/codex-pty-runner.ts
|
|
137693
137919
|
var import_headless = __toESM(require_xterm_headless(), 1);
|
|
137694
137920
|
var import_crypto6 = require("crypto");
|
|
137695
137921
|
var import_fs20 = require("fs");
|
|
137696
|
-
var
|
|
137922
|
+
var import_path17 = require("path");
|
|
137697
137923
|
init_logger();
|
|
137698
137924
|
|
|
137699
137925
|
// src/platform.ts
|
|
137700
137926
|
var import_child_process = require("child_process");
|
|
137701
137927
|
var import_fs19 = require("fs");
|
|
137702
137928
|
var import_os8 = require("os");
|
|
137703
|
-
var
|
|
137929
|
+
var import_path16 = require("path");
|
|
137704
137930
|
var isWindows2 = (0, import_os8.platform)() === "win32";
|
|
137705
137931
|
var _claudeExe;
|
|
137706
137932
|
function resolveClaudeExe() {
|
|
@@ -137719,9 +137945,9 @@ function resolveClaudeExe() {
|
|
|
137719
137945
|
} catch {
|
|
137720
137946
|
}
|
|
137721
137947
|
const candidates = [
|
|
137722
|
-
(0,
|
|
137723
|
-
(0,
|
|
137724
|
-
process.env.LOCALAPPDATA ?? (0,
|
|
137948
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "claude.exe"),
|
|
137949
|
+
(0, import_path16.join)(
|
|
137950
|
+
process.env.LOCALAPPDATA ?? (0, import_path16.join)((0, import_os8.homedir)(), "AppData", "Local"),
|
|
137725
137951
|
"Microsoft",
|
|
137726
137952
|
"WindowsApps",
|
|
137727
137953
|
"claude.exe"
|
|
@@ -137748,7 +137974,7 @@ function resolveClaudeExe() {
|
|
|
137748
137974
|
const candidates = [
|
|
137749
137975
|
"/opt/homebrew/bin/claude",
|
|
137750
137976
|
"/usr/local/bin/claude",
|
|
137751
|
-
(0,
|
|
137977
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "claude")
|
|
137752
137978
|
];
|
|
137753
137979
|
for (const p2 of candidates) {
|
|
137754
137980
|
if ((0, import_fs19.existsSync)(p2)) {
|
|
@@ -137777,9 +138003,9 @@ function resolveCodexExe() {
|
|
|
137777
138003
|
} catch {
|
|
137778
138004
|
}
|
|
137779
138005
|
const candidates = [
|
|
137780
|
-
(0,
|
|
137781
|
-
(0,
|
|
137782
|
-
process.env.LOCALAPPDATA ?? (0,
|
|
138006
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "codex.exe"),
|
|
138007
|
+
(0, import_path16.join)(
|
|
138008
|
+
process.env.LOCALAPPDATA ?? (0, import_path16.join)((0, import_os8.homedir)(), "AppData", "Local"),
|
|
137783
138009
|
"Microsoft",
|
|
137784
138010
|
"WindowsApps",
|
|
137785
138011
|
"codex.exe"
|
|
@@ -137806,7 +138032,7 @@ function resolveCodexExe() {
|
|
|
137806
138032
|
const candidates = [
|
|
137807
138033
|
"/opt/homebrew/bin/codex",
|
|
137808
138034
|
"/usr/local/bin/codex",
|
|
137809
|
-
(0,
|
|
138035
|
+
(0, import_path16.join)((0, import_os8.homedir)(), ".local", "bin", "codex")
|
|
137810
138036
|
];
|
|
137811
138037
|
for (const p2 of candidates) {
|
|
137812
138038
|
if ((0, import_fs19.existsSync)(p2)) {
|
|
@@ -137902,7 +138128,7 @@ var CodexPtyRunner = class {
|
|
|
137902
138128
|
}
|
|
137903
138129
|
async doStart(sessionId, options) {
|
|
137904
138130
|
const nodePty = await loadPty();
|
|
137905
|
-
const projectName = options.projectName ?? (0,
|
|
138131
|
+
const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
|
|
137906
138132
|
const proc = nodePty.spawn(
|
|
137907
138133
|
resolveCodexExe(),
|
|
137908
138134
|
["resume", sessionId, "--cd", options.projectPath, "--no-alt-screen"],
|
|
@@ -137947,7 +138173,7 @@ var CodexPtyRunner = class {
|
|
|
137947
138173
|
async startFresh(options) {
|
|
137948
138174
|
const nodePty = await loadPty();
|
|
137949
138175
|
const sessionId = (0, import_crypto6.randomUUID)();
|
|
137950
|
-
const projectName = options.projectName ?? (0,
|
|
138176
|
+
const projectName = options.projectName ?? (0, import_path17.basename)(options.projectPath);
|
|
137951
138177
|
const args = ["--cd", options.projectPath, "--no-alt-screen"];
|
|
137952
138178
|
if (options.systemPrompt) {
|
|
137953
138179
|
args.push(options.systemPrompt);
|
|
@@ -138277,7 +138503,7 @@ function stripAnsi(str) {
|
|
|
138277
138503
|
var import_headless2 = __toESM(require_xterm_headless(), 1);
|
|
138278
138504
|
var import_crypto7 = require("crypto");
|
|
138279
138505
|
var import_fs21 = require("fs");
|
|
138280
|
-
var
|
|
138506
|
+
var import_path18 = require("path");
|
|
138281
138507
|
init_logger();
|
|
138282
138508
|
|
|
138283
138509
|
// src/services/questions/detectPermissionGate.ts
|
|
@@ -138629,7 +138855,7 @@ var PTYManager = class {
|
|
|
138629
138855
|
}
|
|
138630
138856
|
async doStart(sessionId, options) {
|
|
138631
138857
|
const nodePty = await loadPty2();
|
|
138632
|
-
const projectName = options.projectName ?? (0,
|
|
138858
|
+
const projectName = options.projectName ?? (0, import_path18.basename)(options.projectPath);
|
|
138633
138859
|
const proc = nodePty.spawn(
|
|
138634
138860
|
resolveClaudeExe(),
|
|
138635
138861
|
[
|
|
@@ -138680,7 +138906,7 @@ var PTYManager = class {
|
|
|
138680
138906
|
async startFresh(options) {
|
|
138681
138907
|
const nodePty = await loadPty2();
|
|
138682
138908
|
const sessionId = (0, import_crypto7.randomUUID)();
|
|
138683
|
-
const projectName = options.projectName ?? (0,
|
|
138909
|
+
const projectName = options.projectName ?? (0, import_path18.basename)(options.projectPath);
|
|
138684
138910
|
const args = [
|
|
138685
138911
|
"--permission-mode",
|
|
138686
138912
|
options.permissionMode ?? "acceptEdits",
|
|
@@ -139252,7 +139478,7 @@ var LiveSessionManager = class {
|
|
|
139252
139478
|
const runner = this.runners.get(provider);
|
|
139253
139479
|
if (runner) return runner;
|
|
139254
139480
|
const err = new Error(
|
|
139255
|
-
`Live ${provider} sessions are not implemented yet for ${(0,
|
|
139481
|
+
`Live ${provider} sessions are not implemented yet for ${(0, import_path19.basename)(projectPath)}`
|
|
139256
139482
|
);
|
|
139257
139483
|
err.statusCode = 501;
|
|
139258
139484
|
throw err;
|
|
@@ -139319,7 +139545,7 @@ var PairTokenStore = class {
|
|
|
139319
139545
|
// src/process-discovery.ts
|
|
139320
139546
|
var import_child_process2 = require("child_process");
|
|
139321
139547
|
var import_os9 = require("os");
|
|
139322
|
-
var
|
|
139548
|
+
var import_path20 = require("path");
|
|
139323
139549
|
async function discoverClaudeProcesses() {
|
|
139324
139550
|
if ((0, import_os9.platform)() === "win32") return discoverWindows();
|
|
139325
139551
|
return discoverUnix();
|
|
@@ -139338,7 +139564,7 @@ async function discoverUnix() {
|
|
|
139338
139564
|
return {
|
|
139339
139565
|
pid,
|
|
139340
139566
|
projectPath: cwd,
|
|
139341
|
-
projectName: (0,
|
|
139567
|
+
projectName: (0, import_path20.basename)(cwd),
|
|
139342
139568
|
branch: await readGitBranch2(cwd),
|
|
139343
139569
|
conversationId,
|
|
139344
139570
|
startedAt
|
|
@@ -139360,7 +139586,7 @@ async function discoverWindows() {
|
|
|
139360
139586
|
return {
|
|
139361
139587
|
pid,
|
|
139362
139588
|
projectPath: info.cwd,
|
|
139363
|
-
projectName: (0,
|
|
139589
|
+
projectName: (0, import_path20.basename)(info.cwd),
|
|
139364
139590
|
branch: await readGitBranch2(info.cwd),
|
|
139365
139591
|
conversationId: extractResumeId(info.args),
|
|
139366
139592
|
startedAt: info.startedAt
|
|
@@ -139441,7 +139667,7 @@ async function getProcessInfoWindows(pid) {
|
|
|
139441
139667
|
const startedAt = /* @__PURE__ */ new Date(`${year}-${month}-${day}T${hour}:${min}:${sec}`);
|
|
139442
139668
|
if (Number.isNaN(startedAt.getTime())) return null;
|
|
139443
139669
|
const exePath = parts[3] ?? "";
|
|
139444
|
-
const cwd = exePath ? (0,
|
|
139670
|
+
const cwd = exePath ? (0, import_path20.dirname)(exePath) : "";
|
|
139445
139671
|
return { cwd, args, startedAt };
|
|
139446
139672
|
} catch {
|
|
139447
139673
|
return null;
|
|
@@ -139483,11 +139709,11 @@ function seal(plaintext, recipientPublicKeyBase64) {
|
|
|
139483
139709
|
// node_modules/chokidar/index.js
|
|
139484
139710
|
var import_node_events2 = require("events");
|
|
139485
139711
|
var import_node_fs7 = require("fs");
|
|
139486
|
-
var
|
|
139712
|
+
var import_promises14 = require("fs/promises");
|
|
139487
139713
|
var sp2 = __toESM(require("path"), 1);
|
|
139488
139714
|
|
|
139489
139715
|
// node_modules/readdirp/index.js
|
|
139490
|
-
var
|
|
139716
|
+
var import_promises12 = require("fs/promises");
|
|
139491
139717
|
var import_node_path9 = require("path");
|
|
139492
139718
|
var import_node_stream2 = require("stream");
|
|
139493
139719
|
var EntryTypes2 = {
|
|
@@ -139568,7 +139794,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139568
139794
|
const { root, type } = opts;
|
|
139569
139795
|
this._fileFilter = normalizeFilter2(opts.fileFilter);
|
|
139570
139796
|
this._directoryFilter = normalizeFilter2(opts.directoryFilter);
|
|
139571
|
-
const statMethod = opts.lstat ?
|
|
139797
|
+
const statMethod = opts.lstat ? import_promises12.lstat : import_promises12.stat;
|
|
139572
139798
|
if (wantBigintFsStats2) {
|
|
139573
139799
|
this._stat = (path2) => statMethod(path2, { bigint: true });
|
|
139574
139800
|
} else {
|
|
@@ -139639,7 +139865,7 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139639
139865
|
async _exploreDir(path2, depth) {
|
|
139640
139866
|
let files;
|
|
139641
139867
|
try {
|
|
139642
|
-
files = await (0,
|
|
139868
|
+
files = await (0, import_promises12.readdir)(path2, this._rdOptions);
|
|
139643
139869
|
} catch (error51) {
|
|
139644
139870
|
this._onError(error51);
|
|
139645
139871
|
}
|
|
@@ -139647,10 +139873,10 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139647
139873
|
}
|
|
139648
139874
|
async _formatEntry(dirent, path2) {
|
|
139649
139875
|
let entry;
|
|
139650
|
-
const
|
|
139876
|
+
const basename12 = this._isDirent ? dirent.name : dirent;
|
|
139651
139877
|
try {
|
|
139652
|
-
const fullPath = (0, import_node_path9.resolve)((0, import_node_path9.join)(path2,
|
|
139653
|
-
entry = { path: (0, import_node_path9.relative)(this._root, fullPath), fullPath, basename:
|
|
139878
|
+
const fullPath = (0, import_node_path9.resolve)((0, import_node_path9.join)(path2, basename12));
|
|
139879
|
+
entry = { path: (0, import_node_path9.relative)(this._root, fullPath), fullPath, basename: basename12 };
|
|
139654
139880
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
139655
139881
|
} catch (err) {
|
|
139656
139882
|
this._onError(err);
|
|
@@ -139677,8 +139903,8 @@ var ReaddirpStream2 = class extends import_node_stream2.Readable {
|
|
|
139677
139903
|
if (stats && stats.isSymbolicLink()) {
|
|
139678
139904
|
const full = entry.fullPath;
|
|
139679
139905
|
try {
|
|
139680
|
-
const entryRealPath = await (0,
|
|
139681
|
-
const entryRealPathStats = await (0,
|
|
139906
|
+
const entryRealPath = await (0, import_promises12.realpath)(full);
|
|
139907
|
+
const entryRealPathStats = await (0, import_promises12.lstat)(entryRealPath);
|
|
139682
139908
|
if (entryRealPathStats.isFile()) {
|
|
139683
139909
|
return "file";
|
|
139684
139910
|
}
|
|
@@ -139721,7 +139947,7 @@ function readdirp2(root, options = {}) {
|
|
|
139721
139947
|
|
|
139722
139948
|
// node_modules/chokidar/handler.js
|
|
139723
139949
|
var import_node_fs6 = require("fs");
|
|
139724
|
-
var
|
|
139950
|
+
var import_promises13 = require("fs/promises");
|
|
139725
139951
|
var import_node_os3 = require("os");
|
|
139726
139952
|
var sp = __toESM(require("path"), 1);
|
|
139727
139953
|
var STR_DATA2 = "data";
|
|
@@ -139748,7 +139974,7 @@ var EVENTS2 = {
|
|
|
139748
139974
|
};
|
|
139749
139975
|
var EV2 = EVENTS2;
|
|
139750
139976
|
var THROTTLE_MODE_WATCH2 = "watch";
|
|
139751
|
-
var statMethods2 = { lstat:
|
|
139977
|
+
var statMethods2 = { lstat: import_promises13.lstat, stat: import_promises13.stat };
|
|
139752
139978
|
var KEY_LISTENERS2 = "listeners";
|
|
139753
139979
|
var KEY_ERR2 = "errHandlers";
|
|
139754
139980
|
var KEY_RAW2 = "rawEmitters";
|
|
@@ -140105,7 +140331,7 @@ var setFsWatchListener2 = (path2, fullPath, options, handlers) => {
|
|
|
140105
140331
|
cont.watcherUnusable = true;
|
|
140106
140332
|
if (isWindows3 && error51.code === "EPERM") {
|
|
140107
140333
|
try {
|
|
140108
|
-
const fd = await (0,
|
|
140334
|
+
const fd = await (0, import_promises13.open)(path2, "r");
|
|
140109
140335
|
await fd.close();
|
|
140110
140336
|
broadcastErr(error51);
|
|
140111
140337
|
} catch (err) {
|
|
@@ -140191,9 +140417,9 @@ var NodeFsHandler2 = class {
|
|
|
140191
140417
|
_watchWithNodeFs(path2, listener) {
|
|
140192
140418
|
const opts = this.fsw.options;
|
|
140193
140419
|
const directory = sp.dirname(path2);
|
|
140194
|
-
const
|
|
140420
|
+
const basename12 = sp.basename(path2);
|
|
140195
140421
|
const parent = this.fsw._getWatchedDir(directory);
|
|
140196
|
-
parent.add(
|
|
140422
|
+
parent.add(basename12);
|
|
140197
140423
|
const absolutePath = sp.resolve(path2);
|
|
140198
140424
|
const options = {
|
|
140199
140425
|
persistent: opts.persistent
|
|
@@ -140203,7 +140429,7 @@ var NodeFsHandler2 = class {
|
|
|
140203
140429
|
let closer;
|
|
140204
140430
|
if (opts.usePolling) {
|
|
140205
140431
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
140206
|
-
options.interval = enableBin && isBinaryPath2(
|
|
140432
|
+
options.interval = enableBin && isBinaryPath2(basename12) ? opts.binaryInterval : opts.interval;
|
|
140207
140433
|
closer = setFsWatchFileListener2(path2, absolutePath, options, {
|
|
140208
140434
|
listener,
|
|
140209
140435
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -140226,17 +140452,17 @@ var NodeFsHandler2 = class {
|
|
|
140226
140452
|
return;
|
|
140227
140453
|
}
|
|
140228
140454
|
const dirname17 = sp.dirname(file2);
|
|
140229
|
-
const
|
|
140455
|
+
const basename12 = sp.basename(file2);
|
|
140230
140456
|
const parent = this.fsw._getWatchedDir(dirname17);
|
|
140231
140457
|
let prevStats = stats;
|
|
140232
|
-
if (parent.has(
|
|
140458
|
+
if (parent.has(basename12))
|
|
140233
140459
|
return;
|
|
140234
140460
|
const listener = async (path2, newStats) => {
|
|
140235
140461
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH2, file2, 5))
|
|
140236
140462
|
return;
|
|
140237
140463
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
140238
140464
|
try {
|
|
140239
|
-
const newStats2 = await (0,
|
|
140465
|
+
const newStats2 = await (0, import_promises13.stat)(file2);
|
|
140240
140466
|
if (this.fsw.closed)
|
|
140241
140467
|
return;
|
|
140242
140468
|
const at2 = newStats2.atimeMs;
|
|
@@ -140254,9 +140480,9 @@ var NodeFsHandler2 = class {
|
|
|
140254
140480
|
prevStats = newStats2;
|
|
140255
140481
|
}
|
|
140256
140482
|
} catch (error51) {
|
|
140257
|
-
this.fsw._remove(dirname17,
|
|
140483
|
+
this.fsw._remove(dirname17, basename12);
|
|
140258
140484
|
}
|
|
140259
|
-
} else if (parent.has(
|
|
140485
|
+
} else if (parent.has(basename12)) {
|
|
140260
140486
|
const at2 = newStats.atimeMs;
|
|
140261
140487
|
const mt2 = newStats.mtimeMs;
|
|
140262
140488
|
if (!at2 || at2 <= mt2 || mt2 !== prevStats.mtimeMs) {
|
|
@@ -140291,7 +140517,7 @@ var NodeFsHandler2 = class {
|
|
|
140291
140517
|
this.fsw._incrReadyCount();
|
|
140292
140518
|
let linkPath;
|
|
140293
140519
|
try {
|
|
140294
|
-
linkPath = await (0,
|
|
140520
|
+
linkPath = await (0, import_promises13.realpath)(path2);
|
|
140295
140521
|
} catch (e) {
|
|
140296
140522
|
this.fsw._emitReady();
|
|
140297
140523
|
return true;
|
|
@@ -140440,7 +140666,7 @@ var NodeFsHandler2 = class {
|
|
|
140440
140666
|
let closer;
|
|
140441
140667
|
if (stats.isDirectory()) {
|
|
140442
140668
|
const absPath = sp.resolve(path2);
|
|
140443
|
-
const targetPath = follow ? await (0,
|
|
140669
|
+
const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
|
|
140444
140670
|
if (this.fsw.closed)
|
|
140445
140671
|
return;
|
|
140446
140672
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -140450,7 +140676,7 @@ var NodeFsHandler2 = class {
|
|
|
140450
140676
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
140451
140677
|
}
|
|
140452
140678
|
} else if (stats.isSymbolicLink()) {
|
|
140453
|
-
const targetPath = follow ? await (0,
|
|
140679
|
+
const targetPath = follow ? await (0, import_promises13.realpath)(path2) : path2;
|
|
140454
140680
|
if (this.fsw.closed)
|
|
140455
140681
|
return;
|
|
140456
140682
|
const parent = sp.dirname(wh.watchPath);
|
|
@@ -140610,7 +140836,7 @@ var DirEntry2 = class {
|
|
|
140610
140836
|
return;
|
|
140611
140837
|
const dir = this.path;
|
|
140612
140838
|
try {
|
|
140613
|
-
await (0,
|
|
140839
|
+
await (0, import_promises14.readdir)(dir);
|
|
140614
140840
|
} catch (err) {
|
|
140615
140841
|
if (this._removeWatcher) {
|
|
140616
140842
|
this._removeWatcher(sp2.dirname(dir), sp2.basename(dir));
|
|
@@ -140960,7 +141186,7 @@ var FSWatcher2 = class extends import_node_events2.EventEmitter {
|
|
|
140960
141186
|
const fullPath = opts.cwd ? sp2.join(opts.cwd, path2) : path2;
|
|
140961
141187
|
let stats2;
|
|
140962
141188
|
try {
|
|
140963
|
-
stats2 = await (0,
|
|
141189
|
+
stats2 = await (0, import_promises14.stat)(fullPath);
|
|
140964
141190
|
} catch (err) {
|
|
140965
141191
|
}
|
|
140966
141192
|
if (!stats2 || this.closed)
|
|
@@ -141214,7 +141440,7 @@ var chokidar_default = { watch: watch2, FSWatcher: FSWatcher2 };
|
|
|
141214
141440
|
|
|
141215
141441
|
// src/services/conversations/conversationWatcher.ts
|
|
141216
141442
|
var import_fs22 = require("fs");
|
|
141217
|
-
var
|
|
141443
|
+
var import_promises15 = require("fs/promises");
|
|
141218
141444
|
var ConversationWatcher = class {
|
|
141219
141445
|
files = /* @__PURE__ */ new Map();
|
|
141220
141446
|
directories = /* @__PURE__ */ new Map();
|
|
@@ -141318,12 +141544,12 @@ var ConversationWatcher = class {
|
|
|
141318
141544
|
entry.reading = true;
|
|
141319
141545
|
try {
|
|
141320
141546
|
for (; ; ) {
|
|
141321
|
-
const st2 = await (0,
|
|
141547
|
+
const st2 = await (0, import_promises15.stat)(filePath);
|
|
141322
141548
|
if (st2.size <= entry.offset) break;
|
|
141323
141549
|
const readFrom = entry.offset;
|
|
141324
141550
|
const bytesToRead = st2.size - readFrom;
|
|
141325
141551
|
const buf = Buffer.alloc(bytesToRead);
|
|
141326
|
-
const fh = await (0,
|
|
141552
|
+
const fh = await (0, import_promises15.open)(filePath, "r");
|
|
141327
141553
|
try {
|
|
141328
141554
|
await fh.read(buf, 0, bytesToRead, readFrom);
|
|
141329
141555
|
} finally {
|
|
@@ -141772,9 +141998,9 @@ function discoveredToResponse(d, conversationId) {
|
|
|
141772
141998
|
|
|
141773
141999
|
// src/uploads.ts
|
|
141774
142000
|
var import_crypto9 = require("crypto");
|
|
141775
|
-
var
|
|
142001
|
+
var import_promises16 = require("fs/promises");
|
|
141776
142002
|
var import_heic_convert = __toESM(require_heic_convert(), 1);
|
|
141777
|
-
var
|
|
142003
|
+
var import_path21 = require("path");
|
|
141778
142004
|
var UPLOAD_DIR_NAME = ".threadbase-uploads";
|
|
141779
142005
|
var MAX_BYTES = 25 * 1024 * 1024;
|
|
141780
142006
|
var HEIC_MIMES = /* @__PURE__ */ new Set(["image/heic", "image/heif"]);
|
|
@@ -141807,10 +142033,10 @@ async function saveUploadFile(input) {
|
|
|
141807
142033
|
}
|
|
141808
142034
|
const id = `up_${(0, import_crypto9.randomBytes)(8).toString("hex")}`;
|
|
141809
142035
|
const safeName = sanitizeFilename(originalName) || `file${MIME_TO_EXT[mimeType] ?? ""}`;
|
|
141810
|
-
const dir = (0,
|
|
141811
|
-
await (0,
|
|
141812
|
-
const filePath = (0,
|
|
141813
|
-
await (0,
|
|
142036
|
+
const dir = (0, import_path21.join)(input.projectPath, UPLOAD_DIR_NAME, input.sessionId);
|
|
142037
|
+
await (0, import_promises16.mkdir)(dir, { recursive: true });
|
|
142038
|
+
const filePath = (0, import_path21.join)(dir, `${Date.now()}-${id}-${safeName}`);
|
|
142039
|
+
await (0, import_promises16.writeFile)(filePath, buffer);
|
|
141814
142040
|
return {
|
|
141815
142041
|
id,
|
|
141816
142042
|
filePath,
|
|
@@ -142310,11 +142536,11 @@ var StreamerServer = class {
|
|
|
142310
142536
|
this.disableDb = config2.disableDb ?? false;
|
|
142311
142537
|
this.scannerPersistenceDisabled = config2.scannerPersistent === false;
|
|
142312
142538
|
this.scanProfiles = config2.scanProfiles;
|
|
142313
|
-
this.codexRoots = config2.codexRoots ?? [(0,
|
|
142539
|
+
this.codexRoots = config2.codexRoots ?? [(0, import_path22.join)((0, import_os10.homedir)(), ".codex", "sessions")];
|
|
142314
142540
|
this.ptyGracePeriodMs = config2.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
|
|
142315
142541
|
this.defaultSystemPrompt = config2.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
142316
142542
|
this.defaultPermissionMode = config2.defaultPermissionMode ?? loadDefaultPermissionMode() ?? "acceptEdits";
|
|
142317
|
-
this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0,
|
|
142543
|
+
this.cacheDir = config2.cacheDir ?? loadCacheDir() ?? (0, import_path22.join)((0, import_os10.homedir)(), ".threadbase", "cache");
|
|
142318
142544
|
this.tailSize = config2.tailSize ?? loadTailSize() ?? 10;
|
|
142319
142545
|
this.directoryDebounceMs = parseDirScanDebounceEnv(process.env.THREADBASE_DIR_SCAN_DEBOUNCE_MS) ?? config2.directoryScanDebounceMs ?? 1e3;
|
|
142320
142546
|
this.markScannerStaleDebounced = debounce(() => {
|
|
@@ -142325,7 +142551,7 @@ var StreamerServer = class {
|
|
|
142325
142551
|
this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
|
|
142326
142552
|
const rawRoot = process.env.THREADBASE_BROWSE_ROOT ?? loadBrowseRoot() ?? config2.browseRoot;
|
|
142327
142553
|
if (rawRoot) {
|
|
142328
|
-
(0,
|
|
142554
|
+
(0, import_promises17.realpath)(rawRoot).then((resolved) => {
|
|
142329
142555
|
this.browseRoot = resolved;
|
|
142330
142556
|
if (this.verbose) this.log.info(`Browse root: ${resolved}`, { browseRoot: resolved });
|
|
142331
142557
|
}).catch(() => {
|
|
@@ -142481,7 +142707,7 @@ var StreamerServer = class {
|
|
|
142481
142707
|
temporalClient,
|
|
142482
142708
|
taskQueue: agentConfig.temporal.taskQueue
|
|
142483
142709
|
});
|
|
142484
|
-
const conversationsBaseDir = agentConfig.conversationsDir || (0,
|
|
142710
|
+
const conversationsBaseDir = agentConfig.conversationsDir || (0, import_path22.join)((0, import_path22.dirname)(this.cacheDir), "conversations");
|
|
142485
142711
|
conversationWriter = createConversationWriter({
|
|
142486
142712
|
baseDir: conversationsBaseDir
|
|
142487
142713
|
});
|
|
@@ -142705,7 +142931,7 @@ var StreamerServer = class {
|
|
|
142705
142931
|
});
|
|
142706
142932
|
try {
|
|
142707
142933
|
this.cache = ConversationCache.open(
|
|
142708
|
-
(0,
|
|
142934
|
+
(0, import_path22.join)(this.cacheDir, "cache.db"),
|
|
142709
142935
|
this.tailSize,
|
|
142710
142936
|
void 0,
|
|
142711
142937
|
{
|
|
@@ -142731,11 +142957,11 @@ var StreamerServer = class {
|
|
|
142731
142957
|
if (this.scanProfiles && this.scanProfiles.length > 0) {
|
|
142732
142958
|
for (const profile of this.scanProfiles) {
|
|
142733
142959
|
if (profile.enabled) {
|
|
142734
|
-
this.fileWatcher.watchDirectory((0,
|
|
142960
|
+
this.fileWatcher.watchDirectory((0, import_path22.join)(profile.configDir, "projects"));
|
|
142735
142961
|
}
|
|
142736
142962
|
}
|
|
142737
142963
|
} else {
|
|
142738
|
-
this.fileWatcher.watchDirectory((0,
|
|
142964
|
+
this.fileWatcher.watchDirectory((0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects"));
|
|
142739
142965
|
}
|
|
142740
142966
|
} catch (err) {
|
|
142741
142967
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -143289,16 +143515,16 @@ var StreamerServer = class {
|
|
|
143289
143515
|
return scanner;
|
|
143290
143516
|
}
|
|
143291
143517
|
findJsonlPath(uuid3) {
|
|
143292
|
-
const projectsDir = (0,
|
|
143518
|
+
const projectsDir = (0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects");
|
|
143293
143519
|
if (!(0, import_fs24.existsSync)(projectsDir)) return null;
|
|
143294
143520
|
const filename = `${uuid3}.jsonl`;
|
|
143295
143521
|
for (const dir of (0, import_fs24.readdirSync)(projectsDir)) {
|
|
143296
|
-
const fp = (0,
|
|
143522
|
+
const fp = (0, import_path22.join)(projectsDir, dir, filename);
|
|
143297
143523
|
if ((0, import_fs24.existsSync)(fp)) return fp;
|
|
143298
|
-
const projectDir = (0,
|
|
143524
|
+
const projectDir = (0, import_path22.join)(projectsDir, dir);
|
|
143299
143525
|
try {
|
|
143300
143526
|
for (const sub of (0, import_fs24.readdirSync)(projectDir)) {
|
|
143301
|
-
const subagentPath = (0,
|
|
143527
|
+
const subagentPath = (0, import_path22.join)(projectDir, sub, "subagents", filename);
|
|
143302
143528
|
if ((0, import_fs24.existsSync)(subagentPath)) return subagentPath;
|
|
143303
143529
|
}
|
|
143304
143530
|
} catch {
|
|
@@ -143522,7 +143748,7 @@ var StreamerServer = class {
|
|
|
143522
143748
|
});
|
|
143523
143749
|
const conv = conversation;
|
|
143524
143750
|
const cachedConvMeta = this.cache?.getMetaById(id);
|
|
143525
|
-
const convProvider = conv.provider ?? cachedConvMeta?.provider
|
|
143751
|
+
const convProvider = coerceProviderForRunner(conv.provider ?? cachedConvMeta?.provider);
|
|
143526
143752
|
const availability = classifyResumability(conv.projectPath);
|
|
143527
143753
|
const body = {
|
|
143528
143754
|
meta: {
|
|
@@ -143736,7 +143962,7 @@ var StreamerServer = class {
|
|
|
143736
143962
|
return;
|
|
143737
143963
|
}
|
|
143738
143964
|
const cachedConvMeta = this.cache?.getMetaById(sessionId);
|
|
143739
|
-
const provider = conv?.provider ?? cachedConvMeta?.provider
|
|
143965
|
+
const provider = coerceProviderForRunner(conv?.provider ?? cachedConvMeta?.provider);
|
|
143740
143966
|
const session = await this.ptyManager.start(sessionId, {
|
|
143741
143967
|
provider,
|
|
143742
143968
|
projectPath,
|
|
@@ -144091,7 +144317,7 @@ var StreamerServer = class {
|
|
|
144091
144317
|
sessionStore: this.sessionStore,
|
|
144092
144318
|
// biome-ignore lint/style/noNonNullAssertion: agentClient is set when agentConfig.enabled is true
|
|
144093
144319
|
agentClient: this.agentClient,
|
|
144094
|
-
conversationsDir: this.cacheDir ? (0,
|
|
144320
|
+
conversationsDir: this.cacheDir ? (0, import_path22.join)((0, import_path22.dirname)(this.cacheDir), "conversations") : "",
|
|
144095
144321
|
agentConfig: this.agentConfig
|
|
144096
144322
|
});
|
|
144097
144323
|
json2(res, result.status, result.body);
|
|
@@ -144232,9 +144458,9 @@ var StreamerServer = class {
|
|
|
144232
144458
|
// was passed to Claude via --session-id so the filename matches from the start.
|
|
144233
144459
|
watchForJsonl(sessionId, projectPath) {
|
|
144234
144460
|
const encoded = projectPath.replace(/[/\\:.]/g, "-");
|
|
144235
|
-
const projectsDir = (0,
|
|
144461
|
+
const projectsDir = (0, import_path22.join)((0, import_os10.homedir)(), ".claude", "projects", encoded);
|
|
144236
144462
|
const expectedFile = `${sessionId}.jsonl`;
|
|
144237
|
-
const filePath = (0,
|
|
144463
|
+
const filePath = (0, import_path22.join)(projectsDir, expectedFile);
|
|
144238
144464
|
const deadline = Date.now() + 12e4;
|
|
144239
144465
|
let watcher = null;
|
|
144240
144466
|
const cleanup = () => {
|
|
@@ -144256,8 +144482,8 @@ var StreamerServer = class {
|
|
|
144256
144482
|
if (!resolvedFilePath && (0, import_fs24.existsSync)(projectsDir)) {
|
|
144257
144483
|
try {
|
|
144258
144484
|
const now = Date.now();
|
|
144259
|
-
const recent = (0, import_fs24.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0,
|
|
144260
|
-
if (recent) resolvedFilePath = (0,
|
|
144485
|
+
const recent = (0, import_fs24.readdirSync)(projectsDir).filter((f2) => f2.endsWith(".jsonl")).map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0, import_path22.join)(projectsDir, f2)).mtimeMs })).filter(({ mtime }) => now - mtime < 5e3).sort((a, b2) => b2.mtime - a.mtime)[0];
|
|
144486
|
+
if (recent) resolvedFilePath = (0, import_path22.join)(projectsDir, recent.f);
|
|
144261
144487
|
} catch {
|
|
144262
144488
|
}
|
|
144263
144489
|
}
|
|
@@ -144308,7 +144534,7 @@ var StreamerServer = class {
|
|
|
144308
144534
|
watchForCodexRollout(sessionId, projectPath) {
|
|
144309
144535
|
const deadline = Date.now() + 12e4;
|
|
144310
144536
|
const now = /* @__PURE__ */ new Date();
|
|
144311
|
-
const dateDir = (0,
|
|
144537
|
+
const dateDir = (0, import_path22.join)(
|
|
144312
144538
|
String(now.getFullYear()),
|
|
144313
144539
|
String(now.getMonth() + 1).padStart(2, "0"),
|
|
144314
144540
|
String(now.getDate()).padStart(2, "0")
|
|
@@ -144349,7 +144575,7 @@ var StreamerServer = class {
|
|
|
144349
144575
|
this.sessionStore.listManaged().filter((s3) => s3.id !== sessionId && s3.boundConversationId != null).map((s3) => s3.boundConversationId)
|
|
144350
144576
|
);
|
|
144351
144577
|
for (const root of this.codexRoots) {
|
|
144352
|
-
const sessionsDir = (0,
|
|
144578
|
+
const sessionsDir = (0, import_path22.join)(root, dateDir);
|
|
144353
144579
|
if (!(0, import_fs24.existsSync)(sessionsDir)) continue;
|
|
144354
144580
|
let candidateFiles;
|
|
144355
144581
|
try {
|
|
@@ -144358,9 +144584,9 @@ var StreamerServer = class {
|
|
|
144358
144584
|
continue;
|
|
144359
144585
|
}
|
|
144360
144586
|
const nowMs = Date.now();
|
|
144361
|
-
const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0,
|
|
144587
|
+
const recentCandidates = candidateFiles.map((f2) => ({ f: f2, mtime: (0, import_fs24.statSync)((0, import_path22.join)(sessionsDir, f2)).mtimeMs })).filter(({ mtime }) => nowMs - mtime < 1e4).sort((a, b2) => b2.mtime - a.mtime);
|
|
144362
144588
|
for (const { f: f2 } of recentCandidates) {
|
|
144363
|
-
const candidatePath = (0,
|
|
144589
|
+
const candidatePath = (0, import_path22.join)(sessionsDir, f2);
|
|
144364
144590
|
const match2 = matchesProjectPath(candidatePath);
|
|
144365
144591
|
if (!match2) continue;
|
|
144366
144592
|
if (boundElsewhere.has(match2.id)) continue;
|
|
@@ -144814,7 +145040,7 @@ function isBrewInstall(scriptPath = process.argv[1] ?? "") {
|
|
|
144814
145040
|
var import_node_crypto4 = require("crypto");
|
|
144815
145041
|
var import_node_fs8 = require("fs");
|
|
144816
145042
|
var import_node_path10 = require("path");
|
|
144817
|
-
var
|
|
145043
|
+
var import_promises18 = require("stream/promises");
|
|
144818
145044
|
|
|
144819
145045
|
// src/updater/manifest.ts
|
|
144820
145046
|
init_zod();
|
|
@@ -144889,7 +145115,7 @@ async function downloadAndVerify(opts) {
|
|
|
144889
145115
|
}
|
|
144890
145116
|
});
|
|
144891
145117
|
try {
|
|
144892
|
-
await (0,
|
|
145118
|
+
await (0, import_promises18.pipeline)(res.body.pipeThrough(measured), out);
|
|
144893
145119
|
} catch (err) {
|
|
144894
145120
|
(0, import_node_fs8.rmSync)(targetPath, { force: true });
|
|
144895
145121
|
throw err;
|
|
@@ -145081,7 +145307,7 @@ var import_node_stream3 = __toESM(require("stream"), 1);
|
|
|
145081
145307
|
var import_node_string_decoder = require("string_decoder");
|
|
145082
145308
|
var import_node_path14 = __toESM(require("path"), 1);
|
|
145083
145309
|
var import_node_fs11 = __toESM(require("fs"), 1);
|
|
145084
|
-
var
|
|
145310
|
+
var import_path23 = require("path");
|
|
145085
145311
|
var import_events5 = require("events");
|
|
145086
145312
|
var import_assert = __toESM(require("assert"), 1);
|
|
145087
145313
|
var import_buffer2 = require("buffer");
|
|
@@ -145091,9 +145317,9 @@ var import_node_path15 = require("path");
|
|
|
145091
145317
|
var import_node_path16 = require("path");
|
|
145092
145318
|
var import_fs26 = __toESM(require("fs"), 1);
|
|
145093
145319
|
var import_fs27 = __toESM(require("fs"), 1);
|
|
145094
|
-
var import_path23 = __toESM(require("path"), 1);
|
|
145095
|
-
var import_node_path17 = require("path");
|
|
145096
145320
|
var import_path24 = __toESM(require("path"), 1);
|
|
145321
|
+
var import_node_path17 = require("path");
|
|
145322
|
+
var import_path25 = __toESM(require("path"), 1);
|
|
145097
145323
|
var import_node_fs12 = __toESM(require("fs"), 1);
|
|
145098
145324
|
var import_node_assert = __toESM(require("assert"), 1);
|
|
145099
145325
|
var import_node_crypto5 = require("crypto");
|
|
@@ -145103,7 +145329,7 @@ var import_fs28 = __toESM(require("fs"), 1);
|
|
|
145103
145329
|
var import_node_fs14 = __toESM(require("fs"), 1);
|
|
145104
145330
|
var import_node_path19 = __toESM(require("path"), 1);
|
|
145105
145331
|
var import_node_fs15 = __toESM(require("fs"), 1);
|
|
145106
|
-
var
|
|
145332
|
+
var import_promises19 = __toESM(require("fs/promises"), 1);
|
|
145107
145333
|
var import_node_path20 = __toESM(require("path"), 1);
|
|
145108
145334
|
var import_node_path21 = require("path");
|
|
145109
145335
|
var import_node_fs16 = __toESM(require("fs"), 1);
|
|
@@ -146458,11 +146684,11 @@ var vn = (s3) => {
|
|
|
146458
146684
|
};
|
|
146459
146685
|
var Qi = (s3, t2) => {
|
|
146460
146686
|
let e = new Map(t2.map((n) => [ut(n), true])), i = s3.filter, r = (n, o = "") => {
|
|
146461
|
-
let h = o || (0,
|
|
146687
|
+
let h = o || (0, import_path23.parse)(n).root || ".", a;
|
|
146462
146688
|
if (n === h) a = false;
|
|
146463
146689
|
else {
|
|
146464
146690
|
let l = e.get(n);
|
|
146465
|
-
a = l !== void 0 ? l : r((0,
|
|
146691
|
+
a = l !== void 0 ? l : r((0, import_path23.dirname)(n), h);
|
|
146466
146692
|
}
|
|
146467
146693
|
return e.set(n, a), a;
|
|
146468
146694
|
};
|
|
@@ -146582,7 +146808,7 @@ var de = class extends A {
|
|
|
146582
146808
|
let [o, h] = ce(this.path);
|
|
146583
146809
|
o && typeof h == "string" && (this.path = h, r = o);
|
|
146584
146810
|
}
|
|
146585
|
-
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 ||
|
|
146811
|
+
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 });
|
|
146586
146812
|
let n = this.statCache.get(this.absolute);
|
|
146587
146813
|
n ? this[si](n) : this[ss]();
|
|
146588
146814
|
}
|
|
@@ -146641,7 +146867,7 @@ var de = class extends A {
|
|
|
146641
146867
|
}
|
|
146642
146868
|
[sr](t2) {
|
|
146643
146869
|
if (!this.stat) throw new Error("cannot create link entry without stat");
|
|
146644
|
-
this.type = "Link", this.linkpath = f(
|
|
146870
|
+
this.type = "Link", this.linkpath = f(import_path24.default.relative(this.cwd, t2)), this.stat.size = 0, this[fe](), this.end();
|
|
146645
146871
|
}
|
|
146646
146872
|
[er]() {
|
|
146647
146873
|
if (!this.stat) throw new Error("cannot create file entry without stat");
|
|
@@ -147055,7 +147281,7 @@ var wt = class extends A {
|
|
|
147055
147281
|
return typeof t2 == "string" ? this[ci](t2) : this[or](t2), this.flowing;
|
|
147056
147282
|
}
|
|
147057
147283
|
[or](t2) {
|
|
147058
|
-
let e = f(
|
|
147284
|
+
let e = f(import_path25.default.resolve(this.cwd, t2.path));
|
|
147059
147285
|
if (!this.filter(t2.path, t2)) t2.resume();
|
|
147060
147286
|
else {
|
|
147061
147287
|
let i = new pi(t2.path, e);
|
|
@@ -147064,7 +147290,7 @@ var wt = class extends A {
|
|
|
147064
147290
|
this[Ft]();
|
|
147065
147291
|
}
|
|
147066
147292
|
[ci](t2) {
|
|
147067
|
-
let e = f(
|
|
147293
|
+
let e = f(import_path25.default.resolve(this.cwd, t2));
|
|
147068
147294
|
this[W].push(new pi(t2, e)), this[Ft]();
|
|
147069
147295
|
}
|
|
147070
147296
|
[ds](t2) {
|
|
@@ -147335,7 +147561,7 @@ var gr = (s3, t2, e) => {
|
|
|
147335
147561
|
E2 ? e(E2) : x2 && a ? Es(x2, o, h, (Le) => S2(Le)) : n ? import_node_fs15.default.chmod(s3, r, e) : e();
|
|
147336
147562
|
};
|
|
147337
147563
|
if (s3 === d) return no(s3, S2);
|
|
147338
|
-
if (l) return
|
|
147564
|
+
if (l) return import_promises19.default.mkdir(s3, { mode: r, recursive: true }).then((E2) => S2(null, E2 ?? void 0), S2);
|
|
147339
147565
|
let D2 = f(import_node_path20.default.relative(d, s3)).split("/");
|
|
147340
147566
|
Ss(d, D2, r, c, d, void 0, S2);
|
|
147341
147567
|
};
|