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.
Files changed (59) hide show
  1. package/package.json +2 -2
  2. package/payload/SessionGraph.app/Contents/Info.plist +2 -2
  3. package/payload/SessionGraph.app/Contents/MacOS/sessiongraph +0 -0
  4. package/payload/SessionGraph.app/Contents/Resources/resources/server.mjs +425 -134
  5. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-ngj67_1P.js → index-3_I59bPI.js} +1 -1
  6. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-DZ3QjOks.js → index-86i6pjnx.js} +1 -1
  7. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-Ca1o8F2F.js → index-BEabiGl5.js} +16 -16
  8. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-DmhroAg3.js → index-DxQk-77k.js} +1 -1
  9. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-Oz3Ov7Mv.css → index-vX8x5oFC.css} +1 -1
  10. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{scene-DpPyjrii.js → scene-CEalI0mr.js} +1 -1
  11. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{share-BDMRLovI.js → share-BydK_UaB.js} +3 -3
  12. package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/worker-DwqxiDWY.js +2 -0
  13. package/payload/SessionGraph.app/Contents/Resources/resources/web/index.html +2 -2
  14. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/LICENSE-OFL-1.1.txt +93 -0
  15. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/NOTICE.txt +22 -0
  16. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/amp.svg +1 -0
  17. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/antigravity.svg +1 -0
  18. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/aside.svg +1 -0
  19. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/augment.svg +1 -0
  20. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/cherry.svg +1 -0
  21. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/codebuddy.svg +1 -0
  22. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/codebuff.svg +1 -0
  23. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/commandcode.svg +1 -0
  24. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/crush.svg +1 -0
  25. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/deepseek.svg +1 -0
  26. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/devin.svg +1 -0
  27. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/droid.svg +1 -0
  28. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/freebuff.svg +1 -0
  29. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/fx.svg +1 -0
  30. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/gajae.svg +1 -0
  31. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/goose.svg +1 -0
  32. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/grok.svg +1 -0
  33. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/hermes.svg +1 -0
  34. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/hindsight.svg +1 -0
  35. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/jcode.svg +1 -0
  36. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/junie.svg +1 -0
  37. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/kimchi.svg +1 -0
  38. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/kimi.svg +1 -0
  39. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/kiro.svg +1 -0
  40. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/lmstudio.svg +1 -0
  41. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/mimo.svg +1 -0
  42. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/minimax.svg +1 -0
  43. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/mistral.svg +1 -0
  44. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/muse.svg +1 -0
  45. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/mux.svg +1 -0
  46. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/octofriend.svg +1 -0
  47. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/openclaw.svg +1 -0
  48. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/prime.svg +1 -0
  49. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/proma.svg +1 -0
  50. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/reasonix.svg +1 -0
  51. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/senpi.svg +1 -0
  52. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/t3.svg +1 -0
  53. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/trae.svg +1 -0
  54. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/unsloth.svg +1 -0
  55. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/warp.svg +1 -0
  56. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/zcode.svg +1 -0
  57. package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/zed.svg +1 -0
  58. package/payload/SessionGraph.app/Contents/_CodeSignature/CodeResources +511 -38
  59. 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 time2 = Number(message2.time?.created) || 0;
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: time2 });
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, time2, role) => ({ id: id2, time: time2, role, fragments: [], files: [], tools: [] });
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 = (time2) => Number.isFinite(time2) && time2 > 0 && time2 <= 864e13 ? time2 : null;
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 time2 = messageTime(message2.time);
2932
- const event = { id: id2, kind, name, role: message2.role, time: time2, timeSource: time2 ? "message" : "unknown", text: eventText(text2, 64e3), ...fields2 };
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 time2 = messageTime(event.time || 0);
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: time2,
3013
- timeSource: time2 ? event.timeSource : "unknown",
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 status = ["pending", "running", "completed", "failed"].includes(raw.status) ? raw.status : "unknown";
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 time2 = messageTime(part.time?.created);
3035
- const timing = time2 ? { time: time2, timeSource: "recorded" } : {};
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 status = state2.status === "error" ? "failed" : state2.status === "streaming" ? "pending" : ["running", "completed"].includes(state2.status) ? state2.status : "unknown";
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 time2 = typeof row.timestamp === "string" ? Date.parse(row.timestamp) : NaN;
30453
- times.set(row.uuid, Number.isFinite(time2) && time2 > 0 ? time2 : 0);
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((time2) => time2 && time2 > 0);
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 lstat4, opendir, readFile as readFile3 } from "node:fs/promises";
31626
- import { homedir as homedir6 } from "node:os";
31627
- import { isAbsolute as isAbsolute3, join as join12 } from "node:path";
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 time2 = typeof value === "number" ? value : typeof value === "string" && /(?:Z|[+-]\d\d:\d\d)$/.test(value) ? Date.parse(value) : 0;
31633
- return Number.isFinite(time2) && time2 > 0 && time2 <= 864e13 ? time2 : 0;
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 time2 = cursorTime(raw.timestamp) || cursorTime(body2.timestamp) || cursorTime(body2.createdAt) || (role === "user" && typeof firstText === "string" ? cursorEnvelopeTime(firstText) : 0);
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, time2, role);
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 join11 } from "node:path";
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(join11(tmpdir2(), "sessiongraph-cursor-"));
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 = join11(directory2, "store.db");
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 isAbsolute2 } from "node:path";
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) : isAbsolute2(value) ? 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" && isAbsolute3(value) && !/[\x00-\x1f\x7f]/.test(value) ? value : "";
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" ? join12(homedir6(), "Library/Application Support/Cursor") : process.platform === "win32" ? join12(process.env.APPDATA || join12(homedir6(), "AppData/Roaming"), "Cursor") : join12(process.env.XDG_CONFIG_HOME || join12(homedir6(), ".config"), "Cursor");
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 lstat4(path);
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 lstat4(path)).isDirectory()) return result;
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 = join12(root3, "User/workspaceStorage");
32297
+ const storage = join13(root3, "User/workspaceStorage");
32022
32298
  for (const entry of await entries(storage, warnings)) if (entry.isDirectory()) {
32023
- const database = join12(storage, entry.name, "state.vscdb");
32299
+ const database = join13(storage, entry.name, "state.vscdb");
32024
32300
  stores.set(database, "");
32025
32301
  try {
32026
- const info = await json3(join12(storage, entry.name, "workspace.json"));
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 || join12(homedir6(), ".cursor");
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(join12(editor(), "User/globalStorage/state.vscdb"))) return true;
32047
- for (const entry of await entries(join12(editor(), "User/workspaceStorage"), [])) {
32048
- if (entry.isDirectory() && await fileStats(join12(editor(), "User/workspaceStorage", entry.name, "state.vscdb"))) return true;
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 lstat4(join12(root3(), name))).isDirectory()) return true;
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([[join12(editor(), "User/globalStorage/state.vscdb"), ""], ...workspaceStores]);
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 = join12(path, "..", "meta.json");
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() === join12(homedir6(), ".cursor");
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 = join12(root3(), "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 = join12(projects, dir.name, "agent-transcripts"), directory2 = match(dir.name, slug);
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(join12(transcripts, entry.name), entry.name.slice(0, -6), "transcript", directory2);
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(join12(transcripts, entry.name, `${entry.name}.jsonl`), entry.name, "transcript", directory2);
32163
- for (const child of await entries(join12(transcripts, entry.name, "subagents"), warnings)) {
32164
- if (child.isFile() && child.name.endsWith(".jsonl")) await add(join12(transcripts, entry.name, "subagents", child.name), child.name.slice(0, -6), "transcript", directory2, entry.name);
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 = join12(root3(), "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 = join12(chats, bucket.name), directory2 = match(bucket.name, hashCwd);
32174
- if (/^[a-f\d]{32}$/i.test(bucket.name) && await fileStats(join12(folder, "store.db"))) {
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(join12(folder, "store.db"), id2, "cli", "");
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(join12(folder, entry.name, "store.db"), entry.name, "cli", directory2, "", bucket.name);
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 = join12(root3(), "acp-sessions");
32459
+ const acp = join13(root3(), "acp-sessions");
32184
32460
  for (const entry of await entries(acp, warnings)) {
32185
- if (entry.isDirectory()) await add(join12(acp, entry.name, "store.db"), entry.name, "acp", "");
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 homedir7 } from "node:os";
32238
- import { basename as basename5, dirname as dirname3, join as join13, sep as sep3 } from "node:path";
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 join13(parts.slice(0, parts.lastIndexOf("chats")).join(sep3), ".project_root");
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 ? [join13(process.env.SESSIONGRAPH_GEMINI_HOME, "tmp")] : [join13(process.env.GEMINI_CLI_HOME || homedir7(), ".gemini", "tmp"), join13(process.env.GEMINI_CLI_HOME || homedir7(), ".cache", ".gemini", "tmp")],
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 homedir8 } from "node:os";
32326
- import { join as join14 } from "node:path";
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: () => [join14(process.env.SESSIONGRAPH_QWEN_HOME || process.env.QWEN_RUNTIME_DIR || process.env.QWEN_HOME || join14(homedir8(), ".qwen"), "projects")],
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 homedir9 } from "node:os";
32370
- import { join as join15 } from "node:path";
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: () => [join15(process.env.SESSIONGRAPH_COPILOT_HOME || join15(homedir9(), ".copilot"), "session-state")],
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 homedir10 } from "node:os";
32424
- import { basename as basename6, dirname as dirname4, join as join16 } from "node:path";
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 = homedir10();
32427
- const base = process.platform === "darwin" ? join16(home, "Library", "Application Support") : process.platform === "win32" ? process.env.APPDATA || join16(home, "AppData", "Roaming") : process.env.XDG_CONFIG_HOME || join16(home, ".config");
32428
- return ["Code", "Code - Insiders", "VSCodium", "Cursor", "Windsurf"].map((app) => join16(base, app, "User", "globalStorage", extension, "tasks")).concat([".vscode-server", ".vscode-server-insiders"].map((app) => join16(home, app, "data", "User", "globalStorage", extension, "tasks")));
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] ? [join16(process.env[env], "tasks"), ...id2 === "cline" ? [join16(process.env[env], "data", "sessions")] : []] : [...editorTaskRoots(extension), ...id2 === "cline" ? [process.env.CLINE_SESSION_DATA_DIR || join16(process.env.CLINE_DATA_DIR || join16(process.env.CLINE_DIR || join16(homedir10(), ".cline"), "data"), "sessions")] : []];
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) => join16(dirname4(path), 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(join16(dirname4(path), name2)) ? json2(files.get(join16(dirname4(path), name2))) : void 0);
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: () => [join16(process.env.SESSIONGRAPH_CONTINUE_HOME || process.env.CONTINUE_GLOBAL_DIR || join16(homedir10(), ".continue"), "sessions")],
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) => [join16(dirname4(path), "sessions.json")],
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 = join16(dirname4(path), "sessions.json"), index = files.has(indexPath) ? json2(files.get(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 join19 } from "node:path";
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 homedir11 } from "node:os";
32510
- import { join as join17 } from "node:path";
32511
- var homePath = (...parts) => join17(homedir11(), ...parts);
32512
- var dataPath = (...parts) => join17(process.env.XDG_DATA_HOME || homePath(".local/share"), ...parts);
32513
- var configPath = (...parts) => join17(process.env.XDG_CONFIG_HOME || homePath(".config"), ...parts);
32514
- var appPath = (...parts) => join17(process.platform === "darwin" ? homePath("Library/Application Support") : process.platform === "win32" ? process.env.APPDATA || homePath("AppData/Roaming") : process.env.XDG_CONFIG_HOME || homePath(".config"), ...parts);
32515
- var tokscalePath = (...parts) => join17(process.env.TOKSCALE_CONFIG_DIR || (process.platform === "win32" ? appPath("tokscale") : configPath("tokscale")), ...parts);
32516
- var envHome = (env, fallback, ...parts) => join17(process.env[env]?.trim() || homePath(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 join18 } from "node:path";
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 ? join18(dirname5(path), "messages.jsonl") : path.replace(/\.json$/, ".jsonl");
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(join18(dirname5(path), "chat-archive.jsonl"));
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: () => [join19(process.env.KIMCHI_CODING_AGENT_DIR || configPath("kimchi/harness"), "sessions")] },
32599
- { id: "gajae", name: "Gajae-Code", roots: () => [join19(process.env.GJC_CODING_AGENT_DIR || (process.env.GJC_CONFIG_DIR || process.env.PI_CONFIG_DIR ? join19(process.env.GJC_CONFIG_DIR || process.env.PI_CONFIG_DIR, "agent") : homePath(".gjc/agent")), "sessions"), dataPath("gjc/sessions")] }
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 = join19(folder, "wire.jsonl"), wireRows = files.has(wire) ? jsonLines(files.get(wire)).rows : [];
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, join19(dirname6(path), "session.json"));
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" ? join19(dirname6(p), "messages.jsonl") : p.replace(/\.json$/, ".jsonl")], parse: kiroHistory },
32676
- { id: "mux", name: "Mux", roots: () => [envHome("MUX_ROOT", ".mux", "sessions")], match: (p) => p.endsWith("/chat.jsonl"), extras: (p) => [join19(dirname6(p), "chat-archive.jsonl")], parse: muxHistory },
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) => [join19(dirname6(p), "wire.jsonl")], parse: kimiHistory },
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" ? [join19(dirname6(p), "messages.jsonl")] : [], parse: vibeHistory },
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) => [join19(dirname6(p), "session.json")], parse: fxHistory, history: false, description: "Local native session metadata \xB7 conversation unavailable in usage snapshots" },
32703
- { id: "minimax-code", name: "MiniMax Code", roots: () => [join19(process.env.TOKSCALE_HEADLESS_DIR || tokscalePath("headless"), "mcode")], parse(p, f) {
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 lstat5, readFile as readFile4 } from "node:fs/promises";
32729
- import { isAbsolute as isAbsolute4, join as join20 } from "node:path";
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 && isAbsolute4(process.env.GOOSE_PATH_ROOT) ? [join20(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")),
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" ? join20(process.env.LOCALAPPDATA || homePath("AppData/Local"), "Zed/threads/threads.db") : dataPath("zed/threads/threads.db")], (p) => p.endsWith("threads.db")),
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 = join20(process.env.CRUSH_GLOBAL_DATA || dataPath("crush"), "projects.json");
33152
+ const registry = join21(process.env.CRUSH_GLOBAL_DATA || dataPath("crush"), "projects.json");
32877
33153
  try {
32878
- const stat6 = await lstat5(registry);
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 (!isAbsolute4(text(p.path)) || !text(p.data_dir)) continue;
32884
- const path = join20(isAbsolute4(p.data_dir) ? p.data_dir : join20(p.path, p.data_dir), "crush.db");
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 lstat6 } from "node:fs/promises";
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 lstat6(p).catch(() => void 0))?.isDirectory()) return true;
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, status) {
33435
+ constructor(message2, status2) {
33160
33436
  super(message2);
33161
- this.status = 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 isAbsolute6 } from "node:path";
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 homedir12 } from "node:os";
33779
- import { delimiter, isAbsolute as isAbsolute5, join as join21 } from "node:path";
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 = homedir12();
33782
- const directories = [...(process.env.PATH || "").split(delimiter), join21(home, ".local", "bin"), join21(home, ".opencode", "bin"), join21(home, ".bun", "bin"), join21(home, "Library", "pnpm"), "/opt/homebrew/bin", "/usr/local/bin"];
33783
- if (process.platform === "win32" && process.env.APPDATA) directories.push(join21(process.env.APPDATA, "npm"));
33784
- if (process.platform === "win32" && process.env.SystemRoot) directories.push(join21(process.env.SystemRoot, "System32", "WindowsPowerShell", "v1.0"));
33785
- const candidates = isAbsolute5(name) ? [name] : directories.filter((dir) => isAbsolute5(dir)).flatMap((dir) => (process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""]).map((extension) => join21(dir, name + extension)));
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(join21(homedir12(), "Applications/Codex.app/Contents/Resources/codex"));
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 join22 } from "node:path";
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 time2 = messageTime(message2.time) ? new Date(message2.time).toISOString() : "time unavailable";
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 ${time2}
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 = join22(directory2, "handoffs");
34183
+ const root3 = join23(directory2, "handoffs");
33893
34184
  await mkdir(root3, { recursive: true, mode: 448 });
33894
- const path = join22(root3, `${digest2}.md`), temporary = join22(root3, `.${randomUUID3()}.tmp`);
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" || !isAbsolute6(directory2) || /[\x00-\x1f\x7f]/.test(directory2)) throw new Error("Choose an absolute working directory.");
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 = (status, value) => {
34303
+ const json4 = (status2, value) => {
34013
34304
  if (!res.writableEnded) {
34014
- res.statusCode = status;
34305
+ res.statusCode = status2;
34015
34306
  res.end(JSON.stringify(value));
34016
34307
  }
34017
34308
  };