offsite 0.0.35 → 0.0.37

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 (157) hide show
  1. package/apps/server/dist/main.mjs +180 -57
  2. package/apps/server/dist/main.mjs.map +1 -1
  3. package/apps/server/drizzle/20261021070005_project_positions/migration.sql +3 -0
  4. package/apps/server/drizzle/20261021070005_project_positions/snapshot.json +315 -0
  5. package/apps/web/dist/apple-touch-icon.png +0 -0
  6. package/apps/web/dist/assets/abnfDiagram-WEYOIA3C-CNZkoxwt.js +1 -0
  7. package/apps/web/dist/assets/arc-DgcGdgmL.js +1 -0
  8. package/apps/web/dist/assets/architecture-WOLXFQ4H-O--ui1FL.js +1 -0
  9. package/apps/web/dist/assets/architectureDiagram-ZHVYKT53-Bt5qygpd.js +36 -0
  10. package/apps/web/dist/assets/array-BifhSqXX.js +1 -0
  11. package/apps/web/dist/assets/{audio-player-DPpDuqFI.js → audio-player-BBuXiV2_.js} +1 -1
  12. package/apps/web/dist/assets/blockDiagram-RJAE7QA3-BDcALlM7.js +140 -0
  13. package/apps/web/dist/assets/button-BF3wjXXJ.js +1 -0
  14. package/apps/web/dist/assets/c4Diagram-XDPPPE54-DltmZnfl.js +38 -0
  15. package/apps/web/dist/assets/channel-BiaErSWu.js +1 -0
  16. package/apps/web/dist/assets/chunk-24IY7LWP-BnbC-kCW.js +1 -0
  17. package/apps/web/dist/assets/chunk-2E7WHVMD-DI9Z3LRJ.js +88 -0
  18. package/apps/web/dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  19. package/apps/web/dist/assets/chunk-3M4EKCLJ-DOMgvaXT.js +1 -0
  20. package/apps/web/dist/assets/chunk-4EMNKR2T-Bmu5iPEB.js +1 -0
  21. package/apps/web/dist/assets/chunk-4S7OKTRW-Bg7nzAWG.js +1 -0
  22. package/apps/web/dist/assets/chunk-53FOQ5SW-f76P46nL.js +1 -0
  23. package/apps/web/dist/assets/chunk-55XCU76K-DsrsQaHP.js +1 -0
  24. package/apps/web/dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  25. package/apps/web/dist/assets/chunk-7S6XSTFO-VvdR34BD.js +2 -0
  26. package/apps/web/dist/assets/chunk-AQDTSKZB-DWCLLcEu.js +72 -0
  27. package/apps/web/dist/assets/chunk-BP2KR52E-CwyHPMMJ.js +2 -0
  28. package/apps/web/dist/assets/chunk-DSNLSHJZ-Npz5XPWZ.js +129 -0
  29. package/apps/web/dist/assets/chunk-DUW6YSOI-Dgx8z5s3.js +1 -0
  30. package/apps/web/dist/assets/chunk-EJLWFMJV-DyjKClu9.js +2 -0
  31. package/apps/web/dist/assets/chunk-F6S3BTY2-CZGFqKcE.js +2 -0
  32. package/apps/web/dist/assets/chunk-HAGFOTED-B1IVU9Z4.js +62 -0
  33. package/apps/web/dist/assets/chunk-HNE4Q36P-ByoLUQMm.js +1 -0
  34. package/apps/web/dist/assets/chunk-J5ZVWO5B-oDCd-gWO.js +1 -0
  35. package/apps/web/dist/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  36. package/apps/web/dist/assets/chunk-KPI5JJXK-CYaUTtMz.js +1 -0
  37. package/apps/web/dist/assets/chunk-LNGE3PJU-Cz3NAIRA.js +34 -0
  38. package/apps/web/dist/assets/chunk-NGNAAXSQ-C2Wy9Xmz.js +136 -0
  39. package/apps/web/dist/assets/chunk-NQOKRVIF-B4RCKBlg.js +213 -0
  40. package/apps/web/dist/assets/chunk-OD3NTWWA-tWtUB_cI.js +1 -0
  41. package/apps/web/dist/assets/chunk-OYAV6JZA-rT8O_-D6.js +1 -0
  42. package/apps/web/dist/assets/chunk-QNH66VMT-BbxTKInC.js +1 -0
  43. package/apps/web/dist/assets/chunk-TPMEZKFX-mvOucSjo.js +1 -0
  44. package/apps/web/dist/assets/chunk-UHW7PFBP-Cu9Ayl_R.js +1 -0
  45. package/apps/web/dist/assets/chunk-VPELOWWC-Dw8jWE1Y.js +1 -0
  46. package/apps/web/dist/assets/chunk-VQ5W62QI-yc2D7bI8.js +1 -0
  47. package/apps/web/dist/assets/chunk-VTWWFHGB-CErZyUMc.js +1 -0
  48. package/apps/web/dist/assets/chunk-VZTHESGH-BsQ8KQ39.js +1 -0
  49. package/apps/web/dist/assets/chunk-WQQL4CDK-BAxY1EoE.js +10 -0
  50. package/apps/web/dist/assets/chunk-XXDRQBXY-RlzOQ08v.js +1 -0
  51. package/apps/web/dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  52. package/apps/web/dist/assets/chunk-YK26KJH5-CFTvfUrJ.js +1 -0
  53. package/apps/web/dist/assets/chunk-YZO67HFG-B_UXK566.js +1 -0
  54. package/apps/web/dist/assets/chunk-ZAUX2LTX-BaD-GxqC.js +1 -0
  55. package/apps/web/dist/assets/chunk-ZCHMQSOR-BoFxnrLn.js +2 -0
  56. package/apps/web/dist/assets/chunk-ZO67DCNQ-DQMJSBMv.js +2 -0
  57. package/apps/web/dist/assets/classDiagram-v2-4MYWR3UA-CrgsmZ1r.js +217 -0
  58. package/apps/web/dist/assets/cose-bilkent-JH36ORCC-Ci-t6eKT.js +1 -0
  59. package/apps/web/dist/assets/cynefin-EF2NZ3EQ-B22Il0Q0.js +1 -0
  60. package/apps/web/dist/assets/cynefinDiagram-WF24UDRP-Boik6NMW.js +62 -0
  61. package/apps/web/dist/assets/cytoscape.esm-BegBNzOV.js +321 -0
  62. package/apps/web/dist/assets/dagre-NK4GIZVX-BSfLeunL.js +4 -0
  63. package/apps/web/dist/assets/defaultLocale-BFoDCU3G.js +1 -0
  64. package/apps/web/dist/assets/diagram-CBK3MWTC-BHJqlY6f.js +24 -0
  65. package/apps/web/dist/assets/diagram-I5XIIV2D-B_jxetms.js +24 -0
  66. package/apps/web/dist/assets/diagram-ODIL2UCW-DfqD5uqI.js +30 -0
  67. package/apps/web/dist/assets/diagram-PFBEJUXE-1aq8qGYY.js +3 -0
  68. package/apps/web/dist/assets/diagram-RJA3I4VV-KG9CFGTL.js +41 -0
  69. package/apps/web/dist/assets/diagram-TYUNFSNR-Do2jo9yU.js +200 -0
  70. package/apps/web/dist/assets/dist-B_J_HbC0.js +1 -0
  71. package/apps/web/dist/assets/dist-CkDQKgh1.js +153 -0
  72. package/apps/web/dist/assets/dist-CwYFZY7g.js +1 -0
  73. package/apps/web/dist/assets/ebnfDiagram-V4P3TTPT-D2ts5XpU.js +1 -0
  74. package/apps/web/dist/assets/elk-QONTBCTQ-B_GGAzMO.js +27 -0
  75. package/apps/web/dist/assets/erDiagram-KYQIGQAA-2dqvdzye.js +99 -0
  76. package/apps/web/dist/assets/eventmodeling-K75KTNOO-CXHQFMgp.js +1 -0
  77. package/apps/web/dist/assets/flowDiagram-IUGLLWBU-CtZHqT3f.js +1 -0
  78. package/apps/web/dist/assets/ganttDiagram-R7GPNTJY-BqiF1UBm.js +292 -0
  79. package/apps/web/dist/assets/gitGraph-VSP46ZUC-TdWHDRg-.js +1 -0
  80. package/apps/web/dist/assets/gitGraphDiagram-PDYL7XHY-CmG5ZO6p.js +106 -0
  81. package/apps/web/dist/assets/graphlib-DS17s2tU.js +1 -0
  82. package/apps/web/dist/assets/image-viewer-4LhMaTO_.js +1 -0
  83. package/apps/web/dist/assets/index-NMfUawX9.css +2 -0
  84. package/apps/web/dist/assets/index-yfoAg16U.js +782 -0
  85. package/apps/web/dist/assets/info-OHQRW6UA-vNA4W1BY.js +1 -0
  86. package/apps/web/dist/assets/infoDiagram-MVDRKAX5-BKX9UC-k.js +2 -0
  87. package/apps/web/dist/assets/init-C-OQMol4.js +1 -0
  88. package/apps/web/dist/assets/ishikawaDiagram-HPEHV2GE-B4qnWXRg.js +70 -0
  89. package/apps/web/dist/assets/journeyDiagram-BOSHW7O7-BiKpcTEm.js +139 -0
  90. package/apps/web/dist/assets/jsx-runtime-DKj5X9O4.js +1 -0
  91. package/apps/web/dist/assets/kanban-definition-FNSA4HC5-D0QGHPZw.js +89 -0
  92. package/apps/web/dist/assets/katex-B_JcIwqj.js +257 -0
  93. package/apps/web/dist/assets/line-QLqjjjjp.js +1 -0
  94. package/apps/web/dist/assets/linear-DzP0d4la.js +1 -0
  95. package/apps/web/dist/assets/mermaid-parser.core-BHOBNwvf.js +4 -0
  96. package/apps/web/dist/assets/mermaid.core-BvdElKsv.js +11 -0
  97. package/apps/web/dist/assets/mindmap-definition-6OY57UG3-BXYDkcmu.js +98 -0
  98. package/apps/web/dist/assets/ordinal-BDEzSJ7C.js +1 -0
  99. package/apps/web/dist/assets/packet-JDAUHWVQ-B8hYuedA.js +1 -0
  100. package/apps/web/dist/assets/path-fybaL0A-.js +1 -0
  101. package/apps/web/dist/assets/pegDiagram-ECIUJNBX-CKUDNsQa.js +1 -0
  102. package/apps/web/dist/assets/pie-XZMESJXO-Dot5dfKq.js +1 -0
  103. package/apps/web/dist/assets/pieDiagram-GNMPY74T-CYBpcOWI.js +39 -0
  104. package/apps/web/dist/assets/preload-helper-BLdHbfdN.js +1 -0
  105. package/apps/web/dist/assets/{preview-dialog-CPvYDNeU.js → preview-dialog-jk_R2034.js} +1 -1
  106. package/apps/web/dist/assets/quadrantDiagram-D57K4MC3-Ce4rstAB.js +7 -0
  107. package/apps/web/dist/assets/radar-ABXABTNO-B-JNDxsg.js +1 -0
  108. package/apps/web/dist/assets/railroad-I3PHUGI6-CZyDVcgN.js +1 -0
  109. package/apps/web/dist/assets/railroad-abnf-LNEFI6M7-Vj_R5cg2.js +1 -0
  110. package/apps/web/dist/assets/railroad-ebnf-DWYD2UWJ-CUdwkvqU.js +1 -0
  111. package/apps/web/dist/assets/railroad-peg-JR7BVNR7-Cx8B3Fw_.js +1 -0
  112. package/apps/web/dist/assets/railroadDiagram-Y72NRBL7-DJFwL-gy.js +1 -0
  113. package/apps/web/dist/assets/{react-BlUBLzv4.js → react-99wk3OSj.js} +1 -1
  114. package/apps/web/dist/assets/requirementDiagram-EQYSW5RA-BRGd7bW2.js +84 -0
  115. package/apps/web/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  116. package/apps/web/dist/assets/rough.esm-Dy-Kn_BL.js +1 -0
  117. package/apps/web/dist/assets/sankeyDiagram-SY24JHO5-K6n9GTvI.js +40 -0
  118. package/apps/web/dist/assets/sequenceDiagram-BLEHNHQU-C5fTKXFr.js +169 -0
  119. package/apps/web/dist/assets/sizeCapture-INFHLROL-3uHXrFqA.js +1 -0
  120. package/apps/web/dist/assets/src-BbHDS76q.js +1 -0
  121. package/apps/web/dist/assets/stateDiagram-v2-A6IESKWZ-DmuliVkN.js +291 -0
  122. package/apps/web/dist/assets/swimlanes-B3ENRKFQ-C6184yrk.js +1 -0
  123. package/apps/web/dist/assets/swimlanesDiagram-AYQRV4AK-C7v5ZG8a.js +8 -0
  124. package/apps/web/dist/assets/tags-DrTyXsO5.js +1 -0
  125. package/apps/web/dist/assets/timeline-definition-JXYKGLGB-9zgkFWSz.js +120 -0
  126. package/apps/web/dist/assets/tooltip-CiWlkHa6.js +1 -0
  127. package/apps/web/dist/assets/treeView-D4JQ5SDB-C4nFWZ36.js +1 -0
  128. package/apps/web/dist/assets/treemap-SAJKECNS-BtKhU7nu.js +1 -0
  129. package/apps/web/dist/assets/usecaseDiagram-WPOLBNNX-GhuLCvVh.js +328 -0
  130. package/apps/web/dist/assets/vennDiagram-Q3Y3IDCW-CkqSz3Ut.js +34 -0
  131. package/apps/web/dist/assets/{video-player-DsF9gAr6.js → video-player-Bcow2OC5.js} +1 -1
  132. package/apps/web/dist/assets/video-player-hDoAwJRk.js +1 -0
  133. package/apps/web/dist/assets/video-viewer-CJ129jI3.js +1 -0
  134. package/apps/web/dist/assets/wardley-7MLQ67FV-zgQ1s-nD.js +1 -0
  135. package/apps/web/dist/assets/wardleyDiagram-IVAIDKWA-CQSNfHYl.js +78 -0
  136. package/apps/web/dist/assets/xychartDiagram-4URNHDU4-oZoMdVOh.js +7 -0
  137. package/apps/web/dist/assets/zoomable-image-CZlWBm_z.js +41 -0
  138. package/apps/web/dist/assets/zoomable-image-DyuZJmov.js +1 -0
  139. package/apps/web/dist/icon-192.png +0 -0
  140. package/apps/web/dist/icon-512.png +0 -0
  141. package/apps/web/dist/icon-maskable-512.png +0 -0
  142. package/apps/web/dist/icon.svg +0 -1
  143. package/apps/web/dist/index.html +10 -7
  144. package/apps/web/dist/sw.js +1 -1
  145. package/package.json +1 -1
  146. package/apps/web/dist/assets/button-B9gb3kFa.js +0 -1
  147. package/apps/web/dist/assets/dist-BJ6NAVkJ.js +0 -153
  148. package/apps/web/dist/assets/dist-DjkoGOJl.js +0 -1
  149. package/apps/web/dist/assets/image-viewer-Cqc2TB1C.js +0 -1
  150. package/apps/web/dist/assets/index-ChaRNH6C.js +0 -782
  151. package/apps/web/dist/assets/index-Cs6X6ieb.css +0 -2
  152. package/apps/web/dist/assets/jsx-runtime-D3jfb0Ew.js +0 -1
  153. package/apps/web/dist/assets/tooltip-CVzJHuCM.js +0 -1
  154. package/apps/web/dist/assets/video-player-4TBQR7ei.js +0 -1
  155. package/apps/web/dist/assets/video-viewer-DAKoRaNT.js +0 -1
  156. package/apps/web/dist/assets/zoomable-image-8K4_Vqt3.js +0 -41
  157. package/apps/web/dist/assets/zoomable-image-DKc1MmY3.js +0 -1
@@ -6,15 +6,15 @@ import { consola } from "consola";
6
6
  import { WebSocketServer } from "ws";
7
7
  import { z } from "zod";
8
8
  import os from "node:os";
9
- import { deleteSession, forkSession, getSessionMessages, getSubagentMessages, listSessions, query, renameSession } from "@anthropic-ai/claude-agent-sdk";
9
+ import { deleteSession, forkSession, getSessionInfo, getSessionMessages, getSubagentMessages, listSessions, query, renameSession } from "@anthropic-ai/claude-agent-sdk";
10
10
  import { execFile, spawn } from "node:child_process";
11
11
  import readline from "node:readline";
12
12
  import { Command } from "@commander-js/extra-typings";
13
13
  import { lstat, mkdir, open, readFile, readdir, readlink, stat, writeFile } from "node:fs/promises";
14
14
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
15
- import { OpenCode } from "@opencode/client";
15
+ import { OpenCode, isSessionNotFoundError } from "@opencode/client";
16
16
  import { ensure, headers } from "@opencode/client/service";
17
- import { and, eq, gt, inArray, lte, sql } from "drizzle-orm";
17
+ import { and, eq, gt, inArray, lte, max, sql } from "drizzle-orm";
18
18
  import { pathToFileURL } from "node:url";
19
19
  import { sumBy } from "es-toolkit";
20
20
  import { DatabaseSync } from "node:sqlite";
@@ -1551,6 +1551,12 @@ async function codexThreads(paths) {
1551
1551
  } while (cursor !== null);
1552
1552
  return threads;
1553
1553
  }
1554
+ async function codexThread(threadId) {
1555
+ return (await server$2(threadId).request("thread/read", {
1556
+ threadId,
1557
+ includeTurns: false
1558
+ })).thread;
1559
+ }
1554
1560
  async function codexHistory(sessionId) {
1555
1561
  const run = codexRun(sessionId);
1556
1562
  const items = turnItems((await readThread(sessionId)).turns, null);
@@ -2038,6 +2044,9 @@ async function openCodeSessions(paths) {
2038
2044
  return found;
2039
2045
  }))).flat().filter((session) => !temporary.has(session.id));
2040
2046
  }
2047
+ async function openCodeSession(sessionId) {
2048
+ return (await openCode()).session.get({ sessionID: sessionId });
2049
+ }
2041
2050
  async function openCodeHistory(sessionId, cwd) {
2042
2051
  const run = openCodeRun(sessionId);
2043
2052
  const client = await openCode();
@@ -2529,7 +2538,8 @@ const projects$2 = snakeCase.table("projects", {
2529
2538
  id: text().primaryKey(),
2530
2539
  path: text().notNull().unique(),
2531
2540
  name: text().notNull(),
2532
- logo: text()
2541
+ logo: text(),
2542
+ position: integer().notNull().default(0)
2533
2543
  });
2534
2544
  const sessions$1 = snakeCase.table("sessions", {
2535
2545
  sessionId: text().primaryKey(),
@@ -2994,7 +3004,12 @@ const LOGO_TYPES = [
2994
3004
  "image/vnd.microsoft.icon"
2995
3005
  ];
2996
3006
  function projects$1() {
2997
- return db.select().from(projects$2).all();
3007
+ return db.select({
3008
+ id: projects$2.id,
3009
+ path: projects$2.path,
3010
+ name: projects$2.name,
3011
+ logo: projects$2.logo
3012
+ }).from(projects$2).orderBy(projects$2.position).all();
2998
3013
  }
2999
3014
  function projectPath(id) {
3000
3015
  const project = db.select().from(projects$2).where(eq(projects$2.id, id)).get();
@@ -3004,11 +3019,13 @@ function projectPath(id) {
3004
3019
  async function addProject(input) {
3005
3020
  const folder = path.resolve(expandHome(input.trim()));
3006
3021
  if (!(await stat(folder)).isDirectory()) throw new Error(`${folder} is not a folder`);
3022
+ const last = db.select({ position: max(projects$2.position) }).from(projects$2).get();
3007
3023
  db.insert(projects$2).values({
3008
3024
  id: randomUUID(),
3009
3025
  path: folder,
3010
3026
  name: path.basename(folder) || folder,
3011
- logo: await findLogo(folder)
3027
+ logo: await findLogo(folder),
3028
+ position: last === void 0 || last.position === null ? 0 : last.position + 1
3012
3029
  }).onConflictDoNothing({ target: projects$2.path }).run();
3013
3030
  publish$1();
3014
3031
  const project = projects$1().find((item) => item.path === folder);
@@ -3032,6 +3049,17 @@ function removeProject(id) {
3032
3049
  db.delete(projects$2).where(eq(projects$2.id, id)).run();
3033
3050
  publish$1();
3034
3051
  }
3052
+ function reorderProjects(ids) {
3053
+ const current = projects$1().map((project) => project.id);
3054
+ if (ids.length !== current.length || !current.every((id) => ids.includes(id))) throw new Error("The projects changed, try again");
3055
+ db.transaction((transaction) => {
3056
+ ids.forEach((id, position) => {
3057
+ transaction.update(projects$2).set({ position }).where(eq(projects$2.id, id)).run();
3058
+ });
3059
+ });
3060
+ publish$1();
3061
+ return null;
3062
+ }
3035
3063
  async function directories(input) {
3036
3064
  const folder = path.resolve(expandHome(input.trim()));
3037
3065
  const entries = await readdir(folder, { withFileTypes: true });
@@ -3062,6 +3090,89 @@ function expandHome(input) {
3062
3090
  return input;
3063
3091
  }
3064
3092
  //#endregion
3093
+ //#region src/services/provider-sessions.ts
3094
+ async function info(provider, id, paths) {
3095
+ switch (provider) {
3096
+ case "claude": return (await Promise.all([...paths].map(async ([cwd, projectId]) => {
3097
+ const item = await getSessionInfo(id, { dir: cwd });
3098
+ return item === void 0 ? null : fromClaude(item, projectId);
3099
+ }))).find((item) => item !== null) ?? null;
3100
+ case "codex": {
3101
+ if (!codexInstalled()) return null;
3102
+ const thread = await codexThread(id).catch((error) => {
3103
+ if (error instanceof Error && error.message.startsWith("thread not loaded")) return null;
3104
+ throw error;
3105
+ });
3106
+ if (thread === null) return null;
3107
+ const projectId = paths.get(thread.cwd);
3108
+ return projectId === void 0 ? null : fromCodex(thread, projectId);
3109
+ }
3110
+ case "opencode": {
3111
+ if (!openCodeInstalled()) return null;
3112
+ const session = await openCodeSession(id).catch((error) => {
3113
+ if (isSessionNotFoundError(error)) return null;
3114
+ throw error;
3115
+ });
3116
+ if (session === null) return null;
3117
+ const projectId = paths.get(session.location.directory);
3118
+ return projectId === void 0 ? null : fromOpenCode(session, projectId);
3119
+ }
3120
+ }
3121
+ }
3122
+ function fromClaude(item, projectId) {
3123
+ return {
3124
+ id: item.sessionId,
3125
+ provider: "claude",
3126
+ title: item.summary,
3127
+ projectId,
3128
+ branch: item.gitBranch ?? null,
3129
+ updatedAt: item.lastModified
3130
+ };
3131
+ }
3132
+ function fromCodex(thread, projectId) {
3133
+ return {
3134
+ id: thread.id,
3135
+ provider: "codex",
3136
+ title: thread.name ?? thread.preview.replaceAll(/\[Image: source: [^\]]+\]/g, ""),
3137
+ projectId,
3138
+ branch: thread.gitInfo?.branch ?? null,
3139
+ updatedAt: thread.updatedAt * 1e3
3140
+ };
3141
+ }
3142
+ function fromOpenCode(session, projectId) {
3143
+ return {
3144
+ id: session.id,
3145
+ provider: "opencode",
3146
+ title: session.title ?? "New session",
3147
+ projectId,
3148
+ branch: null,
3149
+ updatedAt: session.time.updated
3150
+ };
3151
+ }
3152
+ async function find(provider, paths) {
3153
+ switch (provider) {
3154
+ case "claude": return (await Promise.all([...paths].map(async ([cwd, projectId]) => (await listSessions({
3155
+ dir: cwd,
3156
+ includeWorktrees: false,
3157
+ includeProgrammatic: false
3158
+ })).map((item) => fromClaude(item, projectId))))).flat();
3159
+ case "codex":
3160
+ if (!codexInstalled()) return null;
3161
+ return (await codexThreads([...paths.keys()])).flatMap((thread) => {
3162
+ const projectId = paths.get(thread.cwd);
3163
+ if (projectId === void 0) return [];
3164
+ return [fromCodex(thread, projectId)];
3165
+ });
3166
+ case "opencode":
3167
+ if (!openCodeInstalled()) return null;
3168
+ return (await openCodeSessions([...paths.keys()])).flatMap((session) => {
3169
+ const projectId = paths.get(session.location.directory);
3170
+ if (projectId === void 0) return [];
3171
+ return [fromOpenCode(session, projectId)];
3172
+ });
3173
+ }
3174
+ }
3175
+ //#endregion
3065
3176
  //#region ../core/src/terminal.ts
3066
3177
  function encodeFrame(kind, id, data) {
3067
3178
  const frame = new Uint8Array(5 + data.length);
@@ -4074,9 +4185,45 @@ const timers = /* @__PURE__ */ new Map();
4074
4185
  const providers = /* @__PURE__ */ new Map();
4075
4186
  let watchers = [];
4076
4187
  function sessions() {
4077
- const records = new Map(db.select().from(sessions$1).all().map((record) => [record.sessionId, record]));
4078
4188
  const known = new Set(projects$1().map((project) => project.id));
4079
- return allProviders.flatMap((provider) => listed[provider].filter((item) => known.has(item.projectId)).map((item) => {
4189
+ return withStatus(allProviders.flatMap((provider) => listed[provider]).filter((item) => known.has(item.projectId))).filter((session) => session.status !== "inactive");
4190
+ }
4191
+ async function inactiveSessions(projectId) {
4192
+ return (await everything(projectPaths().filter(([, id]) => projectId === null || id === projectId))).filter((session) => session.status === "inactive").sort((a, b) => b.updatedAt - a.updatedAt);
4193
+ }
4194
+ async function searchSessions(query) {
4195
+ const words = query.toLowerCase().split(/\s+/).filter(Boolean);
4196
+ const folders = new Map(projects$1().map((project) => [project.id, project.path]));
4197
+ return (await everything(projectPaths())).filter((session) => {
4198
+ const text = `${session.title} ${folders.get(session.projectId) ?? ""}`.toLowerCase();
4199
+ return words.every((word) => text.includes(word));
4200
+ }).sort((a, b) => b.updatedAt - a.updatedAt).slice(0, 50);
4201
+ }
4202
+ async function findSession(id) {
4203
+ const paths = new Map(projectPaths());
4204
+ const owner = ownerOf(id);
4205
+ if (owner !== void 0) {
4206
+ const item = await info(owner, id, paths);
4207
+ return item === null ? null : withStatus([item])[0];
4208
+ }
4209
+ for (const provider of allProviders) {
4210
+ if (!readConfig().enabledProviders[provider]) continue;
4211
+ const item = await info(provider, id, paths).catch(() => null);
4212
+ if (item !== null) {
4213
+ providers.set(id, provider);
4214
+ return withStatus([item])[0];
4215
+ }
4216
+ }
4217
+ return null;
4218
+ }
4219
+ async function everything(paths) {
4220
+ const found = (await Promise.all(allProviders.filter((provider) => readConfig().enabledProviders[provider]).map((provider) => find(provider, new Map(paths))))).flatMap((items) => items ?? []);
4221
+ for (const item of found) providers.set(item.id, item.provider);
4222
+ return withStatus(found);
4223
+ }
4224
+ function withStatus(items) {
4225
+ const records = new Map(db.select().from(sessions$1).all().map((record) => [record.sessionId, record]));
4226
+ return items.map((item) => {
4080
4227
  const record = records.get(item.id);
4081
4228
  const updatedAt = record?.interactedAt ?? item.updatedAt;
4082
4229
  return {
@@ -4084,7 +4231,13 @@ function sessions() {
4084
4231
  updatedAt,
4085
4232
  status: record === void 0 || record.status === "active" && Date.now() - updatedAt > day ? "inactive" : record.status
4086
4233
  };
4087
- }));
4234
+ });
4235
+ }
4236
+ function projectPaths() {
4237
+ return projects$1().map((project) => [project.path, project.id]);
4238
+ }
4239
+ function ownerOf(sessionId) {
4240
+ return runs.get(sessionId)?.provider ?? providers.get(sessionId);
4088
4241
  }
4089
4242
  function providerStatuses() {
4090
4243
  return allProviders.map((provider) => statuses[provider]);
@@ -4093,7 +4246,7 @@ function listedUpdatedAt(provider, sessionId) {
4093
4246
  return listed[provider].find((item) => item.id === sessionId)?.updatedAt ?? null;
4094
4247
  }
4095
4248
  function providerOf(sessionId) {
4096
- const provider = runs.get(sessionId)?.provider ?? providers.get(sessionId);
4249
+ const provider = ownerOf(sessionId);
4097
4250
  if (provider === void 0) throw new Error("offsite does not know this session yet, reload the page");
4098
4251
  return provider;
4099
4252
  }
@@ -4141,7 +4294,7 @@ async function refresh(provider) {
4141
4294
  refreshing.delete(provider);
4142
4295
  }
4143
4296
  async function list(provider) {
4144
- const paths = new Map(projects$1().map((project) => [project.path, project.id]));
4297
+ const paths = new Map(projectPaths());
4145
4298
  const before = statuses[provider];
4146
4299
  let timer;
4147
4300
  try {
@@ -4154,7 +4307,7 @@ async function list(provider) {
4154
4307
  };
4155
4308
  return;
4156
4309
  }
4157
- const found = await Promise.race([find(provider, paths), new Promise((_, reject) => {
4310
+ const found = await Promise.race([tracked(provider, paths), new Promise((_, reject) => {
4158
4311
  timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`${providerName(provider)} did not list its sessions within ${LIST_TIMEOUT / 1e3} seconds`)), LIST_TIMEOUT);
4159
4312
  })]);
4160
4313
  if (found === null) {
@@ -4190,49 +4343,14 @@ async function list(provider) {
4190
4343
  });
4191
4344
  }
4192
4345
  }
4193
- async function find(provider, paths) {
4194
- switch (provider) {
4195
- case "claude": return (await Promise.all([...paths].map(async ([cwd, projectId]) => (await listSessions({
4196
- dir: cwd,
4197
- includeWorktrees: false,
4198
- includeProgrammatic: false
4199
- })).map((item) => ({
4200
- id: item.sessionId,
4201
- provider: "claude",
4202
- title: item.summary,
4203
- projectId,
4204
- branch: item.gitBranch ?? null,
4205
- updatedAt: item.lastModified
4206
- }))))).flat();
4207
- case "codex":
4208
- if (!codexInstalled()) return null;
4209
- return (await codexThreads([...paths.keys()])).flatMap((thread) => {
4210
- const projectId = paths.get(thread.cwd);
4211
- if (projectId === void 0) return [];
4212
- return [{
4213
- id: thread.id,
4214
- provider: "codex",
4215
- title: thread.name ?? thread.preview.replaceAll(/\[Image: source: [^\]]+\]/g, ""),
4216
- projectId,
4217
- branch: thread.gitInfo?.branch ?? null,
4218
- updatedAt: thread.updatedAt * 1e3
4219
- }];
4220
- });
4221
- case "opencode":
4222
- if (!openCodeInstalled()) return null;
4223
- return (await openCodeSessions([...paths.keys()])).flatMap((session) => {
4224
- const projectId = paths.get(session.location.directory);
4225
- if (projectId === void 0) return [];
4226
- return [{
4227
- id: session.id,
4228
- provider: "opencode",
4229
- title: session.title ?? "New session",
4230
- projectId,
4231
- branch: null,
4232
- updatedAt: session.time.updated
4233
- }];
4234
- });
4235
- }
4346
+ async function tracked(provider, paths) {
4347
+ if (provider === "codex" && !codexInstalled() || provider === "opencode" && !openCodeInstalled()) return null;
4348
+ return (await Promise.all(db.select().from(sessions$1).all().map((record) => {
4349
+ const owner = ownerOf(record.sessionId);
4350
+ if (owner === provider) return info(provider, record.sessionId, paths);
4351
+ if (owner === void 0) return info(provider, record.sessionId, paths).catch(() => null);
4352
+ return null;
4353
+ }))).filter((item) => item !== null);
4236
4354
  }
4237
4355
  function watchSessions() {
4238
4356
  for (const watcher of watchers) watcher.close();
@@ -4266,7 +4384,7 @@ async function updateSession(id, patch) {
4266
4384
  await run.closed;
4267
4385
  }
4268
4386
  db.delete(sessions$1).where(eq(sessions$1.sessionId, id)).run();
4269
- const all = sessions();
4387
+ const all = withStatus(allProviders.flatMap((provider) => listed[provider]));
4270
4388
  const session = all.find((item) => item.id === id);
4271
4389
  if (session !== void 0 && all.every((item) => item.projectId !== session.projectId || item.status === "inactive")) closeProjectTabs(session.projectId);
4272
4390
  } else if (patch.status !== void 0) {
@@ -4281,6 +4399,7 @@ async function updateSession(id, patch) {
4281
4399
  target: sessions$1.sessionId,
4282
4400
  set
4283
4401
  }).run();
4402
+ await refresh(providerOf(id));
4284
4403
  }
4285
4404
  if (patch.title !== void 0) refreshSessions(providerOf(id));
4286
4405
  }
@@ -6370,6 +6489,7 @@ const handlers = {
6370
6489
  refreshAll();
6371
6490
  return null;
6372
6491
  },
6492
+ "projects.reorder": (params) => reorderProjects(params.ids),
6373
6493
  "directories.list": (params) => directories(params.path),
6374
6494
  "sessions.update": async (params) => {
6375
6495
  try {
@@ -6388,9 +6508,12 @@ const handlers = {
6388
6508
  return null;
6389
6509
  },
6390
6510
  "sessions.open": async (params, client) => {
6511
+ const session = await findSession(params.sessionId);
6391
6512
  await open$1(client, params.sessionId, params.projectId);
6392
- return null;
6513
+ return session;
6393
6514
  },
6515
+ "sessions.inactive": (params) => inactiveSessions(params.projectId),
6516
+ "sessions.search": (params) => searchSessions(params.query),
6394
6517
  "sessions.earlier": (params) => earlier(params.sessionId, params.before),
6395
6518
  "sessions.image": (params) => image(params.sessionId, params.itemId, params.index),
6396
6519
  "sessions.agent": (params) => {