sessiongraph-app-darwin-x64 1.0.3 → 1.0.5
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/package.json +2 -2
- package/payload/SessionGraph.app/Contents/Info.plist +2 -2
- package/payload/SessionGraph.app/Contents/MacOS/sessiongraph +0 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/server.mjs +425 -134
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-ngj67_1P.js → index-3_I59bPI.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-DZ3QjOks.js → index-86i6pjnx.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-Ca1o8F2F.js → index-BEabiGl5.js} +16 -16
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-DmhroAg3.js → index-DxQk-77k.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-Oz3Ov7Mv.css → index-vX8x5oFC.css} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{scene-DpPyjrii.js → scene-CEalI0mr.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{share-BDMRLovI.js → share-BydK_UaB.js} +3 -3
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/worker-DwqxiDWY.js +2 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/index.html +2 -2
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/LICENSE-OFL-1.1.txt +93 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/NOTICE.txt +22 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/amp.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/antigravity.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/aside.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/augment.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/cherry.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/codebuddy.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/codebuff.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/commandcode.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/crush.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/deepseek.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/devin.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/droid.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/freebuff.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/fx.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/gajae.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/goose.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/grok.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/hermes.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/hindsight.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/jcode.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/junie.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/kimchi.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/kimi.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/kiro.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/lmstudio.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/mimo.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/minimax.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/mistral.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/muse.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/mux.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/octofriend.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/openclaw.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/prime.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/proma.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/reasonix.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/senpi.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/t3.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/trae.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/unsloth.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/warp.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/zcode.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/zed.svg +1 -0
- package/payload/SessionGraph.app/Contents/_CodeSignature/CodeResources +511 -38
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/worker-YMPBjASm.js +0 -2
|
@@ -2784,7 +2784,7 @@ function extractContent(messages) {
|
|
|
2784
2784
|
for (const raw of messages) {
|
|
2785
2785
|
if (!raw || typeof raw !== "object") continue;
|
|
2786
2786
|
const message2 = raw;
|
|
2787
|
-
const
|
|
2787
|
+
const time3 = Number(message2.time?.created) || 0;
|
|
2788
2788
|
const seen = /* @__PURE__ */ new Set();
|
|
2789
2789
|
const add = (value, kind) => {
|
|
2790
2790
|
if (typeof value !== "string" || !value.trim() || value.startsWith("data:") || seen.has(value)) return;
|
|
@@ -2794,7 +2794,7 @@ function extractContent(messages) {
|
|
|
2794
2794
|
if (size <= 0) return;
|
|
2795
2795
|
const text2 = value.slice(0, size);
|
|
2796
2796
|
remaining -= text2.length;
|
|
2797
|
-
fragments.push({ text: text2, kind, time:
|
|
2797
|
+
fragments.push({ text: text2, kind, time: time3 });
|
|
2798
2798
|
};
|
|
2799
2799
|
const strings = (value, depth = 0) => {
|
|
2800
2800
|
if (depth > 5 || remaining <= 0) {
|
|
@@ -2873,7 +2873,7 @@ var blankSession = (source, nativeID, directory2 = "") => ({
|
|
|
2873
2873
|
cost: null,
|
|
2874
2874
|
tokens: null
|
|
2875
2875
|
});
|
|
2876
|
-
var blankMessage = (id2,
|
|
2876
|
+
var blankMessage = (id2, time3, role) => ({ id: id2, time: time3, role, fragments: [], files: [], tools: [] });
|
|
2877
2877
|
function addText(message2, value, kind) {
|
|
2878
2878
|
if (typeof value !== "string" || !value.trim() || value.startsWith("data:")) return;
|
|
2879
2879
|
const remaining = Math.max(0, 128e3 - message2.fragments.reduce((n, f) => n + f.text.length, 0));
|
|
@@ -2897,7 +2897,7 @@ function toolText(message2, value, depth = 0) {
|
|
|
2897
2897
|
}
|
|
2898
2898
|
|
|
2899
2899
|
// server/activity.ts
|
|
2900
|
-
var messageTime = (
|
|
2900
|
+
var messageTime = (time3) => Number.isFinite(time3) && time3 > 0 && time3 <= 864e13 ? time3 : null;
|
|
2901
2901
|
var isUserMessage = (message2) => message2.role === "user" && message2.fragments.some((f) => f.kind === "You" && f.text.trim());
|
|
2902
2902
|
var activitySQL = `SELECT min(time) AS firstMessageAt, max(time) AS lastMessageAt,
|
|
2903
2903
|
coalesce(sum(is_user), 0) AS userMessages,
|
|
@@ -2928,8 +2928,8 @@ function eventText(value, limit = 32e3) {
|
|
|
2928
2928
|
}
|
|
2929
2929
|
}
|
|
2930
2930
|
function eventFor(message2, id2, kind, name, text2 = "", fields2 = {}) {
|
|
2931
|
-
const
|
|
2932
|
-
const event = { id: id2, kind, name, role: message2.role, time:
|
|
2931
|
+
const time3 = messageTime(message2.time);
|
|
2932
|
+
const event = { id: id2, kind, name, role: message2.role, time: time3, timeSource: time3 ? "message" : "unknown", text: eventText(text2, 64e3), ...fields2 };
|
|
2933
2933
|
event.partial ||= [event.text, event.input, event.output].some((value) => /\[(shortened|omitted|unavailable)\]/.test(value || "")) || text2.length > 64e3;
|
|
2934
2934
|
return event;
|
|
2935
2935
|
}
|
|
@@ -2997,7 +2997,7 @@ function normalizedEvents(message2, sessionID) {
|
|
|
2997
2997
|
const files = message2.files.map((file, i) => eventFor(message2, `file:${i}`, "file_change", file.path, `${file.source} \xB7 ${file.steps} recorded step(s)`, { nativeType: file.source }));
|
|
2998
2998
|
return [...events, ...files].slice(0, 200).map((event) => {
|
|
2999
2999
|
const text2 = String(event.text || "").slice(0, 64e3), input = event.input?.slice(0, 32e3), output = event.output?.slice(0, 64e3);
|
|
3000
|
-
const
|
|
3000
|
+
const time3 = messageTime(event.time || 0);
|
|
3001
3001
|
return {
|
|
3002
3002
|
...event,
|
|
3003
3003
|
id: digest([message2.id, event.id]),
|
|
@@ -3009,8 +3009,8 @@ function normalizedEvents(message2, sessionID) {
|
|
|
3009
3009
|
callID: event.callID ? String(event.callID).slice(0, 512) : void 0,
|
|
3010
3010
|
parentID: event.parentID ? String(event.parentID).slice(0, 512) : void 0,
|
|
3011
3011
|
endTime: messageTime(event.endTime || 0),
|
|
3012
|
-
time:
|
|
3013
|
-
timeSource:
|
|
3012
|
+
time: time3,
|
|
3013
|
+
timeSource: time3 ? event.timeSource : "unknown",
|
|
3014
3014
|
text: text2,
|
|
3015
3015
|
input,
|
|
3016
3016
|
output,
|
|
@@ -3024,21 +3024,21 @@ function opencodeEvents(raw, message2) {
|
|
|
3024
3024
|
const fields2 = { nativeID: message2.id, nativeType: String(raw.type), timeSource: message2.time ? "recorded" : "unknown" };
|
|
3025
3025
|
if (raw.type === "user") return [messageEvent(message2, typeof raw.text === "string" ? raw.text : ""), ...raw.files?.length ? [eventFor(message2, "attachments", "event", "Attachments", "Non-text attachments are not included.", { partial: true })] : []];
|
|
3026
3026
|
if (raw.type !== "assistant") {
|
|
3027
|
-
const
|
|
3027
|
+
const status2 = ["pending", "running", "completed", "failed"].includes(raw.status) ? raw.status : "unknown";
|
|
3028
3028
|
const known = ["compaction", "system", "synthetic", "shell", "model-switched", "agent-switched", "location-switched", "skill", "idle"].includes(raw.type);
|
|
3029
|
-
return [eventFor(message2, "event", raw.type === "compaction" ? "compaction" : "event", raw.description || raw.type, eventText(raw.summary ?? raw.text ?? raw.error ?? (raw.type === "shell" ? raw.command : raw)), { ...fields2, role: "system", status, output: raw.type === "shell" ? eventText(raw.output?.output) : void 0, partial: !known || Boolean(raw.output?.truncated) })];
|
|
3029
|
+
return [eventFor(message2, "event", raw.type === "compaction" ? "compaction" : "event", raw.description || raw.type, eventText(raw.summary ?? raw.text ?? raw.error ?? (raw.type === "shell" ? raw.command : raw)), { ...fields2, role: "system", status: status2, output: raw.type === "shell" ? eventText(raw.output?.output) : void 0, partial: !known || Boolean(raw.output?.truncated) })];
|
|
3030
3030
|
}
|
|
3031
3031
|
const events = [];
|
|
3032
3032
|
for (const [i, part] of (Array.isArray(raw.content) ? raw.content.slice(0, 200) : []).entries()) {
|
|
3033
3033
|
const id2 = `${part.type}:${part.id || i}`, native = { nativeID: part.id, nativeType: String(part.type) };
|
|
3034
|
-
const
|
|
3035
|
-
const timing =
|
|
3034
|
+
const time3 = messageTime(part.time?.created);
|
|
3035
|
+
const timing = time3 ? { time: time3, timeSource: "recorded" } : {};
|
|
3036
3036
|
if (part.type === "text") events.push(eventFor(message2, id2, "message", "Assistant message", part.text || "", { ...native, ...timing }));
|
|
3037
3037
|
else if (part.type === "reasoning") events.push(eventFor(message2, id2, "reasoning", "Recorded reasoning", part.text || "", { ...native, ...timing }));
|
|
3038
3038
|
else if (part.type === "tool") {
|
|
3039
3039
|
const state2 = part.state || {}, endTime = messageTime(part.time?.completed);
|
|
3040
|
-
const
|
|
3041
|
-
const common = { ...native, callID: part.id, status, endTime };
|
|
3040
|
+
const status2 = state2.status === "error" ? "failed" : state2.status === "streaming" ? "pending" : ["running", "completed"].includes(state2.status) ? state2.status : "unknown";
|
|
3041
|
+
const common = { ...native, callID: part.id, status: status2, endTime };
|
|
3042
3042
|
events.push(eventFor(message2, `${id2}:call`, "tool_call", part.name || "Tool call", "", { ...common, ...timing, input: eventText(state2.input) }));
|
|
3043
3043
|
if (["completed", "error"].includes(state2.status)) events.push(eventFor(message2, `${id2}:result`, "tool_result", part.name || "Tool result", "", { ...common, role: "tool", ...endTime ? { time: endTime, timeSource: "recorded" } : {}, output: eventText(state2.error ?? state2.content, 64e3) }));
|
|
3044
3044
|
} else events.push(eventFor(message2, id2, "event", `${part.type || "Unknown"} content`, "Unsupported content.", { ...native, ...timing, partial: true }));
|
|
@@ -30449,8 +30449,8 @@ async function claudeTranscript(path, revision2) {
|
|
|
30449
30449
|
}
|
|
30450
30450
|
entries2.push(row);
|
|
30451
30451
|
if (typeof row.uuid === "string") {
|
|
30452
|
-
const
|
|
30453
|
-
times.set(row.uuid, Number.isFinite(
|
|
30452
|
+
const time3 = typeof row.timestamp === "string" ? Date.parse(row.timestamp) : NaN;
|
|
30453
|
+
times.set(row.uuid, Number.isFinite(time3) && time3 > 0 ? time3 : 0);
|
|
30454
30454
|
}
|
|
30455
30455
|
} catch {
|
|
30456
30456
|
partial = true;
|
|
@@ -30482,7 +30482,7 @@ function claudeTranscriptInfo(transcript, sessionId) {
|
|
|
30482
30482
|
}).find(Boolean);
|
|
30483
30483
|
const title = rows2.findLast((row) => ["custom-title", "ai-title", "summary"].includes(String(row.type)) && typeof (row.customTitle || row.aiTitle || row.summary) === "string");
|
|
30484
30484
|
const cwd2 = rows2.findLast((row) => row.type === "relocated" && typeof row.relocatedCwd === "string")?.relocatedCwd || messages.find((row) => typeof row.cwd === "string")?.cwd;
|
|
30485
|
-
const createdAt = messages.map((row) => transcript.times.get(String(row.uuid))).find((
|
|
30485
|
+
const createdAt = messages.map((row) => transcript.times.get(String(row.uuid))).find((time3) => time3 && time3 > 0);
|
|
30486
30486
|
return { sessionId, summary: String(title?.customTitle || title?.aiTitle || title?.summary || firstPrompt || "Claude Code session"), firstPrompt, cwd: typeof cwd2 === "string" ? cwd2 : void 0, createdAt, lastModified: transcript.modified, fileSize: transcript.size };
|
|
30487
30487
|
}
|
|
30488
30488
|
function claudeTranscriptStore(transcript, sessionId, agent) {
|
|
@@ -30993,7 +30993,9 @@ function sqliteRevision(path) {
|
|
|
30993
30993
|
}
|
|
30994
30994
|
})]);
|
|
30995
30995
|
}
|
|
30996
|
-
function withSqliteSnapshot(path, read3, expected) {
|
|
30996
|
+
function withSqliteSnapshot(path, read3, expected, pinned = false) {
|
|
30997
|
+
const retained = copies.get(path);
|
|
30998
|
+
if (pinned && expected && retained?.revision === expected) return read3(retained.db);
|
|
30997
30999
|
const revision2 = sqliteRevision(path);
|
|
30998
31000
|
if (expected && revision2 !== expected) throw new Error("History database changed during import; import again.");
|
|
30999
31001
|
let copy = copies.get(path);
|
|
@@ -31029,7 +31031,7 @@ function withSqliteSnapshot(path, read3, expected) {
|
|
|
31029
31031
|
}
|
|
31030
31032
|
}
|
|
31031
31033
|
const result = read3(copy.db);
|
|
31032
|
-
if (sqliteRevision(path) !== revision2) throw new Error("History database changed during reading; import again.");
|
|
31034
|
+
if (!pinned && sqliteRevision(path) !== revision2) throw new Error("History database changed during reading; import again.");
|
|
31033
31035
|
return result;
|
|
31034
31036
|
}
|
|
31035
31037
|
function hasTable(db2, name) {
|
|
@@ -31620,17 +31622,291 @@ var codexAdapter = {
|
|
|
31620
31622
|
}
|
|
31621
31623
|
};
|
|
31622
31624
|
|
|
31625
|
+
// server/adapters/t3-code.ts
|
|
31626
|
+
import { lstat as lstat4 } from "node:fs/promises";
|
|
31627
|
+
import { homedir as homedir6 } from "node:os";
|
|
31628
|
+
import { isAbsolute as isAbsolute2, join as join11 } from "node:path";
|
|
31629
|
+
var SOURCE = "t3-code";
|
|
31630
|
+
var PAGE = 100;
|
|
31631
|
+
var MAX_THREADS = 2e4;
|
|
31632
|
+
var MAX_ITEM_JSON = 256e3;
|
|
31633
|
+
var providerSource = { codex: "codex", claudeAgent: "claude-code", opencode: "opencode" };
|
|
31634
|
+
var string = (value) => typeof value === "string" ? value : "";
|
|
31635
|
+
function parsedObject(value) {
|
|
31636
|
+
if (typeof value !== "string") return;
|
|
31637
|
+
try {
|
|
31638
|
+
const parsed = JSON.parse(value);
|
|
31639
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
31640
|
+
} catch {
|
|
31641
|
+
return;
|
|
31642
|
+
}
|
|
31643
|
+
}
|
|
31644
|
+
function time2(value) {
|
|
31645
|
+
const parsed = typeof value === "string" ? Date.parse(value) : typeof value === "number" ? value : NaN;
|
|
31646
|
+
return Number.isFinite(parsed) && parsed > 0 && parsed <= 864e13 ? parsed : 0;
|
|
31647
|
+
}
|
|
31648
|
+
function status(value) {
|
|
31649
|
+
return ["pending", "running", "completed", "failed"].includes(string(value)) ? value : "unknown";
|
|
31650
|
+
}
|
|
31651
|
+
async function databasePath2() {
|
|
31652
|
+
const root3 = process.env.SESSIONGRAPH_T3_CODE_HISTORY_DIR || process.env.T3CODE_HOME || join11(homedir6(), ".t3");
|
|
31653
|
+
const paths = /\.sqlite$/.test(root3) ? [root3] : [
|
|
31654
|
+
join11(root3, "userdata", "statev2.sqlite"),
|
|
31655
|
+
join11(root3, "statev2.sqlite"),
|
|
31656
|
+
join11(root3, "userdata", "state.sqlite"),
|
|
31657
|
+
join11(root3, "state.sqlite")
|
|
31658
|
+
];
|
|
31659
|
+
for (const path of paths) {
|
|
31660
|
+
try {
|
|
31661
|
+
if ((await lstat4(path)).isFile()) return path;
|
|
31662
|
+
} catch (error) {
|
|
31663
|
+
if (error.code !== "ENOENT") throw error;
|
|
31664
|
+
}
|
|
31665
|
+
}
|
|
31666
|
+
}
|
|
31667
|
+
function batches(values, size = 500) {
|
|
31668
|
+
const result = [];
|
|
31669
|
+
for (let i = 0; i < values.length; i += size) result.push(values.slice(i, i + size));
|
|
31670
|
+
return result;
|
|
31671
|
+
}
|
|
31672
|
+
function projectRoots(db2, ids) {
|
|
31673
|
+
const roots = /* @__PURE__ */ new Map();
|
|
31674
|
+
if (!hasTable(db2, "projection_projects")) return roots;
|
|
31675
|
+
for (const batch of batches([...new Set(ids.filter(Boolean))])) {
|
|
31676
|
+
const placeholders = batch.map(() => "?").join(",");
|
|
31677
|
+
for (const row of db2.prepare(`SELECT project_id, substr(workspace_root,1,4096) AS workspace_root FROM projection_projects WHERE deleted_at IS NULL AND project_id IN (${placeholders})`).all(...batch))
|
|
31678
|
+
roots.set(string(row.project_id), string(row.workspace_root));
|
|
31679
|
+
}
|
|
31680
|
+
return roots;
|
|
31681
|
+
}
|
|
31682
|
+
function aggregates(db2, table, ids) {
|
|
31683
|
+
const result = /* @__PURE__ */ new Map();
|
|
31684
|
+
if (!hasTable(db2, table)) return /* @__PURE__ */ new Map();
|
|
31685
|
+
for (const batch of batches(ids)) {
|
|
31686
|
+
const placeholders = batch.map(() => "?").join(",");
|
|
31687
|
+
for (const row of db2.prepare(`SELECT thread_id, COUNT(*) AS n, MAX(updated_at) AS latest FROM ${table} WHERE thread_id IN (${placeholders}) GROUP BY thread_id`).all(...batch))
|
|
31688
|
+
result.set(string(row.thread_id), [Number(row.n), string(row.latest)]);
|
|
31689
|
+
}
|
|
31690
|
+
return result;
|
|
31691
|
+
}
|
|
31692
|
+
function linkedSessions(db2, ids) {
|
|
31693
|
+
const links = /* @__PURE__ */ new Map();
|
|
31694
|
+
if (!hasTable(db2, "orchestration_v2_projection_provider_threads")) return links;
|
|
31695
|
+
for (const batch of batches(ids)) {
|
|
31696
|
+
const placeholders = batch.map(() => "?").join(",");
|
|
31697
|
+
for (const row of db2.prepare(`SELECT thread_id, provider,
|
|
31698
|
+
CASE WHEN json_valid(payload_json) THEN substr(json_extract(payload_json,'$.nativeThreadRef.nativeId'),1,513) END AS native_id,
|
|
31699
|
+
CASE WHEN json_valid(payload_json) THEN json_extract(payload_json,'$.nativeThreadRef.strength') END AS strength,
|
|
31700
|
+
CASE WHEN json_valid(payload_json) THEN json_extract(payload_json,'$.nativeThreadRef.driver') END AS driver
|
|
31701
|
+
FROM orchestration_v2_projection_provider_threads WHERE thread_id IN (${placeholders})`).all(...batch)) {
|
|
31702
|
+
const source = providerSource[string(row.provider)];
|
|
31703
|
+
const nativeID = string(row.native_id);
|
|
31704
|
+
if (!source || row.strength !== "strong" || row.driver && row.driver !== row.provider || !nativeID || nativeID.length > 512) continue;
|
|
31705
|
+
const id2 = string(row.thread_id);
|
|
31706
|
+
links.set(id2, [.../* @__PURE__ */ new Set([...links.get(id2) || [], identity(source, nativeID)])]);
|
|
31707
|
+
}
|
|
31708
|
+
}
|
|
31709
|
+
return links;
|
|
31710
|
+
}
|
|
31711
|
+
function discoverV2(db2, path, databaseRevision) {
|
|
31712
|
+
if (!hasTable(db2, "orchestration_v2_projection_threads") || !hasTable(db2, "orchestration_v2_projection_turn_items")) throw new Error("Unsupported T3 Code database schema.");
|
|
31713
|
+
const rows2 = db2.prepare(`SELECT thread_id, project_id, substr(title,1,300) AS title, default_provider, created_at, updated_at, archived_at,
|
|
31714
|
+
CASE WHEN json_valid(payload_json) THEN substr(json_extract(payload_json,'$.worktreePath'),1,4096) END AS worktree_path,
|
|
31715
|
+
CASE WHEN json_valid(payload_json) THEN substr(json_extract(payload_json,'$.modelSelection.model'),1,200) END AS model,
|
|
31716
|
+
CASE WHEN json_valid(payload_json) THEN json_extract(payload_json,'$.lineage.parentThreadId') END AS parent_thread_id,
|
|
31717
|
+
CASE WHEN json_valid(payload_json) THEN json_extract(payload_json,'$.lineage.relationshipToParent') END AS relationship,
|
|
31718
|
+
json_valid(payload_json) AS valid_payload
|
|
31719
|
+
FROM orchestration_v2_projection_threads WHERE deleted_at IS NULL ORDER BY created_at, thread_id LIMIT ?`).all(MAX_THREADS + 1);
|
|
31720
|
+
const selected = rows2.slice(0, MAX_THREADS), ids = selected.map((row) => string(row.thread_id));
|
|
31721
|
+
const roots = projectRoots(db2, selected.map((row) => string(row.project_id)));
|
|
31722
|
+
const counts = aggregates(db2, "orchestration_v2_projection_messages", ids);
|
|
31723
|
+
const items = aggregates(db2, "orchestration_v2_projection_turn_items", ids);
|
|
31724
|
+
const links = linkedSessions(db2, ids);
|
|
31725
|
+
const sessions = [], projects = /* @__PURE__ */ new Map(), warnings = [];
|
|
31726
|
+
if (rows2.length > MAX_THREADS) warnings.push(`T3 Code discovery is limited to ${MAX_THREADS.toLocaleString()} threads.`);
|
|
31727
|
+
let unreadableMetadata = 0;
|
|
31728
|
+
for (const row of selected) {
|
|
31729
|
+
const nativeID = string(row.thread_id), created = time2(row.created_at);
|
|
31730
|
+
if (!nativeID || nativeID.length > 512 || !created) continue;
|
|
31731
|
+
if (!row.valid_payload) unreadableMetadata++;
|
|
31732
|
+
const directory2 = string(row.worktree_path) || roots.get(string(row.project_id)) || "";
|
|
31733
|
+
const p = project(SOURCE, directory2);
|
|
31734
|
+
projects.set(p.id, p);
|
|
31735
|
+
const session = blankSession(SOURCE, nativeID, directory2);
|
|
31736
|
+
const parent2 = string(row.parent_thread_id);
|
|
31737
|
+
session.parentID = row.relationship === "subagent" && parent2 ? identity(SOURCE, parent2) : void 0;
|
|
31738
|
+
session.forkID = row.relationship === "fork" && parent2 ? identity(SOURCE, parent2) : void 0;
|
|
31739
|
+
Object.assign(session, {
|
|
31740
|
+
title: string(row.title) || "T3 Code thread",
|
|
31741
|
+
projectID: p.id,
|
|
31742
|
+
created,
|
|
31743
|
+
updated: time2(row.updated_at) || created,
|
|
31744
|
+
archived: Boolean(row.archived_at),
|
|
31745
|
+
model: string(row.model) || "Unknown model",
|
|
31746
|
+
provider: string(row.default_provider),
|
|
31747
|
+
agent: "T3 Code",
|
|
31748
|
+
linkedSessionIDs: links.get(nativeID) || []
|
|
31749
|
+
});
|
|
31750
|
+
const revision2 = digest([row.updated_at, counts.get(nativeID), items.get(nativeID), links.get(nativeID)]);
|
|
31751
|
+
sessions.push({ session, revision: revision2, locator: { path, databaseRevision, threadID: nativeID, format: "v2", metadataPartial: row.valid_payload ? "" : "1" } });
|
|
31752
|
+
}
|
|
31753
|
+
if (unreadableMetadata) warnings.push(`${unreadableMetadata} T3 Code threads had unreadable metadata; model or lineage may be unavailable.`);
|
|
31754
|
+
return { sessions, projects: [...projects.values()], warnings };
|
|
31755
|
+
}
|
|
31756
|
+
function discoverV1(db2, path, databaseRevision) {
|
|
31757
|
+
if (!hasTable(db2, "projection_threads") || !hasTable(db2, "projection_thread_messages")) throw new Error("Unsupported T3 Code database schema.");
|
|
31758
|
+
const rows2 = db2.prepare(`SELECT thread_id, project_id, substr(title,1,300) AS title, substr(worktree_path,1,4096) AS worktree_path,
|
|
31759
|
+
created_at, updated_at, archived_at,
|
|
31760
|
+
CASE WHEN json_valid(model_selection_json) THEN substr(json_extract(model_selection_json,'$.model'),1,200) END AS model
|
|
31761
|
+
FROM projection_threads WHERE deleted_at IS NULL ORDER BY created_at, thread_id LIMIT ?`).all(MAX_THREADS + 1);
|
|
31762
|
+
const selected = rows2.slice(0, MAX_THREADS);
|
|
31763
|
+
const roots = projectRoots(db2, selected.map((row) => string(row.project_id)));
|
|
31764
|
+
const counts = aggregates(db2, "projection_thread_messages", selected.map((row) => string(row.thread_id)));
|
|
31765
|
+
const sessions = [], projects = /* @__PURE__ */ new Map();
|
|
31766
|
+
for (const row of selected) {
|
|
31767
|
+
const nativeID = string(row.thread_id), created = time2(row.created_at);
|
|
31768
|
+
if (!nativeID || nativeID.length > 512 || !created) continue;
|
|
31769
|
+
const directory2 = string(row.worktree_path) || roots.get(string(row.project_id)) || "";
|
|
31770
|
+
const p = project(SOURCE, directory2);
|
|
31771
|
+
projects.set(p.id, p);
|
|
31772
|
+
const session = blankSession(SOURCE, nativeID, directory2);
|
|
31773
|
+
Object.assign(session, {
|
|
31774
|
+
title: string(row.title) || "T3 Code thread",
|
|
31775
|
+
projectID: p.id,
|
|
31776
|
+
created,
|
|
31777
|
+
updated: time2(row.updated_at) || created,
|
|
31778
|
+
archived: Boolean(row.archived_at),
|
|
31779
|
+
model: string(row.model) || "Unknown model",
|
|
31780
|
+
agent: "T3 Code"
|
|
31781
|
+
});
|
|
31782
|
+
sessions.push({ session, revision: digest([row.updated_at, counts.get(nativeID)]), locator: { path, databaseRevision, threadID: nativeID, format: "v1" } });
|
|
31783
|
+
}
|
|
31784
|
+
const warnings = ["Legacy T3 Code V1 stores text conversations but has limited event and provider-link coverage."];
|
|
31785
|
+
if (rows2.length > MAX_THREADS) warnings.push(`T3 Code discovery is limited to ${MAX_THREADS.toLocaleString()} threads.`);
|
|
31786
|
+
return { sessions, projects: [...projects.values()], warnings };
|
|
31787
|
+
}
|
|
31788
|
+
function v2Message(row, directory2) {
|
|
31789
|
+
const parsed = parsedObject(row.payload_json), item = parsed || {}, type = string(row.type), id2 = string(row.turn_item_id);
|
|
31790
|
+
const role = type === "user_message" ? "user" : type === "assistant_message" ? "assistant" : type === "reasoning" ? "assistant" : "tool";
|
|
31791
|
+
const message2 = blankMessage(`item:${id2}`, time2(item.startedAt || item.createdAt), role);
|
|
31792
|
+
const recorded = Boolean(message2.time), name = string(item.title || item.toolName) || type.replaceAll("_", " ");
|
|
31793
|
+
const fields2 = {
|
|
31794
|
+
nativeID: id2,
|
|
31795
|
+
nativeType: type,
|
|
31796
|
+
parentID: string(item.parentItemId) || void 0,
|
|
31797
|
+
status: status(row.status),
|
|
31798
|
+
endTime: time2(item.completedAt) || null,
|
|
31799
|
+
timeSource: recorded ? "recorded" : "unknown"
|
|
31800
|
+
};
|
|
31801
|
+
if (!parsed) {
|
|
31802
|
+
message2.partial = true;
|
|
31803
|
+
message2.events = [eventFor(message2, id2, "event", name, "Oversized or unreadable T3 item omitted.", { ...fields2, partial: true })];
|
|
31804
|
+
return message2;
|
|
31805
|
+
}
|
|
31806
|
+
if (type === "user_message" || type === "assistant_message") {
|
|
31807
|
+
const body2 = string(item.text);
|
|
31808
|
+
if (body2) addText(message2, body2, role === "user" ? "You" : "Assistant");
|
|
31809
|
+
message2.events = [{ ...messageEvent(message2, body2, id2), ...fields2 }];
|
|
31810
|
+
if (Array.isArray(item.attachments) && item.attachments.length) message2.partial = true;
|
|
31811
|
+
return message2;
|
|
31812
|
+
}
|
|
31813
|
+
if (type === "reasoning") {
|
|
31814
|
+
message2.events = [eventFor(message2, id2, "reasoning", "Recorded reasoning", string(item.text), fields2)];
|
|
31815
|
+
return message2;
|
|
31816
|
+
}
|
|
31817
|
+
if (type === "file_change") {
|
|
31818
|
+
const file = string(item.fileName), completed = status(row.status) === "completed";
|
|
31819
|
+
if (file && completed) message2.files.push({ path: isAbsolute2(file) ? file : join11(directory2, file), source: "file change", steps: 1 });
|
|
31820
|
+
message2.events = [eventFor(message2, id2, "file_change", file || name, "", fields2)];
|
|
31821
|
+
return message2;
|
|
31822
|
+
}
|
|
31823
|
+
if (["command_execution", "dynamic_tool", "file_search", "web_search"].includes(type)) {
|
|
31824
|
+
const input = eventText(item.input ?? item.pattern ?? item.patterns, 32e3);
|
|
31825
|
+
const output = eventText(item.output ?? item.results, 64e3);
|
|
31826
|
+
const kind2 = fields2.status === "completed" || fields2.status === "failed" ? "tool_result" : "tool_call";
|
|
31827
|
+
message2.tools.push(name);
|
|
31828
|
+
if (input) addText(message2, input, "Tool");
|
|
31829
|
+
if (output) addText(message2, output, "Tool");
|
|
31830
|
+
message2.events = [eventFor(message2, id2, kind2, name, "", { ...fields2, input, output })];
|
|
31831
|
+
return message2;
|
|
31832
|
+
}
|
|
31833
|
+
const kind = type === "compaction" ? "compaction" : type === "error" ? "error" : "event";
|
|
31834
|
+
message2.events = [eventFor(message2, id2, kind, name, string(item.text), fields2)];
|
|
31835
|
+
return message2;
|
|
31836
|
+
}
|
|
31837
|
+
function readV2(db2, candidate, cursor) {
|
|
31838
|
+
let ordinal = -1, id2 = "";
|
|
31839
|
+
if (cursor) {
|
|
31840
|
+
const separator = cursor.indexOf(":");
|
|
31841
|
+
ordinal = Number(cursor.slice(0, separator));
|
|
31842
|
+
id2 = cursor.slice(separator + 1);
|
|
31843
|
+
if (separator < 1 || !Number.isSafeInteger(ordinal) || !id2) throw new Error("Invalid T3 Code history cursor.");
|
|
31844
|
+
}
|
|
31845
|
+
const rows2 = db2.prepare(`SELECT turn_item_id, ordinal, type, status,
|
|
31846
|
+
CASE WHEN length(payload_json)<=? THEN payload_json END AS payload_json
|
|
31847
|
+
FROM orchestration_v2_projection_turn_items
|
|
31848
|
+
WHERE thread_id=? AND (ordinal>? OR (ordinal=? AND turn_item_id>?))
|
|
31849
|
+
ORDER BY ordinal, turn_item_id LIMIT ?`).all(MAX_ITEM_JSON, candidate.locator.threadID, ordinal, ordinal, id2, PAGE + 1);
|
|
31850
|
+
const page = rows2.slice(0, PAGE), last = page.at(-1);
|
|
31851
|
+
return {
|
|
31852
|
+
messages: page.map((row) => v2Message(row, candidate.session.directory)),
|
|
31853
|
+
cursor: rows2.length > PAGE && last ? `${last.ordinal}:${last.turn_item_id}` : void 0,
|
|
31854
|
+
partial: candidate.locator.metadataPartial === "1" || page.some((row) => !parsedObject(row.payload_json)),
|
|
31855
|
+
note: "T3 Code app-owned messages and activity. Attachments and checkpoint file snapshots are not imported; provider-native histories may contain additional detail."
|
|
31856
|
+
};
|
|
31857
|
+
}
|
|
31858
|
+
function readV1(db2, candidate, cursor) {
|
|
31859
|
+
const offset = cursor ? Number(cursor) : 0;
|
|
31860
|
+
if (!Number.isSafeInteger(offset) || offset < 0) throw new Error("Invalid T3 Code history cursor.");
|
|
31861
|
+
const rows2 = db2.prepare(`SELECT message_id, role, created_at,
|
|
31862
|
+
CASE WHEN length(text)<=? THEN text END AS text FROM projection_thread_messages
|
|
31863
|
+
WHERE thread_id=? ORDER BY created_at, message_id LIMIT ? OFFSET ?`).all(MAX_ITEM_JSON, candidate.locator.threadID, PAGE + 1, offset);
|
|
31864
|
+
const messages = rows2.slice(0, PAGE).map((row) => {
|
|
31865
|
+
const role = row.role === "user" ? "user" : row.role === "assistant" ? "assistant" : "system";
|
|
31866
|
+
const message2 = blankMessage(`message:${row.message_id}`, time2(row.created_at), role);
|
|
31867
|
+
const body2 = string(row.text);
|
|
31868
|
+
if (body2) addText(message2, body2, role === "user" ? "You" : "Assistant");
|
|
31869
|
+
message2.events = [{ ...messageEvent(message2, body2), nativeID: string(row.message_id), nativeType: "legacy-message" }];
|
|
31870
|
+
message2.partial = row.text == null;
|
|
31871
|
+
return message2;
|
|
31872
|
+
});
|
|
31873
|
+
return {
|
|
31874
|
+
messages,
|
|
31875
|
+
cursor: rows2.length > PAGE ? String(offset + PAGE) : void 0,
|
|
31876
|
+
partial: true,
|
|
31877
|
+
note: "Legacy T3 Code text messages only. Tool activity, attachments, and provider links are unavailable."
|
|
31878
|
+
};
|
|
31879
|
+
}
|
|
31880
|
+
var t3CodeAdapter = {
|
|
31881
|
+
id: SOURCE,
|
|
31882
|
+
name: "T3 Code",
|
|
31883
|
+
description: "Local T3 server threads and saved activity \xB7 no running agent required",
|
|
31884
|
+
capabilities: { history: true, forks: true, children: true, files: true },
|
|
31885
|
+
async detect() {
|
|
31886
|
+
return Boolean(await databasePath2());
|
|
31887
|
+
},
|
|
31888
|
+
async discover() {
|
|
31889
|
+
const path = await databasePath2();
|
|
31890
|
+
if (!path) return { sessions: [], projects: [], warnings: ["T3 Code database is unavailable. Saved history is retained."] };
|
|
31891
|
+
const databaseRevision = sqliteRevision(path);
|
|
31892
|
+
return withSqliteSnapshot(path, (db2) => hasTable(db2, "orchestration_v2_projection_threads") ? discoverV2(db2, path, databaseRevision) : discoverV1(db2, path, databaseRevision), databaseRevision);
|
|
31893
|
+
},
|
|
31894
|
+
async read(candidate, cursor) {
|
|
31895
|
+
return withSqliteSnapshot(candidate.locator.path, (db2) => candidate.locator.format === "v2" ? readV2(db2, candidate, cursor) : readV1(db2, candidate, cursor), candidate.locator.databaseRevision, true);
|
|
31896
|
+
}
|
|
31897
|
+
};
|
|
31898
|
+
|
|
31623
31899
|
// server/adapters/cursor.ts
|
|
31624
31900
|
import { createHash as createHash3 } from "node:crypto";
|
|
31625
|
-
import { lstat as
|
|
31626
|
-
import { homedir as
|
|
31627
|
-
import { isAbsolute as
|
|
31901
|
+
import { lstat as lstat5, opendir, readFile as readFile3 } from "node:fs/promises";
|
|
31902
|
+
import { homedir as homedir7 } from "node:os";
|
|
31903
|
+
import { isAbsolute as isAbsolute4, join as join13 } from "node:path";
|
|
31628
31904
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
31629
31905
|
|
|
31630
31906
|
// server/adapters/cursor-message.ts
|
|
31631
31907
|
function cursorTime(value) {
|
|
31632
|
-
const
|
|
31633
|
-
return Number.isFinite(
|
|
31908
|
+
const time3 = typeof value === "number" ? value : typeof value === "string" && /(?:Z|[+-]\d\d:\d\d)$/.test(value) ? Date.parse(value) : 0;
|
|
31909
|
+
return Number.isFinite(time3) && time3 > 0 && time3 <= 864e13 ? time3 : 0;
|
|
31634
31910
|
}
|
|
31635
31911
|
function cursorEnvelopeTime(text2) {
|
|
31636
31912
|
const value = text2.match(/^\s*<timestamp>([^<]+)<\/timestamp>/)?.[1];
|
|
@@ -31658,9 +31934,9 @@ function cursorMessage(raw, fallbackID) {
|
|
|
31658
31934
|
if (!["user", "assistant", "tool", "system"].includes(role)) return;
|
|
31659
31935
|
const content = body2.content;
|
|
31660
31936
|
const firstText = typeof content === "string" ? content : Array.isArray(content) && content[0]?.type === "text" ? content[0].text : "";
|
|
31661
|
-
const
|
|
31937
|
+
const time3 = cursorTime(raw.timestamp) || cursorTime(body2.timestamp) || cursorTime(body2.createdAt) || (role === "user" && typeof firstText === "string" ? cursorEnvelopeTime(firstText) : 0);
|
|
31662
31938
|
const native = [raw.uuid, raw.id, body2.uuid, body2.id].find((id2) => typeof id2 === "string" && id2.length && id2.length <= 512);
|
|
31663
|
-
const msg = blankMessage(native || fallbackID,
|
|
31939
|
+
const msg = blankMessage(native || fallbackID, time3, role);
|
|
31664
31940
|
msg.events = role === "tool" ? [eventFor(msg, "result", "tool_result", body2.name || "Tool result", "", { callID: body2.tool_call_id, output: eventText(content, 64e3), status: "unknown" })] : blockEvents(msg, content);
|
|
31665
31941
|
const kind = role === "user" ? "You" : role === "assistant" ? "Assistant" : "Tool";
|
|
31666
31942
|
const text2 = (value) => addText(msg, role === "user" && typeof value === "string" ? cursorUserText(value) : value, kind);
|
|
@@ -31702,7 +31978,7 @@ function cursorMessage(raw, fallbackID) {
|
|
|
31702
31978
|
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
31703
31979
|
import { chmodSync as chmodSync2, copyFileSync as copyFileSync2, lstatSync as lstatSync3, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "node:fs";
|
|
31704
31980
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
31705
|
-
import { join as
|
|
31981
|
+
import { join as join12 } from "node:path";
|
|
31706
31982
|
var MAX_VALUE = 2e6;
|
|
31707
31983
|
var MAX_BYTES3 = 64e6;
|
|
31708
31984
|
var MAX_NODES = 5e4;
|
|
@@ -31719,11 +31995,11 @@ function withStore(path, read3) {
|
|
|
31719
31995
|
throw error;
|
|
31720
31996
|
}
|
|
31721
31997
|
});
|
|
31722
|
-
const before = stats(), directory2 = mkdtempSync2(
|
|
31998
|
+
const before = stats(), directory2 = mkdtempSync2(join12(tmpdir2(), "sessiongraph-cursor-"));
|
|
31723
31999
|
let db2;
|
|
31724
32000
|
try {
|
|
31725
32001
|
chmodSync2(directory2, 448);
|
|
31726
|
-
const copy =
|
|
32002
|
+
const copy = join12(directory2, "store.db");
|
|
31727
32003
|
files.forEach((file, index) => {
|
|
31728
32004
|
if (before[index]) {
|
|
31729
32005
|
const target = index ? `${copy}-wal` : copy;
|
|
@@ -31860,7 +32136,7 @@ function readCursorStore(path) {
|
|
|
31860
32136
|
}
|
|
31861
32137
|
|
|
31862
32138
|
// server/adapters/cursor-composer.ts
|
|
31863
|
-
import { isAbsolute as
|
|
32139
|
+
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
31864
32140
|
import { fileURLToPath } from "node:url";
|
|
31865
32141
|
var MAX_VALUE2 = 32e6;
|
|
31866
32142
|
var MAX_BUBBLE = 8e6;
|
|
@@ -31872,7 +32148,7 @@ function decode(value) {
|
|
|
31872
32148
|
function directory(raw) {
|
|
31873
32149
|
const value = text(raw.workspaceIdentifier?.uri?.path) || text(raw.workspaceIdentifier?.uri) || text(raw.cwd);
|
|
31874
32150
|
try {
|
|
31875
|
-
return value.startsWith("file:") ? fileURLToPath(value) :
|
|
32151
|
+
return value.startsWith("file:") ? fileURLToPath(value) : isAbsolute3(value) ? value : "";
|
|
31876
32152
|
} catch {
|
|
31877
32153
|
return "";
|
|
31878
32154
|
}
|
|
@@ -31972,13 +32248,13 @@ function readComposer(candidate) {
|
|
|
31972
32248
|
// server/adapters/cursor.ts
|
|
31973
32249
|
var LIMIT = 2e4;
|
|
31974
32250
|
var validID = (id2) => /^[a-z\d][\w-]{0,159}$/i.test(id2);
|
|
31975
|
-
var cwd = (value) => typeof value === "string" &&
|
|
32251
|
+
var cwd = (value) => typeof value === "string" && isAbsolute4(value) && !/[\x00-\x1f\x7f]/.test(value) ? value : "";
|
|
31976
32252
|
var slug = (path) => path.replace(/\\/g, "/").replace(/^([A-Z]):/i, (_, drive) => drive.toLowerCase()).replace(/^\/+|\/+$/g, "").replace(/[/:]+/g, "-");
|
|
31977
32253
|
var hashCwd = (path) => createHash3("md5").update(path).digest("hex");
|
|
31978
|
-
var userData = () => process.platform === "darwin" ?
|
|
32254
|
+
var userData = () => process.platform === "darwin" ? join13(homedir7(), "Library/Application Support/Cursor") : process.platform === "win32" ? join13(process.env.APPDATA || join13(homedir7(), "AppData/Roaming"), "Cursor") : join13(process.env.XDG_CONFIG_HOME || join13(homedir7(), ".config"), "Cursor");
|
|
31979
32255
|
async function fileStats(path) {
|
|
31980
32256
|
try {
|
|
31981
|
-
const s = await
|
|
32257
|
+
const s = await lstat5(path);
|
|
31982
32258
|
if (s.isSymbolicLink()) throw new Error("Cursor history symlinks are not followed.");
|
|
31983
32259
|
return s.isFile() ? s : void 0;
|
|
31984
32260
|
} catch (error) {
|
|
@@ -32003,7 +32279,7 @@ async function json3(path) {
|
|
|
32003
32279
|
async function entries(path, warnings) {
|
|
32004
32280
|
const result = [];
|
|
32005
32281
|
try {
|
|
32006
|
-
if (!(await
|
|
32282
|
+
if (!(await lstat5(path)).isDirectory()) return result;
|
|
32007
32283
|
for await (const entry of await opendir(path)) {
|
|
32008
32284
|
if (!entry.isSymbolicLink()) result.push(entry);
|
|
32009
32285
|
if (result.length === LIMIT) {
|
|
@@ -32018,12 +32294,12 @@ async function entries(path, warnings) {
|
|
|
32018
32294
|
}
|
|
32019
32295
|
async function workspacePaths(root3, warnings) {
|
|
32020
32296
|
const stores = /* @__PURE__ */ new Map();
|
|
32021
|
-
const storage =
|
|
32297
|
+
const storage = join13(root3, "User/workspaceStorage");
|
|
32022
32298
|
for (const entry of await entries(storage, warnings)) if (entry.isDirectory()) {
|
|
32023
|
-
const database =
|
|
32299
|
+
const database = join13(storage, entry.name, "state.vscdb");
|
|
32024
32300
|
stores.set(database, "");
|
|
32025
32301
|
try {
|
|
32026
|
-
const info = await json3(
|
|
32302
|
+
const info = await json3(join13(storage, entry.name, "workspace.json"));
|
|
32027
32303
|
if (typeof info.folder === "string" && info.folder.startsWith("file:")) {
|
|
32028
32304
|
const path = cwd(fileURLToPath2(info.folder));
|
|
32029
32305
|
if (path) stores.set(database, path);
|
|
@@ -32035,7 +32311,7 @@ async function workspacePaths(root3, warnings) {
|
|
|
32035
32311
|
return stores;
|
|
32036
32312
|
}
|
|
32037
32313
|
function createCursorAdapter(options = {}) {
|
|
32038
|
-
const root3 = () => options.home || process.env.SESSIONGRAPH_CURSOR_HOME || process.env.SESSION_ATLAS_CURSOR_HOME ||
|
|
32314
|
+
const root3 = () => options.home || process.env.SESSIONGRAPH_CURSOR_HOME || process.env.SESSION_ATLAS_CURSOR_HOME || join13(homedir7(), ".cursor");
|
|
32039
32315
|
const editor = () => options.userData || process.env.SESSIONGRAPH_CURSOR_USER_DATA_DIR || process.env.SESSION_ATLAS_CURSOR_USER_DATA_DIR || userData();
|
|
32040
32316
|
return {
|
|
32041
32317
|
id: "cursor",
|
|
@@ -32043,13 +32319,13 @@ function createCursorAdapter(options = {}) {
|
|
|
32043
32319
|
description: "Local IDE transcripts, legacy Composer, subagents, and CLI / ACP stores \xB7 read-only",
|
|
32044
32320
|
capabilities: { history: true, forks: false, children: true, files: false },
|
|
32045
32321
|
async detect() {
|
|
32046
|
-
if (await fileStats(
|
|
32047
|
-
for (const entry of await entries(
|
|
32048
|
-
if (entry.isDirectory() && await fileStats(
|
|
32322
|
+
if (await fileStats(join13(editor(), "User/globalStorage/state.vscdb"))) return true;
|
|
32323
|
+
for (const entry of await entries(join13(editor(), "User/workspaceStorage"), [])) {
|
|
32324
|
+
if (entry.isDirectory() && await fileStats(join13(editor(), "User/workspaceStorage", entry.name, "state.vscdb"))) return true;
|
|
32049
32325
|
}
|
|
32050
32326
|
for (const name of ["projects", "chats", "acp-sessions"]) {
|
|
32051
32327
|
try {
|
|
32052
|
-
if ((await
|
|
32328
|
+
if ((await lstat5(join13(root3(), name))).isDirectory()) return true;
|
|
32053
32329
|
} catch {
|
|
32054
32330
|
}
|
|
32055
32331
|
}
|
|
@@ -32059,7 +32335,7 @@ function createCursorAdapter(options = {}) {
|
|
|
32059
32335
|
const warnings = [], found = /* @__PURE__ */ new Map(), blocked = /* @__PURE__ */ new Set();
|
|
32060
32336
|
const workspaceStores = await workspacePaths(editor(), warnings);
|
|
32061
32337
|
const paths = [...new Set([...workspaceStores.values()].filter(Boolean))];
|
|
32062
|
-
const legacyStores = new Map([[
|
|
32338
|
+
const legacyStores = new Map([[join13(editor(), "User/globalStorage/state.vscdb"), ""], ...workspaceStores]);
|
|
32063
32339
|
for (const [path, workspace] of legacyStores) {
|
|
32064
32340
|
try {
|
|
32065
32341
|
if (!await fileStats(path)) continue;
|
|
@@ -32090,7 +32366,7 @@ function createCursorAdapter(options = {}) {
|
|
|
32090
32366
|
if (!stats) return;
|
|
32091
32367
|
const native = parent2 ? `${parent2}/agent/${id2}` : id2;
|
|
32092
32368
|
const locator = { path, kind };
|
|
32093
|
-
if (kind !== "transcript") locator.meta =
|
|
32369
|
+
if (kind !== "transcript") locator.meta = join13(path, "..", "meta.json");
|
|
32094
32370
|
const before = await snapshot(locator);
|
|
32095
32371
|
const extra2 = locator.meta ? await json3(locator.meta) : {};
|
|
32096
32372
|
const meta = kind === "transcript" ? {} : cursorStoreMetadata(path);
|
|
@@ -32129,7 +32405,7 @@ function createCursorAdapter(options = {}) {
|
|
|
32129
32405
|
}
|
|
32130
32406
|
if (!session.directory) locator.directoryNote = "Working directory is unknown; choose one when continuing.";
|
|
32131
32407
|
session.projectID = project("cursor", session.directory).id;
|
|
32132
|
-
session.nativeResume = kind === "cli" && Boolean(session.directory) && hashCwd(session.directory) === workspaceHash && root3() ===
|
|
32408
|
+
session.nativeResume = kind === "cli" && Boolean(session.directory) && hashCwd(session.directory) === workspaceHash && root3() === join13(homedir7(), ".cursor");
|
|
32133
32409
|
locator.snapshot = before;
|
|
32134
32410
|
if (await snapshot(locator) !== before) throw new Error("Cursor session changed during discovery.");
|
|
32135
32411
|
const previous = found.get(session.id);
|
|
@@ -32150,39 +32426,39 @@ function createCursorAdapter(options = {}) {
|
|
|
32150
32426
|
if (kind !== "transcript") blocked.add(identity("cursor", id2));
|
|
32151
32427
|
}
|
|
32152
32428
|
};
|
|
32153
|
-
const projects =
|
|
32429
|
+
const projects = join13(root3(), "projects");
|
|
32154
32430
|
for (const dir of await entries(projects, warnings)) {
|
|
32155
32431
|
if (!dir.isDirectory() || scanned >= LIMIT) continue;
|
|
32156
|
-
const transcripts =
|
|
32432
|
+
const transcripts = join13(projects, dir.name, "agent-transcripts"), directory2 = match(dir.name, slug);
|
|
32157
32433
|
for (const entry of await entries(transcripts, warnings)) {
|
|
32158
32434
|
if (scanned >= LIMIT) break;
|
|
32159
|
-
if (entry.isFile() && entry.name.endsWith(".jsonl")) await add(
|
|
32435
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl")) await add(join13(transcripts, entry.name), entry.name.slice(0, -6), "transcript", directory2);
|
|
32160
32436
|
else if (entry.isFile() && entry.name.endsWith(".txt")) legacy++;
|
|
32161
32437
|
else if (entry.isDirectory() && validID(entry.name)) {
|
|
32162
|
-
await add(
|
|
32163
|
-
for (const child of await entries(
|
|
32164
|
-
if (child.isFile() && child.name.endsWith(".jsonl")) await add(
|
|
32438
|
+
await add(join13(transcripts, entry.name, `${entry.name}.jsonl`), entry.name, "transcript", directory2);
|
|
32439
|
+
for (const child of await entries(join13(transcripts, entry.name, "subagents"), warnings)) {
|
|
32440
|
+
if (child.isFile() && child.name.endsWith(".jsonl")) await add(join13(transcripts, entry.name, "subagents", child.name), child.name.slice(0, -6), "transcript", directory2, entry.name);
|
|
32165
32441
|
if (scanned >= LIMIT) break;
|
|
32166
32442
|
}
|
|
32167
32443
|
}
|
|
32168
32444
|
}
|
|
32169
32445
|
}
|
|
32170
|
-
const chats =
|
|
32446
|
+
const chats = join13(root3(), "chats");
|
|
32171
32447
|
for (const bucket of await entries(chats, warnings)) {
|
|
32172
32448
|
if (!bucket.isDirectory() || scanned >= LIMIT) continue;
|
|
32173
|
-
const folder =
|
|
32174
|
-
if (/^[a-f\d]{32}$/i.test(bucket.name) && await fileStats(
|
|
32449
|
+
const folder = join13(chats, bucket.name), directory2 = match(bucket.name, hashCwd);
|
|
32450
|
+
if (/^[a-f\d]{32}$/i.test(bucket.name) && await fileStats(join13(folder, "store.db"))) {
|
|
32175
32451
|
const id2 = bucket.name.replace(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/, "$1-$2-$3-$4-$5");
|
|
32176
|
-
await add(
|
|
32452
|
+
await add(join13(folder, "store.db"), id2, "cli", "");
|
|
32177
32453
|
}
|
|
32178
32454
|
for (const entry of await entries(folder, warnings)) {
|
|
32179
|
-
if (entry.isDirectory()) await add(
|
|
32455
|
+
if (entry.isDirectory()) await add(join13(folder, entry.name, "store.db"), entry.name, "cli", directory2, "", bucket.name);
|
|
32180
32456
|
if (scanned >= LIMIT) break;
|
|
32181
32457
|
}
|
|
32182
32458
|
}
|
|
32183
|
-
const acp =
|
|
32459
|
+
const acp = join13(root3(), "acp-sessions");
|
|
32184
32460
|
for (const entry of await entries(acp, warnings)) {
|
|
32185
|
-
if (entry.isDirectory()) await add(
|
|
32461
|
+
if (entry.isDirectory()) await add(join13(acp, entry.name, "store.db"), entry.name, "acp", "");
|
|
32186
32462
|
if (scanned >= LIMIT) break;
|
|
32187
32463
|
}
|
|
32188
32464
|
if (scanned >= LIMIT) warnings.push("Cursor discovery limited to 20,000 history files.");
|
|
@@ -32234,11 +32510,11 @@ function createCursorAdapter(options = {}) {
|
|
|
32234
32510
|
var cursorAdapter = createCursorAdapter();
|
|
32235
32511
|
|
|
32236
32512
|
// server/adapters/gemini.ts
|
|
32237
|
-
import { homedir as
|
|
32238
|
-
import { basename as basename5, dirname as dirname3, join as
|
|
32513
|
+
import { homedir as homedir8 } from "node:os";
|
|
32514
|
+
import { basename as basename5, dirname as dirname3, join as join14, sep as sep3 } from "node:path";
|
|
32239
32515
|
function projectRootFile(path) {
|
|
32240
32516
|
const parts = path.split(sep3);
|
|
32241
|
-
return
|
|
32517
|
+
return join14(parts.slice(0, parts.lastIndexOf("chats")).join(sep3), ".project_root");
|
|
32242
32518
|
}
|
|
32243
32519
|
function geminiConversation(contents, lines) {
|
|
32244
32520
|
const parsed = lines ? jsonLines(contents) : { rows: [object(json2(contents))], partial: false };
|
|
@@ -32286,7 +32562,7 @@ var geminiAdapter = localFileAdapter({
|
|
|
32286
32562
|
name: "Gemini CLI",
|
|
32287
32563
|
description: "Local JSON and JSONL chats, including recorded subagent histories",
|
|
32288
32564
|
capabilities: { history: true, forks: false, children: true, files: true },
|
|
32289
|
-
roots: () => process.env.SESSIONGRAPH_GEMINI_HOME ? [
|
|
32565
|
+
roots: () => process.env.SESSIONGRAPH_GEMINI_HOME ? [join14(process.env.SESSIONGRAPH_GEMINI_HOME, "tmp")] : [join14(process.env.GEMINI_CLI_HOME || homedir8(), ".gemini", "tmp"), join14(process.env.GEMINI_CLI_HOME || homedir8(), ".cache", ".gemini", "tmp")],
|
|
32290
32566
|
match: (path) => /^[^/]+\/chats\/(?:[^/]+\/)?[^/]+\.jsonl?$/.test(path),
|
|
32291
32567
|
extras: (path) => [projectRootFile(path)],
|
|
32292
32568
|
parse(path, files) {
|
|
@@ -32322,14 +32598,14 @@ var geminiAdapter = localFileAdapter({
|
|
|
32322
32598
|
});
|
|
32323
32599
|
|
|
32324
32600
|
// server/adapters/qwen.ts
|
|
32325
|
-
import { homedir as
|
|
32326
|
-
import { join as
|
|
32601
|
+
import { homedir as homedir9 } from "node:os";
|
|
32602
|
+
import { join as join15 } from "node:path";
|
|
32327
32603
|
var qwenAdapter = localFileAdapter({
|
|
32328
32604
|
id: "qwen-code",
|
|
32329
32605
|
name: "Qwen Code",
|
|
32330
32606
|
description: "Local project chat records \xB7 tool results, forks, and child sessions",
|
|
32331
32607
|
capabilities: { history: true, forks: true, children: true, files: true },
|
|
32332
|
-
roots: () => [
|
|
32608
|
+
roots: () => [join15(process.env.SESSIONGRAPH_QWEN_HOME || process.env.QWEN_RUNTIME_DIR || process.env.QWEN_HOME || join15(homedir9(), ".qwen"), "projects")],
|
|
32333
32609
|
match: (path) => /^[^/]+\/chats\/[^/]+\.jsonl$/.test(path),
|
|
32334
32610
|
parse(path, files) {
|
|
32335
32611
|
const { rows: rows2, partial } = jsonLines(files.get(path));
|
|
@@ -32366,14 +32642,14 @@ var qwenAdapter = localFileAdapter({
|
|
|
32366
32642
|
});
|
|
32367
32643
|
|
|
32368
32644
|
// server/adapters/copilot.ts
|
|
32369
|
-
import { homedir as
|
|
32370
|
-
import { join as
|
|
32645
|
+
import { homedir as homedir10 } from "node:os";
|
|
32646
|
+
import { join as join16 } from "node:path";
|
|
32371
32647
|
var copilotAdapter = localFileAdapter({
|
|
32372
32648
|
id: "copilot",
|
|
32373
32649
|
name: "GitHub Copilot CLI",
|
|
32374
32650
|
description: "Local session event logs \xB7 conversations and completed file edits",
|
|
32375
32651
|
capabilities: { history: true, forks: false, children: true, files: true },
|
|
32376
|
-
roots: () => [
|
|
32652
|
+
roots: () => [join16(process.env.SESSIONGRAPH_COPILOT_HOME || join16(homedir10(), ".copilot"), "session-state")],
|
|
32377
32653
|
match: (path) => /(?:^|\/)events\.jsonl$/.test(path),
|
|
32378
32654
|
parse(path, files) {
|
|
32379
32655
|
const { rows: rows2, partial } = jsonLines(files.get(path));
|
|
@@ -32420,15 +32696,15 @@ var copilotAdapter = localFileAdapter({
|
|
|
32420
32696
|
});
|
|
32421
32697
|
|
|
32422
32698
|
// server/adapters/extensions.ts
|
|
32423
|
-
import { homedir as
|
|
32424
|
-
import { basename as basename6, dirname as dirname4, join as
|
|
32699
|
+
import { homedir as homedir11 } from "node:os";
|
|
32700
|
+
import { basename as basename6, dirname as dirname4, join as join17 } from "node:path";
|
|
32425
32701
|
function editorTaskRoots(extension) {
|
|
32426
|
-
const home =
|
|
32427
|
-
const base = process.platform === "darwin" ?
|
|
32428
|
-
return ["Code", "Code - Insiders", "VSCodium", "Cursor", "Windsurf"].map((app) =>
|
|
32702
|
+
const home = homedir11();
|
|
32703
|
+
const base = process.platform === "darwin" ? join17(home, "Library", "Application Support") : process.platform === "win32" ? process.env.APPDATA || join17(home, "AppData", "Roaming") : process.env.XDG_CONFIG_HOME || join17(home, ".config");
|
|
32704
|
+
return ["Code", "Code - Insiders", "VSCodium", "Cursor", "Windsurf"].map((app) => join17(base, app, "User", "globalStorage", extension, "tasks")).concat([".vscode-server", ".vscode-server-insiders"].map((app) => join17(home, app, "data", "User", "globalStorage", extension, "tasks")));
|
|
32429
32705
|
}
|
|
32430
32706
|
function taskAdapter(id2, name, extension, env) {
|
|
32431
|
-
const roots = () => process.env[env] ? [
|
|
32707
|
+
const roots = () => process.env[env] ? [join17(process.env[env], "tasks"), ...id2 === "cline" ? [join17(process.env[env], "data", "sessions")] : []] : [...editorTaskRoots(extension), ...id2 === "cline" ? [process.env.CLINE_SESSION_DATA_DIR || join17(process.env.CLINE_DATA_DIR || join17(process.env.CLINE_DIR || join17(homedir11(), ".cline"), "data"), "sessions")] : []];
|
|
32432
32708
|
return localFileAdapter({
|
|
32433
32709
|
id: id2,
|
|
32434
32710
|
name,
|
|
@@ -32436,12 +32712,12 @@ function taskAdapter(id2, name, extension, env) {
|
|
|
32436
32712
|
capabilities: { history: true, forks: id2 === "cline", children: true, files: true },
|
|
32437
32713
|
roots,
|
|
32438
32714
|
match: (path) => /^[^/]+\/api_conversation_history\.json$/.test(path) || id2 === "cline" && /^[^/]+\/[^/]+\.messages\.json$/.test(path),
|
|
32439
|
-
extras: (path) => ["history_item.json", "task_metadata.json", "session.json"].map((file) =>
|
|
32715
|
+
extras: (path) => ["history_item.json", "task_metadata.json", "session.json"].map((file) => join17(dirname4(path), file)),
|
|
32440
32716
|
parse(path, files) {
|
|
32441
32717
|
const sdk = path.endsWith(".messages.json"), value = json2(files.get(path));
|
|
32442
32718
|
const records = sdk ? object(value).messages : value;
|
|
32443
32719
|
if (!Array.isArray(records) || sdk && !text(value.sessionId)) throw new Error("Unsupported task history.");
|
|
32444
|
-
const read3 = (name2) => object(files.has(
|
|
32720
|
+
const read3 = (name2) => object(files.has(join17(dirname4(path), name2)) ? json2(files.get(join17(dirname4(path), name2))) : void 0);
|
|
32445
32721
|
const history = read3("history_item.json"), info = read3("session.json"), task = read3("task_metadata.json");
|
|
32446
32722
|
const nativeID = sdk ? value.sessionId : basename6(dirname4(path));
|
|
32447
32723
|
if (history.id && history.id !== nativeID || info.session_id && info.session_id !== nativeID) throw new Error("Task metadata identity mismatch.");
|
|
@@ -32477,14 +32753,14 @@ var continueAdapter = localFileAdapter({
|
|
|
32477
32753
|
name: "Continue",
|
|
32478
32754
|
description: "Local IDE and CLI session JSON \xB7 recorded conversation and tool history",
|
|
32479
32755
|
capabilities: { history: true, forks: false, children: false, files: false },
|
|
32480
|
-
roots: () => [
|
|
32756
|
+
roots: () => [join17(process.env.SESSIONGRAPH_CONTINUE_HOME || process.env.CONTINUE_GLOBAL_DIR || join17(homedir11(), ".continue"), "sessions")],
|
|
32481
32757
|
match: (path) => /^[^/]+\.json$/.test(path) && path !== "sessions.json",
|
|
32482
|
-
extras: (path) => [
|
|
32758
|
+
extras: (path) => [join17(dirname4(path), "sessions.json")],
|
|
32483
32759
|
revisionExtras: false,
|
|
32484
32760
|
parse(path, files) {
|
|
32485
32761
|
const value = object(json2(files.get(path)));
|
|
32486
32762
|
if (!text(value.sessionId) || !Array.isArray(value.history)) throw new Error("Unsupported Continue session.");
|
|
32487
|
-
const indexPath =
|
|
32763
|
+
const indexPath = join17(dirname4(path), "sessions.json"), index = files.has(indexPath) ? json2(files.get(indexPath)) : [];
|
|
32488
32764
|
const meta = Array.isArray(index) ? object(index.find((r) => r.sessionId === value.sessionId)) : {};
|
|
32489
32765
|
const messages = value.history.map((item, i) => {
|
|
32490
32766
|
const row = object(item), raw = object(row.message), message2 = conversationMessage(raw, `record:${i}`);
|
|
@@ -32503,30 +32779,30 @@ var continueAdapter = localFileAdapter({
|
|
|
32503
32779
|
});
|
|
32504
32780
|
|
|
32505
32781
|
// server/adapters/harness-files.ts
|
|
32506
|
-
import { basename as basename8, dirname as dirname6, join as
|
|
32782
|
+
import { basename as basename8, dirname as dirname6, join as join20 } from "node:path";
|
|
32507
32783
|
|
|
32508
32784
|
// server/adapters/harness-paths.ts
|
|
32509
|
-
import { homedir as
|
|
32510
|
-
import { join as
|
|
32511
|
-
var homePath = (...parts) =>
|
|
32512
|
-
var dataPath = (...parts) =>
|
|
32513
|
-
var configPath = (...parts) =>
|
|
32514
|
-
var appPath = (...parts) =>
|
|
32515
|
-
var tokscalePath = (...parts) =>
|
|
32516
|
-
var envHome = (env, fallback, ...parts) =>
|
|
32785
|
+
import { homedir as homedir12 } from "node:os";
|
|
32786
|
+
import { join as join18 } from "node:path";
|
|
32787
|
+
var homePath = (...parts) => join18(homedir12(), ...parts);
|
|
32788
|
+
var dataPath = (...parts) => join18(process.env.XDG_DATA_HOME || homePath(".local/share"), ...parts);
|
|
32789
|
+
var configPath = (...parts) => join18(process.env.XDG_CONFIG_HOME || homePath(".config"), ...parts);
|
|
32790
|
+
var appPath = (...parts) => join18(process.platform === "darwin" ? homePath("Library/Application Support") : process.platform === "win32" ? process.env.APPDATA || homePath("AppData/Roaming") : process.env.XDG_CONFIG_HOME || homePath(".config"), ...parts);
|
|
32791
|
+
var tokscalePath = (...parts) => join18(process.env.TOKSCALE_CONFIG_DIR || (process.platform === "win32" ? appPath("tokscale") : configPath("tokscale")), ...parts);
|
|
32792
|
+
var envHome = (env, fallback, ...parts) => join18(process.env[env]?.trim() || homePath(fallback), ...parts);
|
|
32517
32793
|
var harnessRoots = (id2, defaults) => () => {
|
|
32518
32794
|
const override = process.env[`SESSIONGRAPH_${id2.replace(/-/g, "_").toUpperCase()}_HISTORY_DIR`]?.trim();
|
|
32519
32795
|
return override ? [override] : defaults();
|
|
32520
32796
|
};
|
|
32521
32797
|
|
|
32522
32798
|
// server/adapters/harness-extra-formats.ts
|
|
32523
|
-
import { basename as basename7, dirname as dirname5, join as
|
|
32799
|
+
import { basename as basename7, dirname as dirname5, join as join19 } from "node:path";
|
|
32524
32800
|
function kiroHistory(path, files) {
|
|
32525
32801
|
const header = object(json2(files.get(path)));
|
|
32526
32802
|
const ide2 = basename7(path) === "session.json";
|
|
32527
32803
|
const nativeID = text(header.session_id || header.sessionId || header.id) || (ide2 ? basename7(dirname5(path)) : "");
|
|
32528
32804
|
if (!nativeID) throw new Error("Unsupported Kiro session header.");
|
|
32529
|
-
const side = ide2 ?
|
|
32805
|
+
const side = ide2 ? join19(dirname5(path), "messages.jsonl") : path.replace(/\.json$/, ".jsonl");
|
|
32530
32806
|
if (!files.has(side)) throw new Error("Kiro conversation sidecar is unavailable.");
|
|
32531
32807
|
const { rows: rows2 } = jsonLines(files.get(side));
|
|
32532
32808
|
const messages = rows2.flatMap((r, i) => {
|
|
@@ -32552,7 +32828,7 @@ function kiroHistory(path, files) {
|
|
|
32552
32828
|
};
|
|
32553
32829
|
}
|
|
32554
32830
|
function muxHistory(path, files) {
|
|
32555
|
-
const archive = files.get(
|
|
32831
|
+
const archive = files.get(join19(dirname5(path), "chat-archive.jsonl"));
|
|
32556
32832
|
const records = [...archive ? jsonLines(archive).rows : [], ...jsonLines(files.get(path)).rows];
|
|
32557
32833
|
const unique = /* @__PURE__ */ new Map();
|
|
32558
32834
|
for (const r of records) {
|
|
@@ -32595,8 +32871,8 @@ var piSources = [
|
|
|
32595
32871
|
{ id: "prime-agent", name: "Prime Agent", roots: () => [process.env.PRIME_AGENT_SESSION_DIR || process.env.PRIME_AGENT_CODING_AGENT_SESSION_DIR || envHome("PRIME_AGENT_CODING_AGENT_DIR", ".prime/agent", "sessions"), envHome("PRIME_AGENT_CODING_AGENT_DIR", ".prime/agent", "session-artifacts")] },
|
|
32596
32872
|
{ id: "omp", name: "Oh My Pi", roots: () => [envHome("PI_CODING_AGENT_DIR_OMP", ".omp/agent", "sessions")] },
|
|
32597
32873
|
{ id: "senpi", name: "Senpi / OmO Native", roots: () => [envHome("SENPI_CODING_AGENT_DIR", ".senpi/agent", "sessions"), homePath(".omo/agent/sessions")] },
|
|
32598
|
-
{ id: "kimchi", name: "Kimchi", roots: () => [
|
|
32599
|
-
{ id: "gajae", name: "Gajae-Code", roots: () => [
|
|
32874
|
+
{ id: "kimchi", name: "Kimchi", roots: () => [join20(process.env.KIMCHI_CODING_AGENT_DIR || configPath("kimchi/harness"), "sessions")] },
|
|
32875
|
+
{ id: "gajae", name: "Gajae-Code", roots: () => [join20(process.env.GJC_CODING_AGENT_DIR || (process.env.GJC_CONFIG_DIR || process.env.PI_CONFIG_DIR ? join20(process.env.GJC_CONFIG_DIR || process.env.PI_CONFIG_DIR, "agent") : homePath(".gjc/agent")), "sessions"), dataPath("gjc/sessions")] }
|
|
32600
32876
|
].map((s) => ({ ...s, parse: piParse }));
|
|
32601
32877
|
var openclawRoots = () => [envHome("OPENCLAW_STATE_DIR", ".openclaw", "agents"), ...[".clawdbot", ".moltbot", ".moldbot"].map((p) => homePath(p, "agents"))];
|
|
32602
32878
|
var promaRoots = () => [".proma", ".proma-dev"].flatMap((p) => ["agent-sessions", "sdk-config/sessions", "sdk-config/projects"].map((s) => homePath(p, s)));
|
|
@@ -32604,7 +32880,7 @@ function kimiHistory(path, files) {
|
|
|
32604
32880
|
const { rows: rows2 } = jsonLines(files.get(path));
|
|
32605
32881
|
const folder = dirname6(path), id2 = basename8(folder), agent = basename8(dirname6(folder)) === "agents";
|
|
32606
32882
|
const nativeID = agent ? `${basename8(dirname6(dirname6(folder)))}/agent/${id2}` : id2;
|
|
32607
|
-
const wire =
|
|
32883
|
+
const wire = join20(folder, "wire.jsonl"), wireRows = files.has(wire) ? jsonLines(files.get(wire)).rows : [];
|
|
32608
32884
|
const messages = rows2.flatMap((r, i) => {
|
|
32609
32885
|
const m = message(r, nativeText(r.id) || `context:${i}`);
|
|
32610
32886
|
return m ? [m] : [];
|
|
@@ -32659,7 +32935,7 @@ function augmentHistory(path, files) {
|
|
|
32659
32935
|
return { nativeID: r.sessionId, messages, partial: true, session: { title: text(r.title), created: time(r.created), model: text(r.agentState?.modelId) || "Unknown model" }, note: "Augment saved exchange records. Typed response-node payloads and absent prompts are not reconstructed into conversations." };
|
|
32660
32936
|
}
|
|
32661
32937
|
function fxHistory(path, files) {
|
|
32662
|
-
const usage = object(json2(files.get(path))), meta = sidecar2(files,
|
|
32938
|
+
const usage = object(json2(files.get(path))), meta = sidecar2(files, join20(dirname6(path), "session.json"));
|
|
32663
32939
|
const id2 = text(usage.session_id) || text(meta.id);
|
|
32664
32940
|
if (!id2 || !usage.snapshot || meta.id && meta.id !== id2) throw new Error("Unsupported Fx session metadata.");
|
|
32665
32941
|
return {
|
|
@@ -32672,15 +32948,15 @@ function fxHistory(path, files) {
|
|
|
32672
32948
|
}
|
|
32673
32949
|
var definitions = [
|
|
32674
32950
|
...piSources,
|
|
32675
|
-
{ id: "kiro", name: "Kiro", roots: () => [homePath(".kiro/sessions"), appPath("Kiro/User/globalStorage/kiro.kiroagent")], match: (p) => p.endsWith("/session.json") || /^cli\/[^/]+\.json$/.test(p), extras: (p) => [basename8(p) === "session.json" ?
|
|
32676
|
-
{ id: "mux", name: "Mux", roots: () => [envHome("MUX_ROOT", ".mux", "sessions")], match: (p) => p.endsWith("/chat.jsonl"), extras: (p) => [
|
|
32951
|
+
{ id: "kiro", name: "Kiro", roots: () => [homePath(".kiro/sessions"), appPath("Kiro/User/globalStorage/kiro.kiroagent")], match: (p) => p.endsWith("/session.json") || /^cli\/[^/]+\.json$/.test(p), extras: (p) => [basename8(p) === "session.json" ? join20(dirname6(p), "messages.jsonl") : p.replace(/\.json$/, ".jsonl")], parse: kiroHistory },
|
|
32952
|
+
{ id: "mux", name: "Mux", roots: () => [envHome("MUX_ROOT", ".mux", "sessions")], match: (p) => p.endsWith("/chat.jsonl"), extras: (p) => [join20(dirname6(p), "chat-archive.jsonl")], parse: muxHistory },
|
|
32677
32953
|
{ id: "devin-desktop", name: "Devin Desktop", roots: () => [appPath("Devin/User/acp-events")], match: (p) => /\.(ndjson|jsonl)$/.test(p), parse: devinDesktopHistory },
|
|
32678
32954
|
{ id: "openclaw", name: "OpenClaw", roots: openclawRoots, match: (p) => /(?:^|\/)sessions\/.*\.jsonl(?:\.[\w.-]+)?$/.test(p) || /session-sqlite-import-archive\/.*\.jsonl\./.test(p), parse: piParse },
|
|
32679
32955
|
{ id: "amp", name: "Amp", roots: () => [dataPath("amp/threads"), tokscalePath("amp-cache/threads")], match: (p) => p.endsWith(".json"), parse: ampHistory },
|
|
32680
32956
|
{ id: "droid", name: "Factory Droid", roots: () => [envHome("FACTORY_HOME", ".factory", "sessions")] },
|
|
32681
32957
|
{ id: "codebuff", name: "Codebuff", roots: () => process.env.CODEBUFF_DATA_DIR ? [process.env.CODEBUFF_DATA_DIR] : ["manicode", "manicode-dev", "manicode-staging"].map((p) => configPath(p)), match: (p) => p.endsWith("/chat-messages.json"), parse: (p, f) => codebuffHistory(p, f, false) },
|
|
32682
32958
|
{ id: "freebuff", name: "Freebuff", roots: () => process.env.FREEBUFF_DATA_DIR ? [process.env.FREEBUFF_DATA_DIR] : process.env.CODEBUFF_DATA_DIR ? [process.env.CODEBUFF_DATA_DIR] : ["manicode", "manicode-dev", "manicode-staging"].map((p) => configPath(p)), match: (p) => p.endsWith("/chat-messages.json"), parse: (p, f) => codebuffHistory(p, f, true) },
|
|
32683
|
-
{ id: "kimi", name: "Kimi CLI / Code", roots: () => [envHome("KIMI_HOME", ".kimi", "sessions"), envHome("KIMI_CODE_HOME", ".kimi-code", "sessions")], match: (p) => p.endsWith("/context.jsonl"), extras: (p) => [
|
|
32959
|
+
{ id: "kimi", name: "Kimi CLI / Code", roots: () => [envHome("KIMI_HOME", ".kimi", "sessions"), envHome("KIMI_CODE_HOME", ".kimi-code", "sessions")], match: (p) => p.endsWith("/context.jsonl"), extras: (p) => [join20(dirname6(p), "wire.jsonl")], parse: kimiHistory },
|
|
32684
32960
|
{ id: "grok", name: "Grok Build", roots: () => [envHome("GROK_HOME", ".grok", "sessions")], match: (p) => p.endsWith("/updates.jsonl"), parse: (p, f) => acpHistory(p, f.get(p)) },
|
|
32685
32961
|
{ id: "jcode", name: "Jcode", roots: () => [envHome("JCODE_HOME", ".jcode", "sessions")], match: (p) => /(?:^|\/)session_[^/]+\.json$/.test(p), extras: (p) => [p.replace(/\.json$/, ".journal.jsonl")], parse: jcodeHistory },
|
|
32686
32962
|
{ id: "cherry-studio", name: "Cherry Studio", roots: () => [appPath("CherryStudio/Data/Agents/.claude/projects"), appPath("CherryStudio/.claude/projects")] },
|
|
@@ -32695,12 +32971,12 @@ var definitions = [
|
|
|
32695
32971
|
h3.nativeID = `${basename8(dirname6(dirname6(dirname6(p))))}/${basename8(dirname6(p))}`;
|
|
32696
32972
|
return h3;
|
|
32697
32973
|
} },
|
|
32698
|
-
{ id: "vibe", name: "Mistral Vibe", roots: () => [envHome("VIBE_HOME", ".vibe", "logs/session")], match: (p) => p.endsWith("/meta.json") || /^[^/]+\.json$/.test(p), extras: (p) => basename8(p) === "meta.json" ? [
|
|
32974
|
+
{ id: "vibe", name: "Mistral Vibe", roots: () => [envHome("VIBE_HOME", ".vibe", "logs/session")], match: (p) => p.endsWith("/meta.json") || /^[^/]+\.json$/.test(p), extras: (p) => basename8(p) === "meta.json" ? [join20(dirname6(p), "messages.jsonl")] : [], parse: vibeHistory },
|
|
32699
32975
|
{ id: "muse", name: "Muse Code", roots: () => [dataPath("muse/sessions")], match: (p) => p.endsWith("/session.jsonl"), parse: museHistory },
|
|
32700
32976
|
{ id: "junie", name: "Junie", roots: () => [homePath(".junie/sessions")], match: (p) => p.endsWith("/events.jsonl"), parse: junieHistory, description: "Local agent event history \xB7 partial conversation coverage" },
|
|
32701
32977
|
{ id: "augment", name: "Augment Code", roots: () => [homePath(".augment/sessions")], match: (p) => p.endsWith(".json"), parse: augmentHistory, description: "Local exchange records \xB7 partial conversation coverage" },
|
|
32702
|
-
{ id: "fx", name: "Fx", roots: () => [homePath(".fx/sessions")], match: (p) => p.endsWith("/usage-v2.json"), extras: (p) => [
|
|
32703
|
-
{ id: "minimax-code", name: "MiniMax Code", roots: () => [
|
|
32978
|
+
{ id: "fx", name: "Fx", roots: () => [homePath(".fx/sessions")], match: (p) => p.endsWith("/usage-v2.json"), extras: (p) => [join20(dirname6(p), "session.json")], parse: fxHistory, history: false, description: "Local native session metadata \xB7 conversation unavailable in usage snapshots" },
|
|
32979
|
+
{ id: "minimax-code", name: "MiniMax Code", roots: () => [join20(process.env.TOKSCALE_HEADLESS_DIR || tokscalePath("headless"), "mcode")], parse(p, f) {
|
|
32704
32980
|
const value = f.get(p), { rows: rows2 } = jsonLines(value), ids = new Set(rows2.map((r) => text(r.sessionId)).filter(Boolean));
|
|
32705
32981
|
if (ids.size !== 1) throw new Error("Headless capture needs one explicit session identity.");
|
|
32706
32982
|
const messages = rows2.flatMap((r, i) => {
|
|
@@ -32725,8 +33001,8 @@ var fileHarnessAdapters = definitions.map((source) => localFileAdapter({
|
|
|
32725
33001
|
}));
|
|
32726
33002
|
|
|
32727
33003
|
// server/adapters/harness-databases.ts
|
|
32728
|
-
import { lstat as
|
|
32729
|
-
import { isAbsolute as
|
|
33004
|
+
import { lstat as lstat6, readFile as readFile4 } from "node:fs/promises";
|
|
33005
|
+
import { isAbsolute as isAbsolute5, join as join21 } from "node:path";
|
|
32730
33006
|
var parsedContent = (v3) => typeof v3 === "string" && /^[\[{]/.test(v3.trim()) ? optionalJSON(v3) : v3;
|
|
32731
33007
|
var millisOrSeconds = (v3) => typeof v3 === "number" && v3 > 0 && v3 < 1e10 ? seconds(v3) : time(v3);
|
|
32732
33008
|
function dbPaths(id2, defaults, match) {
|
|
@@ -32766,7 +33042,7 @@ var hermes = {
|
|
|
32766
33042
|
var goose = {
|
|
32767
33043
|
id: "goose",
|
|
32768
33044
|
name: "Goose",
|
|
32769
|
-
paths: dbPaths("goose", () => process.env.GOOSE_PATH_ROOT &&
|
|
33045
|
+
paths: dbPaths("goose", () => process.env.GOOSE_PATH_ROOT && isAbsolute5(process.env.GOOSE_PATH_ROOT) ? [join21(process.env.GOOSE_PATH_ROOT, "data/sessions/sessions.db")] : [dataPath("goose/sessions/sessions.db"), dataPath("Block/goose/sessions/sessions.db"), appPath("goose/sessions/sessions.db"), appPath("Block/goose/sessions/sessions.db"), appPath("Block/goose/data/sessions/sessions.db")], (p) => p.endsWith("sessions.db")),
|
|
32770
33046
|
table: "sessions",
|
|
32771
33047
|
key: "id",
|
|
32772
33048
|
fields: ["id", "name", "description", "working_dir", "created_at", "updated_at", "model_config_json", "provider_name", "session_type", "parent_session_id", "archived_at"],
|
|
@@ -32829,7 +33105,7 @@ function forkStore(id2, name, defaultPath, desktop) {
|
|
|
32829
33105
|
var zed = {
|
|
32830
33106
|
id: "zed",
|
|
32831
33107
|
name: "Zed Agent",
|
|
32832
|
-
paths: dbPaths("zed", () => [process.platform === "darwin" ? appPath("Zed/threads/threads.db") : process.platform === "win32" ?
|
|
33108
|
+
paths: dbPaths("zed", () => [process.platform === "darwin" ? appPath("Zed/threads/threads.db") : process.platform === "win32" ? join21(process.env.LOCALAPPDATA || homePath("AppData/Local"), "Zed/threads/threads.db") : dataPath("zed/threads/threads.db")], (p) => p.endsWith("threads.db")),
|
|
32833
33109
|
table: "threads",
|
|
32834
33110
|
key: "id",
|
|
32835
33111
|
fields: ["id", "summary", "created_at", "updated_at", "data_type", "data", "folder_paths"],
|
|
@@ -32873,15 +33149,15 @@ var crush = {
|
|
|
32873
33149
|
paths: async () => {
|
|
32874
33150
|
const override = process.env.SESSIONGRAPH_CRUSH_HISTORY_DIR;
|
|
32875
33151
|
if (override) return (await historyFiles([override], (p) => p.endsWith("crush.db"))).files;
|
|
32876
|
-
const registry =
|
|
33152
|
+
const registry = join21(process.env.CRUSH_GLOBAL_DATA || dataPath("crush"), "projects.json");
|
|
32877
33153
|
try {
|
|
32878
|
-
const stat6 = await
|
|
33154
|
+
const stat6 = await lstat6(registry);
|
|
32879
33155
|
if (!stat6.isFile() || stat6.size > 2e6) throw new Error("Unsupported Crush registry.");
|
|
32880
33156
|
const raw = JSON.parse(await readFile4(registry, "utf8"));
|
|
32881
33157
|
const paths = [];
|
|
32882
33158
|
for (const p of Array.isArray(raw.projects) ? raw.projects.slice(0, 2e4) : []) {
|
|
32883
|
-
if (!
|
|
32884
|
-
const path =
|
|
33159
|
+
if (!isAbsolute5(text(p.path)) || !text(p.data_dir)) continue;
|
|
33160
|
+
const path = join21(isAbsolute5(p.data_dir) ? p.data_dir : join21(p.path, p.data_dir), "crush.db");
|
|
32885
33161
|
paths.push(path);
|
|
32886
33162
|
crushDirectories.set(path, p.path);
|
|
32887
33163
|
}
|
|
@@ -32987,7 +33263,7 @@ var databaseHarnessAdapters = [
|
|
|
32987
33263
|
// server/adapters/harness-metadata.ts
|
|
32988
33264
|
import { basename as basename9 } from "node:path";
|
|
32989
33265
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
32990
|
-
import { lstat as
|
|
33266
|
+
import { lstat as lstat7 } from "node:fs/promises";
|
|
32991
33267
|
function protoFields(value) {
|
|
32992
33268
|
if (value.length > 2e6) throw new Error("Trajectory metadata exceeds 2 MB.");
|
|
32993
33269
|
const fields2 = /* @__PURE__ */ new Map();
|
|
@@ -33073,7 +33349,7 @@ var usageOnlyAdapters = [
|
|
|
33073
33349
|
description: `Detection only \xB7 ${source.note}`,
|
|
33074
33350
|
capabilities: { history: false, forks: false, children: false, files: false },
|
|
33075
33351
|
async detect() {
|
|
33076
|
-
for (const p of harnessRoots(source.id, source.roots)()) if ((await
|
|
33352
|
+
for (const p of harnessRoots(source.id, source.roots)()) if ((await lstat7(p).catch(() => void 0))?.isDirectory()) return true;
|
|
33077
33353
|
return false;
|
|
33078
33354
|
},
|
|
33079
33355
|
async discover() {
|
|
@@ -33088,7 +33364,7 @@ var usageOnlyAdapters = [
|
|
|
33088
33364
|
var extra = [...databaseHarnessAdapters, ...fileHarnessAdapters, antigravityCacheAdapter, ...antigravityDatabaseAdapters, ...usageOnlyAdapters];
|
|
33089
33365
|
var grouped = /* @__PURE__ */ new Map();
|
|
33090
33366
|
for (const adapter of extra) grouped.set(adapter.id, [...grouped.get(adapter.id) || [], adapter]);
|
|
33091
|
-
var adapters = [opencodeAdapter, claudeAdapter, codexAdapter, cursorAdapter, geminiAdapter, qwenAdapter, piAdapter, copilotAdapter, clineAdapter, rooAdapter, kiloAdapter, continueAdapter, ...[...grouped.values()].map((parts) => parts.length === 1 ? parts[0] : combineAdapters(parts))];
|
|
33367
|
+
var adapters = [opencodeAdapter, claudeAdapter, codexAdapter, t3CodeAdapter, cursorAdapter, geminiAdapter, qwenAdapter, piAdapter, copilotAdapter, clineAdapter, rooAdapter, kiloAdapter, continueAdapter, ...[...grouped.values()].map((parts) => parts.length === 1 ? parts[0] : combineAdapters(parts))];
|
|
33092
33368
|
|
|
33093
33369
|
// server/store.ts
|
|
33094
33370
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
@@ -33156,9 +33432,9 @@ function eventSummary(row) {
|
|
|
33156
33432
|
return { id: String(row.id), kind: row.kind, role: row.role, name: String(row.name), time: row.time === null ? null : Number(row.time), timeSource: row.timeSource, ordinal: Number(row.ordinal), preview: String(row.preview), status: row.status, partial: Boolean(row.partial) };
|
|
33157
33433
|
}
|
|
33158
33434
|
var EventReadError = class extends Error {
|
|
33159
|
-
constructor(message2,
|
|
33435
|
+
constructor(message2, status2) {
|
|
33160
33436
|
super(message2);
|
|
33161
|
-
this.status =
|
|
33437
|
+
this.status = status2;
|
|
33162
33438
|
}
|
|
33163
33439
|
status;
|
|
33164
33440
|
};
|
|
@@ -33291,6 +33567,21 @@ function normalizeViewState(value) {
|
|
|
33291
33567
|
return result;
|
|
33292
33568
|
}
|
|
33293
33569
|
|
|
33570
|
+
// src/session-links.ts
|
|
33571
|
+
function visibleSessions(sessions) {
|
|
33572
|
+
const owners = /* @__PURE__ */ new Map();
|
|
33573
|
+
for (const session of sessions) {
|
|
33574
|
+
if (session.source !== "t3-code" || session.coverage?.history !== "complete" || !session.activity?.userMessages) continue;
|
|
33575
|
+
for (const id2 of session.linkedSessionIDs || []) owners.set(id2, [...owners.get(id2) || [], session.id]);
|
|
33576
|
+
}
|
|
33577
|
+
const unique = new Map([...owners].flatMap(([native, ids]) => ids.length === 1 ? [[native, ids[0]]] : []));
|
|
33578
|
+
return sessions.filter((session) => !unique.has(session.id)).map((session) => ({
|
|
33579
|
+
...session,
|
|
33580
|
+
parentID: session.parentID ? unique.get(session.parentID) || session.parentID : void 0,
|
|
33581
|
+
forkID: session.forkID ? unique.get(session.forkID) || session.forkID : void 0
|
|
33582
|
+
}));
|
|
33583
|
+
}
|
|
33584
|
+
|
|
33294
33585
|
// server/store.ts
|
|
33295
33586
|
var SessionGraphStore = class {
|
|
33296
33587
|
constructor(path = databasePath()) {
|
|
@@ -33454,7 +33745,7 @@ var SessionGraphStore = class {
|
|
|
33454
33745
|
importing,
|
|
33455
33746
|
preferences: this.setting("preferences") ? { ...normalizePreferences(this.setting("preferences")), autoImport: this.autoImportEnabled() } : void 0,
|
|
33456
33747
|
viewState: normalizeViewState(this.setting("viewState")),
|
|
33457
|
-
sessions: this.db.prepare("SELECT metadata FROM sessions").all().map((r) => JSON.parse(String(r.metadata))),
|
|
33748
|
+
sessions: visibleSessions(this.db.prepare("SELECT metadata FROM sessions").all().map((r) => JSON.parse(String(r.metadata)))),
|
|
33458
33749
|
projects: this.db.prepare("SELECT data FROM projects").all().map((r) => JSON.parse(String(r.data))),
|
|
33459
33750
|
loadedAt: Date.now(),
|
|
33460
33751
|
warnings: []
|
|
@@ -33741,7 +34032,7 @@ var Importer = class {
|
|
|
33741
34032
|
import { execFile, spawn as spawn2 } from "node:child_process";
|
|
33742
34033
|
import { promisify } from "node:util";
|
|
33743
34034
|
import { stat as stat4 } from "node:fs/promises";
|
|
33744
|
-
import { basename as basename10, dirname as dirname8, isAbsolute as
|
|
34035
|
+
import { basename as basename10, dirname as dirname8, isAbsolute as isAbsolute7 } from "node:path";
|
|
33745
34036
|
|
|
33746
34037
|
// src/launch-links.ts
|
|
33747
34038
|
var HARNESSES = [
|
|
@@ -33775,14 +34066,14 @@ function resumeArgs(value) {
|
|
|
33775
34066
|
// server/harnesses.ts
|
|
33776
34067
|
import { access, stat as stat3 } from "node:fs/promises";
|
|
33777
34068
|
import { constants as constants6 } from "node:fs";
|
|
33778
|
-
import { homedir as
|
|
33779
|
-
import { delimiter, isAbsolute as
|
|
34069
|
+
import { homedir as homedir13 } from "node:os";
|
|
34070
|
+
import { delimiter, isAbsolute as isAbsolute6, join as join22 } from "node:path";
|
|
33780
34071
|
async function executable(name) {
|
|
33781
|
-
const home =
|
|
33782
|
-
const directories = [...(process.env.PATH || "").split(delimiter),
|
|
33783
|
-
if (process.platform === "win32" && process.env.APPDATA) directories.push(
|
|
33784
|
-
if (process.platform === "win32" && process.env.SystemRoot) directories.push(
|
|
33785
|
-
const candidates =
|
|
34072
|
+
const home = homedir13();
|
|
34073
|
+
const directories = [...(process.env.PATH || "").split(delimiter), join22(home, ".local", "bin"), join22(home, ".opencode", "bin"), join22(home, ".bun", "bin"), join22(home, "Library", "pnpm"), "/opt/homebrew/bin", "/usr/local/bin"];
|
|
34074
|
+
if (process.platform === "win32" && process.env.APPDATA) directories.push(join22(process.env.APPDATA, "npm"));
|
|
34075
|
+
if (process.platform === "win32" && process.env.SystemRoot) directories.push(join22(process.env.SystemRoot, "System32", "WindowsPowerShell", "v1.0"));
|
|
34076
|
+
const candidates = isAbsolute6(name) ? [name] : directories.filter((dir) => isAbsolute6(dir)).flatMap((dir) => (process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""]).map((extension) => join22(dir, name + extension)));
|
|
33786
34077
|
for (const path of candidates) {
|
|
33787
34078
|
try {
|
|
33788
34079
|
if ((await stat3(path)).isFile()) {
|
|
@@ -33798,7 +34089,7 @@ async function harnessExecutable(target) {
|
|
|
33798
34089
|
const path = await executable(name);
|
|
33799
34090
|
if (path) return path;
|
|
33800
34091
|
if (target === "codex" && process.platform === "darwin") {
|
|
33801
|
-
return await executable("/Applications/Codex.app/Contents/Resources/codex") || await executable(
|
|
34092
|
+
return await executable("/Applications/Codex.app/Contents/Resources/codex") || await executable(join22(homedir13(), "Applications/Codex.app/Contents/Resources/codex"));
|
|
33802
34093
|
}
|
|
33803
34094
|
}
|
|
33804
34095
|
async function terminalExecutable() {
|
|
@@ -33823,7 +34114,7 @@ function launchCommand(binary, args, directory2, platform = process.platform) {
|
|
|
33823
34114
|
// server/handoff.ts
|
|
33824
34115
|
import { createHash as createHash4, randomUUID as randomUUID3 } from "node:crypto";
|
|
33825
34116
|
import { mkdir, writeFile as writeFile2, rename as rename2, rm as rm4 } from "node:fs/promises";
|
|
33826
|
-
import { join as
|
|
34117
|
+
import { join as join23 } from "node:path";
|
|
33827
34118
|
function handoffDocument(snapshot2) {
|
|
33828
34119
|
const { session, messages, firstUser, totalMessages } = snapshot2;
|
|
33829
34120
|
if (!messages.length) throw new Error("Import this session\u2019s conversation before continuing in another app.");
|
|
@@ -33837,14 +34128,14 @@ function handoffDocument(snapshot2) {
|
|
|
33837
34128
|
${text3.slice(-half)}`;
|
|
33838
34129
|
};
|
|
33839
34130
|
const block = (message2, limit) => {
|
|
33840
|
-
const
|
|
34131
|
+
const time3 = messageTime(message2.time) ? new Date(message2.time).toISOString() : "time unavailable";
|
|
33841
34132
|
const content = message2.fragments.map((f) => `[${f.kind}]
|
|
33842
34133
|
${clip(f.text, f.kind === "Tool" ? 2e3 : 12e3)}`).join("\n\n");
|
|
33843
34134
|
const files = message2.files.length ? `
|
|
33844
34135
|
|
|
33845
34136
|
Recorded file changes: ${message2.files.slice(0, 60).map((f) => JSON.stringify(f.path)).join(", ")}` : "";
|
|
33846
34137
|
shortened ||= message2.files.length > 60 || Boolean(message2.partial);
|
|
33847
|
-
return `## ${message2.role} \xB7 ${
|
|
34138
|
+
return `## ${message2.role} \xB7 ${time3}
|
|
33848
34139
|
|
|
33849
34140
|
${clip(content + files, limit)}
|
|
33850
34141
|
`;
|
|
@@ -33889,9 +34180,9 @@ This handoff transfers saved text and file-change evidence, not files, credentia
|
|
|
33889
34180
|
async function saveHandoff(snapshot2, directory2) {
|
|
33890
34181
|
const { text: text2, ...coverage2 } = handoffDocument(snapshot2);
|
|
33891
34182
|
const digest2 = createHash4("sha256").update(text2).digest("hex");
|
|
33892
|
-
const root3 =
|
|
34183
|
+
const root3 = join23(directory2, "handoffs");
|
|
33893
34184
|
await mkdir(root3, { recursive: true, mode: 448 });
|
|
33894
|
-
const path =
|
|
34185
|
+
const path = join23(root3, `${digest2}.md`), temporary = join23(root3, `.${randomUUID3()}.tmp`);
|
|
33895
34186
|
try {
|
|
33896
34187
|
await writeFile2(temporary, text2, { mode: 384, flag: "wx" });
|
|
33897
34188
|
await rename2(temporary, path);
|
|
@@ -33923,7 +34214,7 @@ async function getLaunchConnection(session) {
|
|
|
33923
34214
|
}
|
|
33924
34215
|
async function prepareLaunch(store, session, target, directory2 = session.directory) {
|
|
33925
34216
|
if (!isHarness(target)) throw new Error("Choose a supported destination app.");
|
|
33926
|
-
if (typeof directory2 !== "string" || !
|
|
34217
|
+
if (typeof directory2 !== "string" || !isAbsolute7(directory2) || /[\x00-\x1f\x7f]/.test(directory2)) throw new Error("Choose an absolute working directory.");
|
|
33927
34218
|
if (!(await stat4(directory2).catch(() => void 0))?.isDirectory()) throw new Error("Working directory is unavailable. Choose an existing directory.");
|
|
33928
34219
|
const [binary, terminal] = await Promise.all([harnessExecutable(target), terminalExecutable()]);
|
|
33929
34220
|
let args;
|
|
@@ -34009,9 +34300,9 @@ async function sessionGraphMiddleware(req, res, next) {
|
|
|
34009
34300
|
res.setHeader("Content-Type", "application/json");
|
|
34010
34301
|
res.setHeader("Cache-Control", "no-store");
|
|
34011
34302
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
34012
|
-
const json4 = (
|
|
34303
|
+
const json4 = (status2, value) => {
|
|
34013
34304
|
if (!res.writableEnded) {
|
|
34014
|
-
res.statusCode =
|
|
34305
|
+
res.statusCode = status2;
|
|
34015
34306
|
res.end(JSON.stringify(value));
|
|
34016
34307
|
}
|
|
34017
34308
|
};
|