spiracha 1.5.0 → 2.0.0

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 (365) hide show
  1. package/AGENTS.md +114 -205
  2. package/README.md +89 -269
  3. package/apps/ui/AGENTS.md +17 -7
  4. package/apps/ui/README.md +34 -8
  5. package/apps/ui/components.json +21 -0
  6. package/apps/ui/package.json +65 -0
  7. package/apps/ui/src/components/antigravity-conversations-table.tsx +206 -0
  8. package/apps/ui/src/components/antigravity-keychain-panel.tsx +76 -0
  9. package/apps/ui/src/components/antigravity-workspaces-table.tsx +63 -0
  10. package/apps/ui/src/components/app-shell.tsx +124 -0
  11. package/apps/ui/src/components/breadcrumbs.tsx +53 -0
  12. package/apps/ui/src/components/claude-code-sessions-table.tsx +114 -0
  13. package/apps/ui/src/components/claude-code-workspaces-table.tsx +55 -0
  14. package/apps/ui/src/components/cursor-threads-table.tsx +189 -0
  15. package/apps/ui/src/components/cursor-workspaces-table.tsx +140 -0
  16. package/apps/ui/src/components/data-table.tsx +241 -0
  17. package/apps/ui/src/components/delete-confirm-dialog.tsx +88 -0
  18. package/apps/ui/src/components/export-dialog.tsx +184 -0
  19. package/apps/ui/src/components/json-panel.tsx +17 -0
  20. package/apps/ui/src/components/kiro-sessions-table.tsx +112 -0
  21. package/apps/ui/src/components/kiro-workspaces-table.tsx +53 -0
  22. package/apps/ui/src/components/list-search-input.tsx +18 -0
  23. package/apps/ui/src/components/loading-panel.tsx +23 -0
  24. package/apps/ui/src/components/metadata-section.tsx +31 -0
  25. package/apps/ui/src/components/metric-card.tsx +19 -0
  26. package/apps/ui/src/components/opencode-sessions-table.tsx +128 -0
  27. package/apps/ui/src/components/opencode-workspaces-table.tsx +57 -0
  28. package/apps/ui/src/components/page-header.tsx +33 -0
  29. package/apps/ui/src/components/projects-loading-state.tsx +74 -0
  30. package/apps/ui/src/components/projects-table.tsx +108 -0
  31. package/apps/ui/src/components/qoder-sessions-table.tsx +112 -0
  32. package/apps/ui/src/components/qoder-workspaces-table.tsx +53 -0
  33. package/apps/ui/src/components/recent-threads-list.tsx +52 -0
  34. package/apps/ui/src/components/reload-error-panel.tsx +20 -0
  35. package/apps/ui/src/components/text-document-panel.tsx +19 -0
  36. package/apps/ui/src/components/theme-toggle.tsx +48 -0
  37. package/apps/ui/src/components/threads-table.tsx +202 -0
  38. package/apps/ui/src/components/transcript-view.tsx +552 -0
  39. package/apps/ui/src/components/ui/alert-dialog.tsx +160 -0
  40. package/apps/ui/src/components/ui/badge.tsx +45 -0
  41. package/apps/ui/src/components/ui/button.tsx +62 -0
  42. package/apps/ui/src/components/ui/checkbox.tsx +29 -0
  43. package/apps/ui/src/components/ui/dialog.tsx +137 -0
  44. package/apps/ui/src/components/ui/dropdown-menu.tsx +217 -0
  45. package/apps/ui/src/components/ui/input.tsx +21 -0
  46. package/apps/ui/src/components/ui/scroll-area.tsx +46 -0
  47. package/apps/ui/src/components/ui/select.tsx +163 -0
  48. package/apps/ui/src/components/ui/separator.tsx +28 -0
  49. package/apps/ui/src/components/ui/sheet.tsx +107 -0
  50. package/apps/ui/src/components/ui/skeleton.tsx +7 -0
  51. package/apps/ui/src/components/ui/table.tsx +76 -0
  52. package/apps/ui/src/components/ui/tabs.tsx +71 -0
  53. package/apps/ui/src/components/ui/tooltip.tsx +44 -0
  54. package/apps/ui/src/integrations/tanstack-query/devtools.tsx +6 -0
  55. package/apps/ui/src/integrations/tanstack-query/root-provider.tsx +10 -0
  56. package/apps/ui/src/lib/antigravity-conversation-state.ts +28 -0
  57. package/apps/ui/src/lib/antigravity-queries.ts +33 -0
  58. package/apps/ui/src/lib/antigravity-server.ts +128 -0
  59. package/apps/ui/src/lib/antigravity-transcript-events.ts +335 -0
  60. package/apps/ui/src/lib/claude-code-queries.ts +26 -0
  61. package/apps/ui/src/lib/claude-code-server.ts +75 -0
  62. package/apps/ui/src/lib/claude-code-transcript-events.ts +154 -0
  63. package/apps/ui/src/lib/codex-queries.ts +66 -0
  64. package/apps/ui/src/lib/codex-server.ts +209 -0
  65. package/apps/ui/src/lib/cursor-queries.ts +37 -0
  66. package/apps/ui/src/lib/cursor-server.ts +272 -0
  67. package/apps/ui/src/lib/cursor-transcript-events.ts +229 -0
  68. package/apps/ui/src/lib/download.ts +166 -0
  69. package/apps/ui/src/lib/formatters.ts +149 -0
  70. package/apps/ui/src/lib/kiro-queries.ts +22 -0
  71. package/apps/ui/src/lib/kiro-server.ts +73 -0
  72. package/apps/ui/src/lib/kiro-transcript-events.ts +113 -0
  73. package/apps/ui/src/lib/opencode-queries.ts +37 -0
  74. package/apps/ui/src/lib/opencode-server.ts +73 -0
  75. package/apps/ui/src/lib/opencode-transcript-events.ts +221 -0
  76. package/apps/ui/src/lib/package-metadata.ts +16 -0
  77. package/apps/ui/src/lib/path-utils.ts +13 -0
  78. package/apps/ui/src/lib/qoder-queries.ts +22 -0
  79. package/apps/ui/src/lib/qoder-server.ts +79 -0
  80. package/apps/ui/src/lib/qoder-transcript-events.ts +139 -0
  81. package/apps/ui/src/lib/route-search.ts +68 -0
  82. package/apps/ui/src/lib/settings-store.tsx +59 -0
  83. package/apps/ui/src/lib/source-session-export-server.ts +56 -0
  84. package/apps/ui/src/lib/text-filter.ts +22 -0
  85. package/apps/ui/src/lib/thread-id.ts +3 -0
  86. package/apps/ui/src/lib/thread-transcript-stats.ts +57 -0
  87. package/apps/ui/src/lib/utils.ts +7 -0
  88. package/apps/ui/src/routeTree.gen.ts +730 -0
  89. package/apps/ui/src/router.tsx +20 -0
  90. package/apps/ui/src/routes/$threadId.tsx +22 -0
  91. package/apps/ui/src/routes/__root.tsx +127 -0
  92. package/apps/ui/src/routes/analytics.tsx +143 -0
  93. package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +438 -0
  94. package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +127 -0
  95. package/apps/ui/src/routes/antigravity.index.tsx +51 -0
  96. package/apps/ui/src/routes/api.v1.conversation-query.ts +12 -0
  97. package/apps/ui/src/routes/api.v1.conversations.$source.$id.export.ts +12 -0
  98. package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +12 -0
  99. package/apps/ui/src/routes/api.v1.conversations.ts +12 -0
  100. package/apps/ui/src/routes/api.v1.resolve.ts +12 -0
  101. package/apps/ui/src/routes/api.v1.sources.ts +12 -0
  102. package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +342 -0
  103. package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +135 -0
  104. package/apps/ui/src/routes/claude-code.index.tsx +48 -0
  105. package/apps/ui/src/routes/codex.$project.tsx +390 -0
  106. package/apps/ui/src/routes/codex.index.tsx +116 -0
  107. package/apps/ui/src/routes/cursor-threads.$composerId.tsx +435 -0
  108. package/apps/ui/src/routes/cursor.$workspaceKey.tsx +416 -0
  109. package/apps/ui/src/routes/cursor.index.tsx +120 -0
  110. package/apps/ui/src/routes/index.tsx +124 -0
  111. package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +345 -0
  112. package/apps/ui/src/routes/kiro.$workspaceKey.tsx +136 -0
  113. package/apps/ui/src/routes/kiro.index.tsx +48 -0
  114. package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +334 -0
  115. package/apps/ui/src/routes/opencode.$workspaceKey.tsx +135 -0
  116. package/apps/ui/src/routes/opencode.index.tsx +48 -0
  117. package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +341 -0
  118. package/apps/ui/src/routes/qoder.$workspaceKey.tsx +139 -0
  119. package/apps/ui/src/routes/qoder.index.tsx +48 -0
  120. package/apps/ui/src/routes/settings.tsx +91 -0
  121. package/apps/ui/src/routes/threads.$threadId.tsx +619 -0
  122. package/apps/ui/src/styles.css +122 -0
  123. package/apps/ui/tsconfig.json +29 -0
  124. package/apps/ui/vite.config.ts +84 -0
  125. package/bin/spiracha.ts +32 -0
  126. package/package.json +46 -73
  127. package/src/client.ts +290 -0
  128. package/src/lib/antigravity-db.ts +213 -19
  129. package/src/lib/antigravity-exporter-types.ts +1 -0
  130. package/src/lib/codex-analytics.ts +1 -1
  131. package/src/lib/codex-browser-db.ts +410 -74
  132. package/src/lib/codex-browser-export.ts +6 -14
  133. package/src/lib/codex-browser-types.ts +1 -1
  134. package/src/lib/{codex-exporter-types.ts → codex-thread-types.ts} +2 -30
  135. package/src/lib/{codex-exporter-transcript.ts → codex-transcript-renderer.ts} +64 -28
  136. package/src/lib/conversation-api.ts +792 -0
  137. package/src/lib/conversation-data/adapter-helpers.ts +110 -0
  138. package/src/lib/conversation-data/antigravity-adapter.ts +148 -0
  139. package/src/lib/conversation-data/claude-code-adapter.ts +175 -0
  140. package/src/lib/conversation-data/codex-adapter.ts +245 -0
  141. package/src/lib/conversation-data/cursor-adapter.ts +171 -0
  142. package/src/lib/conversation-data/index.ts +311 -0
  143. package/src/lib/conversation-data/kiro-adapter.ts +140 -0
  144. package/src/lib/conversation-data/message-selector.ts +37 -0
  145. package/src/lib/conversation-data/opencode-adapter.ts +180 -0
  146. package/src/lib/conversation-data/path-match.ts +79 -0
  147. package/src/lib/conversation-data/qoder-adapter.ts +230 -0
  148. package/src/lib/conversation-data/types.ts +116 -0
  149. package/src/lib/cursor-db.ts +67 -21
  150. package/src/lib/cursor-exporter-types.ts +0 -19
  151. package/src/lib/qoder-acp-client.ts +268 -0
  152. package/src/lib/qoder-db.ts +1601 -0
  153. package/src/lib/qoder-exporter-types.ts +114 -0
  154. package/src/lib/qoder-transcript-phase.ts +41 -0
  155. package/src/lib/qoder-transcript.ts +112 -0
  156. package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +0 -1
  157. package/apps/ui/dist/client/assets/analytics-DOy1b6Sh.js +0 -1
  158. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-DqySVO2K.js +0 -7
  159. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-KAcXtNxI.js +0 -1
  160. package/apps/ui/dist/client/assets/antigravity-keychain-panel-B77qJz6f.js +0 -1
  161. package/apps/ui/dist/client/assets/antigravity._workspaceKey-B3NM6gRH.js +0 -1
  162. package/apps/ui/dist/client/assets/antigravity._workspaceKey-ByitGWki.js +0 -1
  163. package/apps/ui/dist/client/assets/antigravity.index-DP9JC2P9.js +0 -1
  164. package/apps/ui/dist/client/assets/antigravity.index-DgW25FEV.js +0 -1
  165. package/apps/ui/dist/client/assets/badge-C3i4OKs8.js +0 -1
  166. package/apps/ui/dist/client/assets/checkbox-CdHitXWQ.js +0 -1
  167. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-8pQ55ci2.js +0 -1
  168. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-DVz5UmtU.js +0 -1
  169. package/apps/ui/dist/client/assets/claude-code._workspaceKey-BBKskSum.js +0 -1
  170. package/apps/ui/dist/client/assets/claude-code._workspaceKey-OkikMUFs.js +0 -1
  171. package/apps/ui/dist/client/assets/claude-code.index-Cwu76dbb.js +0 -1
  172. package/apps/ui/dist/client/assets/claude-code.index-D6eMd08t.js +0 -1
  173. package/apps/ui/dist/client/assets/createServerFn-B-KkwmHU.js +0 -3
  174. package/apps/ui/dist/client/assets/cursor-threads._composerId-CmBFclK8.js +0 -1
  175. package/apps/ui/dist/client/assets/cursor-threads._composerId-hBWlP1D-.js +0 -1
  176. package/apps/ui/dist/client/assets/cursor._workspaceKey-BFPkIRi-.js +0 -1
  177. package/apps/ui/dist/client/assets/cursor._workspaceKey-CaAZjGmm.js +0 -1
  178. package/apps/ui/dist/client/assets/cursor.index-8y4o20kb.js +0 -2
  179. package/apps/ui/dist/client/assets/cursor.index-CrnMwDCi.js +0 -1
  180. package/apps/ui/dist/client/assets/data-table-Br78_dk3.js +0 -4
  181. package/apps/ui/dist/client/assets/delete-confirm-dialog-Bxs07u-j.js +0 -7
  182. package/apps/ui/dist/client/assets/dist-B9pyYCVU.js +0 -1
  183. package/apps/ui/dist/client/assets/dist-BrJhN2A0.js +0 -5
  184. package/apps/ui/dist/client/assets/dist-Cmd3AIfD.js +0 -1
  185. package/apps/ui/dist/client/assets/dist-DvMS2965.js +0 -1
  186. package/apps/ui/dist/client/assets/download-Bf0QJKD3.js +0 -1
  187. package/apps/ui/dist/client/assets/dropdown-menu-D5cvPaZt.js +0 -1
  188. package/apps/ui/dist/client/assets/es2015-ad6040dw.js +0 -41
  189. package/apps/ui/dist/client/assets/export-dialog-Dr8d2MqD.js +0 -1
  190. package/apps/ui/dist/client/assets/formatters-BtqyrX_c.js +0 -1
  191. package/apps/ui/dist/client/assets/index-C-STgIH4.js +0 -166
  192. package/apps/ui/dist/client/assets/jsx-runtime-DGeXAQPT.js +0 -1
  193. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-CKgfJ7GR.js +0 -1
  194. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-zvIJHtQF.js +0 -1
  195. package/apps/ui/dist/client/assets/kiro._workspaceKey-DhVuJuZB.js +0 -1
  196. package/apps/ui/dist/client/assets/kiro._workspaceKey-QArsjkTY.js +0 -1
  197. package/apps/ui/dist/client/assets/kiro.index-C-fr4m7i.js +0 -1
  198. package/apps/ui/dist/client/assets/kiro.index-OYgAdtZd.js +0 -1
  199. package/apps/ui/dist/client/assets/metric-card-Dplm0ZiM.js +0 -1
  200. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-DLjiTst-.js +0 -1
  201. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-biBwrRbt.js +0 -8
  202. package/apps/ui/dist/client/assets/opencode._workspaceKey-C7OIzMOJ.js +0 -1
  203. package/apps/ui/dist/client/assets/opencode._workspaceKey-sBakX0oI.js +0 -1
  204. package/apps/ui/dist/client/assets/opencode.index-Bl_kNs9N.js +0 -1
  205. package/apps/ui/dist/client/assets/opencode.index-CN53bVmb.js +0 -1
  206. package/apps/ui/dist/client/assets/page-header-Cwa3p6Tl.js +0 -1
  207. package/apps/ui/dist/client/assets/preload-helper-B8fFrdxC.js +0 -1
  208. package/apps/ui/dist/client/assets/projects._project-D8WloxQN.js +0 -1
  209. package/apps/ui/dist/client/assets/projects._project-DSDwH4NF.js +0 -1
  210. package/apps/ui/dist/client/assets/projects.index-5xRtuJdX.js +0 -3
  211. package/apps/ui/dist/client/assets/projects.index-DEfhWqa8.js +0 -1
  212. package/apps/ui/dist/client/assets/react-dom-DL96Jor4.js +0 -1
  213. package/apps/ui/dist/client/assets/refresh-ccw-BgKjOiA6.js +0 -1
  214. package/apps/ui/dist/client/assets/reload-error-panel-AHqu0akK.js +0 -1
  215. package/apps/ui/dist/client/assets/routes-DnzF_9CX.js +0 -1
  216. package/apps/ui/dist/client/assets/scroll-text-fM0sMOB3.js +0 -1
  217. package/apps/ui/dist/client/assets/select-CYF6pF37.js +0 -1
  218. package/apps/ui/dist/client/assets/settings-Dx70jgP_.js +0 -1
  219. package/apps/ui/dist/client/assets/sqlite-error-B6uZjUe8.js +0 -1
  220. package/apps/ui/dist/client/assets/styles-B7Zi9EFA.css +0 -1
  221. package/apps/ui/dist/client/assets/tabs-CmuhkT-c.js +0 -7
  222. package/apps/ui/dist/client/assets/text-filter-DVAZySUS.js +0 -2
  223. package/apps/ui/dist/client/assets/thread-transcript-stats-BUNz6u7F.js +0 -1
  224. package/apps/ui/dist/client/assets/threads._threadId-BB9tTsV4.js +0 -1
  225. package/apps/ui/dist/client/assets/threads._threadId-BMRSFow3.js +0 -1
  226. package/apps/ui/dist/client/assets/useMutation-BSFult2i.js +0 -1
  227. package/apps/ui/dist/client/assets/useQuery-CjINKZf1.js +0 -1
  228. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CQ8Jjs3B.js +0 -387
  229. package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +0 -6
  230. package/apps/ui/dist/server/assets/analytics-CYP_LT5Y.js +0 -16
  231. package/apps/ui/dist/server/assets/analytics-CtpOMVMO.js +0 -146
  232. package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +0 -16
  233. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BKOyL2T6.js +0 -613
  234. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +0 -11
  235. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-eS87Dx7g.js +0 -20
  236. package/apps/ui/dist/server/assets/antigravity-db-Bh8_U9uw.js +0 -580
  237. package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +0 -126
  238. package/apps/ui/dist/server/assets/antigravity-keychain-panel-CC7FLmAK.js +0 -55
  239. package/apps/ui/dist/server/assets/antigravity-queries-CGrJO9Vr.js +0 -37
  240. package/apps/ui/dist/server/assets/antigravity-server-CHRjVFqN.js +0 -114
  241. package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +0 -11
  242. package/apps/ui/dist/server/assets/antigravity._workspaceKey-B0QeYUOh.js +0 -28
  243. package/apps/ui/dist/server/assets/antigravity._workspaceKey-C3kP-qyN.js +0 -210
  244. package/apps/ui/dist/server/assets/antigravity.index-CPCYkqCi.js +0 -104
  245. package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +0 -11
  246. package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +0 -26
  247. package/apps/ui/dist/server/assets/button-CmTDnzOn.js +0 -46
  248. package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +0 -19
  249. package/apps/ui/dist/server/assets/claude-code-db-Ik3VStKZ.js +0 -361
  250. package/apps/ui/dist/server/assets/claude-code-queries-Cgzi4K-e.js +0 -37
  251. package/apps/ui/dist/server/assets/claude-code-server-PfraClXS.js +0 -72
  252. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-C55oe6zj.js +0 -18
  253. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-D1RYYi3j.js +0 -473
  254. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-DSvPLEUL.js +0 -11
  255. package/apps/ui/dist/server/assets/claude-code-transcript-C-bxh3cS.js +0 -139
  256. package/apps/ui/dist/server/assets/claude-code-transcript-phase-DmUMc8VU.js +0 -10
  257. package/apps/ui/dist/server/assets/claude-code._workspaceKey-B5Xg_-tE.js +0 -28
  258. package/apps/ui/dist/server/assets/claude-code._workspaceKey-BPlzyXPa.js +0 -11
  259. package/apps/ui/dist/server/assets/claude-code._workspaceKey-DqDve2wl.js +0 -191
  260. package/apps/ui/dist/server/assets/claude-code.index-B7yYR7dD.js +0 -92
  261. package/apps/ui/dist/server/assets/claude-code.index-BUHThG1W.js +0 -11
  262. package/apps/ui/dist/server/assets/codex-queries-CtgeZ7VL.js +0 -99
  263. package/apps/ui/dist/server/assets/codex-server-CGXU4H8-.js +0 -2294
  264. package/apps/ui/dist/server/assets/concurrency-VXtYvlGh.js +0 -18
  265. package/apps/ui/dist/server/assets/createServerRpc-CF_DEwnm.js +0 -12
  266. package/apps/ui/dist/server/assets/createSsrRpc-C754NPki.js +0 -16
  267. package/apps/ui/dist/server/assets/cursor-db-CZnYy7aT.js +0 -830
  268. package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +0 -34
  269. package/apps/ui/dist/server/assets/cursor-queries-NCIM0Nat.js +0 -67
  270. package/apps/ui/dist/server/assets/cursor-recovery-CXpO8KcD.js +0 -361
  271. package/apps/ui/dist/server/assets/cursor-server-DNu52A3K.js +0 -213
  272. package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +0 -11
  273. package/apps/ui/dist/server/assets/cursor-threads._composerId-Ckn6ItHI.js +0 -582
  274. package/apps/ui/dist/server/assets/cursor-threads._composerId-p9-ARAzc.js +0 -18
  275. package/apps/ui/dist/server/assets/cursor-transcript-B7tGnqtn.js +0 -125
  276. package/apps/ui/dist/server/assets/cursor._workspaceKey-CZuohIUL.js +0 -28
  277. package/apps/ui/dist/server/assets/cursor._workspaceKey-DPp5JSjy.js +0 -401
  278. package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +0 -11
  279. package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +0 -11
  280. package/apps/ui/dist/server/assets/cursor.index-DkWT-mxw.js +0 -189
  281. package/apps/ui/dist/server/assets/data-table-Cdct823O.js +0 -189
  282. package/apps/ui/dist/server/assets/delete-confirm-dialog-BcBNCxWB.js +0 -144
  283. package/apps/ui/dist/server/assets/download-DMmiy1xf.js +0 -92
  284. package/apps/ui/dist/server/assets/dropdown-menu-Dy_9t6TN.js +0 -36
  285. package/apps/ui/dist/server/assets/empty-plugin-adapters-B3lHh1La.js +0 -5
  286. package/apps/ui/dist/server/assets/export-dialog-D88ze9Gy.js +0 -240
  287. package/apps/ui/dist/server/assets/formatters-FJaGZgJk.js +0 -91
  288. package/apps/ui/dist/server/assets/kiro-db--fXrED_-.js +0 -552
  289. package/apps/ui/dist/server/assets/kiro-queries-CzNlM2ok.js +0 -37
  290. package/apps/ui/dist/server/assets/kiro-server-9WRxg2Au.js +0 -72
  291. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-CRY2c7YO.js +0 -11
  292. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-F1UlwxmR.js +0 -449
  293. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-bvTulT7C.js +0 -18
  294. package/apps/ui/dist/server/assets/kiro-transcript-DoekQBaH.js +0 -112
  295. package/apps/ui/dist/server/assets/kiro-transcript-phase-CJG40nQg.js +0 -27
  296. package/apps/ui/dist/server/assets/kiro._workspaceKey-BDe9sQwo.js +0 -11
  297. package/apps/ui/dist/server/assets/kiro._workspaceKey-CJsjgNwO.js +0 -28
  298. package/apps/ui/dist/server/assets/kiro._workspaceKey-D_-4Qb7y.js +0 -193
  299. package/apps/ui/dist/server/assets/kiro.index-C__-UROk.js +0 -11
  300. package/apps/ui/dist/server/assets/kiro.index-CmTbqeYj.js +0 -93
  301. package/apps/ui/dist/server/assets/loading-panel-BGFnWseS.js +0 -27
  302. package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +0 -23
  303. package/apps/ui/dist/server/assets/model-label-B1NWGc65.js +0 -13
  304. package/apps/ui/dist/server/assets/opencode-db-BM7KjOzc.js +0 -397
  305. package/apps/ui/dist/server/assets/opencode-queries-BeNYXnQv.js +0 -50
  306. package/apps/ui/dist/server/assets/opencode-server-BpQ_kRze.js +0 -72
  307. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-CGQ-t0vD.js +0 -518
  308. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-D8Q7in_Z.js +0 -18
  309. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-DKOvi0lV.js +0 -11
  310. package/apps/ui/dist/server/assets/opencode-think-tags-CAoD-EcZ.js +0 -87
  311. package/apps/ui/dist/server/assets/opencode-transcript-BNTcGNym.js +0 -141
  312. package/apps/ui/dist/server/assets/opencode-transcript-phase-OqLkiQD0.js +0 -32
  313. package/apps/ui/dist/server/assets/opencode._workspaceKey-BdqcWHw1.js +0 -11
  314. package/apps/ui/dist/server/assets/opencode._workspaceKey-CfH96HTT.js +0 -28
  315. package/apps/ui/dist/server/assets/opencode._workspaceKey-DdbHPDrO.js +0 -207
  316. package/apps/ui/dist/server/assets/opencode.index-BbVzkJXP.js +0 -11
  317. package/apps/ui/dist/server/assets/opencode.index-Vh_Gq_1L.js +0 -93
  318. package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +0 -29
  319. package/apps/ui/dist/server/assets/path-transforms-DL2IwtYd.js +0 -31
  320. package/apps/ui/dist/server/assets/projects._project-4io5LO0E.js +0 -20
  321. package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +0 -12
  322. package/apps/ui/dist/server/assets/projects._project-D6ZoGhJ8.js +0 -395
  323. package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +0 -12
  324. package/apps/ui/dist/server/assets/projects.index-BkLiF2FF.js +0 -182
  325. package/apps/ui/dist/server/assets/projects.index-DesYXwfi.js +0 -14
  326. package/apps/ui/dist/server/assets/reload-error-panel-BJMxY3U1.js +0 -25
  327. package/apps/ui/dist/server/assets/route-search-ts4W9MJ9.js +0 -38
  328. package/apps/ui/dist/server/assets/router-Sac2DGk6.js +0 -518
  329. package/apps/ui/dist/server/assets/routes-Bsact1uB.js +0 -184
  330. package/apps/ui/dist/server/assets/routes-BzkJgq4W.js +0 -34
  331. package/apps/ui/dist/server/assets/select-GW76p-ld.js +0 -76
  332. package/apps/ui/dist/server/assets/settings-OayxIYQQ.js +0 -100
  333. package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +0 -52
  334. package/apps/ui/dist/server/assets/shared-DyhChtHf.js +0 -137
  335. package/apps/ui/dist/server/assets/source-session-export-server-DNutCawb.js +0 -38
  336. package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +0 -13
  337. package/apps/ui/dist/server/assets/start-B_HFwkkk.js +0 -4
  338. package/apps/ui/dist/server/assets/tabs-DkaChNVg.js +0 -501
  339. package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +0 -36
  340. package/apps/ui/dist/server/assets/thread-transcript-stats-Dh34mt2u.js +0 -45
  341. package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +0 -26
  342. package/apps/ui/dist/server/assets/threads._threadId-BeXEc4Lo.js +0 -648
  343. package/apps/ui/dist/server/assets/threads._threadId-Ci0S4mKU.js +0 -18
  344. package/apps/ui/dist/server/assets/ui-export-files-BHLX9bhN.js +0 -83
  345. package/apps/ui/dist/server/assets/utils-C_uf36nf.js +0 -8
  346. package/apps/ui/dist/server/server.js +0 -5895
  347. package/bin/codex-chats-claude.js +0 -5
  348. package/bin/codex-chats.js +0 -5
  349. package/bin/spiracha.js +0 -5
  350. package/src/export-chats.ts +0 -120
  351. package/src/export-claude.ts +0 -36
  352. package/src/export-cursor.ts +0 -244
  353. package/src/lib/claude-exporter.ts +0 -864
  354. package/src/lib/codex-exporter-cli.ts +0 -277
  355. package/src/lib/codex-exporter-db.ts +0 -319
  356. package/src/lib/codex-exporter.ts +0 -115
  357. package/src/lib/cursor-exporter.ts +0 -266
  358. package/src/lib/interactive-cli.ts +0 -433
  359. package/src/lib/native-open.ts +0 -54
  360. package/src/mcp-server.ts +0 -137
  361. package/src/spiracha.ts +0 -116
  362. package/src/ui-cli.ts +0 -310
  363. /package/apps/ui/{dist/client → public}/icon.svg +0 -0
  364. /package/apps/ui/{dist/client → public}/manifest.json +0 -0
  365. /package/apps/ui/{dist/client → public}/robots.txt +0 -0
@@ -0,0 +1,128 @@
1
+ import { createServerFn } from '@tanstack/react-start';
2
+ import { z } from 'zod';
3
+ import { canExportAntigravityConversation, isAntigravityConversationLocked } from './antigravity-conversation-state';
4
+
5
+ const workspaceSchema = z.object({
6
+ workspaceKey: z.string().min(1),
7
+ });
8
+
9
+ const conversationSchema = z.object({
10
+ conversationId: z.string().min(1),
11
+ });
12
+
13
+ const exportSchema = z.object({
14
+ conversationId: z.string().min(1),
15
+ });
16
+
17
+ export const listAntigravityWorkspacesFn = createServerFn({ method: 'GET' }).handler(async () => {
18
+ const { listAntigravityWorkspaceGroups } = await import('@spiracha/lib/antigravity-db');
19
+ return listAntigravityWorkspaceGroups();
20
+ });
21
+
22
+ export const getAntigravityDecryptionStateFn = createServerFn({ method: 'GET' }).handler(async () => {
23
+ const { getAntigravityDecryptionState } = await import('@spiracha/lib/antigravity-keychain');
24
+ return getAntigravityDecryptionState();
25
+ });
26
+
27
+ export const unlockAntigravityDecryptionFn = createServerFn({ method: 'POST' }).handler(async () => {
28
+ const { unlockAntigravityDecryption } = await import('@spiracha/lib/antigravity-keychain');
29
+ return unlockAntigravityDecryption();
30
+ });
31
+
32
+ export const listAntigravityConversationsFn = createServerFn({ method: 'GET' })
33
+ .validator(workspaceSchema)
34
+ .handler(async ({ data }) => {
35
+ const { listAntigravityConversationsForGroup } = await import('@spiracha/lib/antigravity-db');
36
+ return listAntigravityConversationsForGroup(data.workspaceKey);
37
+ });
38
+
39
+ const findAntigravityConversationById = async (conversationId: string) => {
40
+ const { listAntigravityConversations } = await import('@spiracha/lib/antigravity-db');
41
+ const conversation = (await listAntigravityConversations()).find(
42
+ (candidate) => candidate.conversationId === conversationId,
43
+ );
44
+ if (!conversation) {
45
+ throw new Error(`Antigravity conversation not found: ${conversationId}`);
46
+ }
47
+
48
+ return conversation;
49
+ };
50
+
51
+ export const loadAntigravityConversationDetail = async (conversationId: string) => {
52
+ const { renderAntigravityArtifactsMarkdown, renderAntigravityConversationMarkdown } = await import(
53
+ '@spiracha/lib/antigravity-db'
54
+ );
55
+ const { getCachedAntigravityKeychainSecret } = await import('@spiracha/lib/antigravity-keychain');
56
+ const conversation = await findAntigravityConversationById(conversationId);
57
+ const keychainSecret = getCachedAntigravityKeychainSecret();
58
+ const hasKeychainSecret = Boolean(keychainSecret);
59
+ const transcriptLocked = isAntigravityConversationLocked(conversation, hasKeychainSecret);
60
+ const conversationMarkdown = transcriptLocked
61
+ ? null
62
+ : await renderAntigravityConversationMarkdown(conversation, { keychainSecret });
63
+ const artifactsMarkdown =
64
+ conversation.artifactCount > 0 ? await renderAntigravityArtifactsMarkdown(conversation) : null;
65
+
66
+ return {
67
+ artifactsMarkdown,
68
+ conversation,
69
+ // Suppress the duplicate panel when artifactsMarkdown and conversationMarkdown are identical.
70
+ conversationMarkdown: conversationMarkdown === artifactsMarkdown ? null : conversationMarkdown,
71
+ transcriptLocked,
72
+ };
73
+ };
74
+
75
+ export const loadAntigravityConversationExport = async (conversationId: string) => {
76
+ const { renderAntigravityConversationMarkdown } = await import('@spiracha/lib/antigravity-db');
77
+ const { getCachedAntigravityKeychainSecret } = await import('@spiracha/lib/antigravity-keychain');
78
+ const conversation = await findAntigravityConversationById(conversationId);
79
+ const keychainSecret = getCachedAntigravityKeychainSecret();
80
+ const hasKeychainSecret = Boolean(keychainSecret);
81
+
82
+ if (!canExportAntigravityConversation(conversation, hasKeychainSecret)) {
83
+ if (isAntigravityConversationLocked(conversation, hasKeychainSecret)) {
84
+ throw new Error('Unlock Antigravity Keychain access before exporting transcript logs.');
85
+ }
86
+
87
+ throw new Error(`No exportable Antigravity transcript found for conversation: ${conversationId}`);
88
+ }
89
+
90
+ const content = await renderAntigravityConversationMarkdown(conversation, { keychainSecret });
91
+ if (!content) {
92
+ throw new Error(`No exportable Antigravity transcript found for conversation: ${conversationId}`);
93
+ }
94
+
95
+ return {
96
+ content,
97
+ filename: `${conversationId}.md`,
98
+ };
99
+ };
100
+
101
+ export const getAntigravityConversationDetailFn = createServerFn({ method: 'GET' })
102
+ .validator(conversationSchema)
103
+ .handler(async ({ data }) => {
104
+ return loadAntigravityConversationDetail(data.conversationId);
105
+ });
106
+
107
+ export const exportAntigravityArtifactsFn = createServerFn({ method: 'POST' })
108
+ .validator(exportSchema)
109
+ .handler(async ({ data }) => {
110
+ const { renderAntigravityArtifactsMarkdown } = await import('@spiracha/lib/antigravity-db');
111
+ const conversation = await findAntigravityConversationById(data.conversationId);
112
+
113
+ const content = await renderAntigravityArtifactsMarkdown(conversation);
114
+ if (!content) {
115
+ throw new Error(`No Markdown artifacts found for conversation: ${data.conversationId}`);
116
+ }
117
+
118
+ return {
119
+ content,
120
+ filename: `${data.conversationId}-artifacts.md`,
121
+ };
122
+ });
123
+
124
+ export const exportAntigravityConversationFn = createServerFn({ method: 'POST' })
125
+ .validator(exportSchema)
126
+ .handler(async ({ data }) => {
127
+ return loadAntigravityConversationExport(data.conversationId);
128
+ });
@@ -0,0 +1,335 @@
1
+ import type { ThreadEvent, ThreadTranscriptStats } from '@spiracha/lib/codex-browser-types';
2
+ import type { JsonValue } from '@spiracha/lib/shared';
3
+
4
+ type MarkdownSection = {
5
+ body: string;
6
+ heading: string;
7
+ sequence: number;
8
+ };
9
+
10
+ type ParsedAssistantSection = {
11
+ content: string;
12
+ thinking: string;
13
+ toolCalls: ParsedToolCall[];
14
+ };
15
+
16
+ type ParsedToolCall = {
17
+ argumentsText: string | null;
18
+ name: string;
19
+ };
20
+
21
+ const HEADING_PATTERN = /^##\s+(.+)$/u;
22
+ const TIMESTAMP_PATTERN = /^_Timestamp:\s*(.+?)_$/u;
23
+ const TOOL_HEADING_PATTERN = /^tool:\s*(.+)$/iu;
24
+
25
+ const splitMarkdownSections = (markdown: string | null): MarkdownSection[] => {
26
+ if (!markdown?.trim()) {
27
+ return [];
28
+ }
29
+
30
+ const sections: MarkdownSection[] = [];
31
+ const lines = markdown.split(/\r?\n/u);
32
+ let currentHeading: string | null = null;
33
+ let currentLines: string[] = [];
34
+
35
+ const flush = () => {
36
+ if (!currentHeading) {
37
+ return;
38
+ }
39
+
40
+ sections.push({
41
+ body: currentLines.join('\n').trim(),
42
+ heading: currentHeading,
43
+ sequence: sections.length * 10,
44
+ });
45
+ };
46
+
47
+ for (const line of lines) {
48
+ const heading = HEADING_PATTERN.exec(line);
49
+ if (heading) {
50
+ flush();
51
+ currentHeading = heading[1]!.trim();
52
+ currentLines = [];
53
+ continue;
54
+ }
55
+
56
+ if (currentHeading) {
57
+ currentLines.push(line);
58
+ }
59
+ }
60
+
61
+ flush();
62
+ return sections;
63
+ };
64
+
65
+ const extractTimestamp = (body: string): { body: string; timestamp: string | null } => {
66
+ const lines = body.split(/\r?\n/u);
67
+ const timestamp = TIMESTAMP_PATTERN.exec(lines[0]?.trim() ?? '')?.[1]?.trim() ?? null;
68
+ return {
69
+ body: timestamp ? lines.slice(1).join('\n').trim() : body.trim(),
70
+ timestamp,
71
+ };
72
+ };
73
+
74
+ const sectionBodyBeforeSubheading = (body: string): string => {
75
+ return body.split(/^###\s+/mu)[0]?.trim() ?? '';
76
+ };
77
+
78
+ const extractSubheadingBlock = (body: string, title: string): string => {
79
+ const lines = body.split(/\r?\n/u);
80
+ const startIndex = lines.findIndex((line) => line.trim().toLowerCase() === `### ${title.toLowerCase()}`);
81
+ if (startIndex === -1) {
82
+ return '';
83
+ }
84
+
85
+ const nextSubheadingIndex = lines.findIndex((line, index) => index > startIndex && line.startsWith('### '));
86
+ return lines
87
+ .slice(startIndex + 1, nextSubheadingIndex === -1 ? undefined : nextSubheadingIndex)
88
+ .join('\n')
89
+ .trim();
90
+ };
91
+
92
+ const parseToolCalls = (body: string): ParsedToolCall[] => {
93
+ const toolCallsBlock = extractSubheadingBlock(body, 'Tool Calls');
94
+ if (!toolCallsBlock) {
95
+ return [];
96
+ }
97
+
98
+ const calls: ParsedToolCall[] = [];
99
+ const callPattern = /-\s+`([^`]+)`(?:\s*\n+```json\s*\n([\s\S]*?)\n```)?/gu;
100
+ for (const match of toolCallsBlock.matchAll(callPattern)) {
101
+ calls.push({
102
+ argumentsText: match[2]?.trim() ?? null,
103
+ name: match[1]?.trim() || 'unknown',
104
+ });
105
+ }
106
+
107
+ return calls;
108
+ };
109
+
110
+ const parseAssistantSection = (body: string): ParsedAssistantSection => {
111
+ const content = sectionBodyBeforeSubheading(body);
112
+ const thinkingBlock = extractSubheadingBlock(body, 'Thinking');
113
+ const [thinking, ...remainingThinkingBlock] = thinkingBlock.split(/\n{2,}/u).map((entry) => entry.trim());
114
+
115
+ return {
116
+ content: content || remainingThinkingBlock.join('\n\n').trim(),
117
+ thinking: thinking ?? '',
118
+ toolCalls: parseToolCalls(body),
119
+ };
120
+ };
121
+
122
+ const buildRaw = (section: MarkdownSection, extra: Record<string, JsonValue> = {}): Record<string, JsonValue> => ({
123
+ heading: section.heading,
124
+ source: 'antigravity_markdown',
125
+ ...extra,
126
+ });
127
+
128
+ const buildMessageEvent = (
129
+ section: MarkdownSection,
130
+ role: string,
131
+ text: string,
132
+ timestamp: string | null,
133
+ phase: string | null,
134
+ sequenceOffset = 0,
135
+ ): ThreadEvent => ({
136
+ isHiddenByDefault: role !== 'assistant' && role !== 'user',
137
+ kind: 'message',
138
+ memoryCitation: null,
139
+ model: null,
140
+ phase,
141
+ raw: buildRaw(section, { role }),
142
+ role,
143
+ sequence: section.sequence + sequenceOffset,
144
+ text,
145
+ timestamp,
146
+ variant: role === 'user' ? 'user_message' : role === 'assistant' ? 'agent_message' : 'message',
147
+ });
148
+
149
+ const buildToolCallEvent = (
150
+ section: MarkdownSection,
151
+ toolCall: ParsedToolCall,
152
+ timestamp: string | null,
153
+ sequenceOffset: number,
154
+ ): ThreadEvent => ({
155
+ argumentsParseFailed: false,
156
+ argumentsText: toolCall.argumentsText,
157
+ callId: null,
158
+ command: [toolCall.name, toolCall.argumentsText].filter(Boolean).join('\n'),
159
+ kind: 'tool_call',
160
+ name: toolCall.name,
161
+ raw: buildRaw(section, {
162
+ argumentsText: toolCall.argumentsText,
163
+ name: toolCall.name,
164
+ }),
165
+ sequence: section.sequence + sequenceOffset,
166
+ timestamp,
167
+ workdir: null,
168
+ });
169
+
170
+ const buildToolOutputEvent = (
171
+ section: MarkdownSection,
172
+ toolName: string,
173
+ outputText: string,
174
+ timestamp: string | null,
175
+ ): ThreadEvent => ({
176
+ callId: null,
177
+ exitCode: null,
178
+ kind: 'tool_output',
179
+ outputText,
180
+ raw: buildRaw(section, {
181
+ name: toolName,
182
+ }),
183
+ sequence: section.sequence,
184
+ summary: outputText,
185
+ timestamp,
186
+ wallTime: null,
187
+ });
188
+
189
+ const getFinalAssistantSectionSequences = (sections: MarkdownSection[]): Set<number> => {
190
+ const finalAssistantSectionSequences = new Set<number>();
191
+ let currentAssistantContentSequence: number | null = null;
192
+
193
+ const flushAssistantRun = () => {
194
+ if (currentAssistantContentSequence !== null) {
195
+ finalAssistantSectionSequences.add(currentAssistantContentSequence);
196
+ }
197
+ currentAssistantContentSequence = null;
198
+ };
199
+
200
+ for (const section of sections) {
201
+ const heading = section.heading.toLowerCase();
202
+ if (heading === 'user') {
203
+ flushAssistantRun();
204
+ continue;
205
+ }
206
+
207
+ if (heading !== 'assistant') {
208
+ continue;
209
+ }
210
+
211
+ const { body } = extractTimestamp(section.body);
212
+ const parsed = parseAssistantSection(body);
213
+ if (parsed.toolCalls.length > 0) {
214
+ currentAssistantContentSequence = null;
215
+ } else if (parsed.content) {
216
+ currentAssistantContentSequence = section.sequence;
217
+ }
218
+ }
219
+
220
+ flushAssistantRun();
221
+ return finalAssistantSectionSequences;
222
+ };
223
+
224
+ const textSectionToEvents = (
225
+ section: MarkdownSection,
226
+ role: string,
227
+ body: string,
228
+ timestamp: string | null,
229
+ ): ThreadEvent[] => {
230
+ return body ? [buildMessageEvent(section, role, body, timestamp, null)] : [];
231
+ };
232
+
233
+ const toolOutputSectionToEvents = (
234
+ section: MarkdownSection,
235
+ toolName: string,
236
+ body: string,
237
+ timestamp: string | null,
238
+ ): ThreadEvent[] => {
239
+ return body ? [buildToolOutputEvent(section, toolName, body, timestamp)] : [];
240
+ };
241
+
242
+ const assistantSectionToEvents = (
243
+ section: MarkdownSection,
244
+ body: string,
245
+ timestamp: string | null,
246
+ finalAssistantSectionSequences: Set<number>,
247
+ ): ThreadEvent[] => {
248
+ const parsed = parseAssistantSection(body);
249
+ const events: ThreadEvent[] = [];
250
+ if (parsed.thinking) {
251
+ events.push(buildMessageEvent(section, 'assistant', parsed.thinking, timestamp, 'commentary'));
252
+ }
253
+ if (parsed.content) {
254
+ const phase = finalAssistantSectionSequences.has(section.sequence) ? 'final_answer' : 'commentary';
255
+ events.push(buildMessageEvent(section, 'assistant', parsed.content, timestamp, phase, 1));
256
+ }
257
+ parsed.toolCalls.forEach((toolCall, index) => {
258
+ events.push(buildToolCallEvent(section, toolCall, timestamp, 2 + index));
259
+ });
260
+ return events;
261
+ };
262
+
263
+ const sectionToEvents = (section: MarkdownSection, finalAssistantSectionSequences: Set<number>): ThreadEvent[] => {
264
+ const { body, timestamp } = extractTimestamp(section.body);
265
+ const heading = section.heading.toLowerCase();
266
+ const toolHeading = TOOL_HEADING_PATTERN.exec(section.heading);
267
+
268
+ if (heading === 'user') {
269
+ return textSectionToEvents(section, 'user', body, timestamp);
270
+ }
271
+
272
+ if (toolHeading) {
273
+ return toolOutputSectionToEvents(section, toolHeading[1]?.trim() || 'unknown', body, timestamp);
274
+ }
275
+
276
+ if (heading === 'assistant') {
277
+ return assistantSectionToEvents(section, body, timestamp, finalAssistantSectionSequences);
278
+ }
279
+
280
+ if (heading === 'system') {
281
+ return textSectionToEvents(section, 'system', body, timestamp);
282
+ }
283
+
284
+ return textSectionToEvents(section, 'event', body, timestamp);
285
+ };
286
+
287
+ export const antigravityMarkdownToThreadEvents = (markdown: string | null): ThreadEvent[] => {
288
+ const sections = splitMarkdownSections(markdown);
289
+ const finalAssistantSectionSequences = getFinalAssistantSectionSequences(sections);
290
+ return sections.flatMap((section) => sectionToEvents(section, finalAssistantSectionSequences));
291
+ };
292
+
293
+ const updateMessageStats = (stats: ThreadTranscriptStats, event: Extract<ThreadEvent, { kind: 'message' }>) => {
294
+ stats.messageCount += 1;
295
+ if (event.role === 'assistant') {
296
+ stats.assistantMessageCount += 1;
297
+ }
298
+ if (event.role === 'user') {
299
+ stats.userMessageCount += 1;
300
+ }
301
+ if (event.phase === 'commentary') {
302
+ stats.commentaryCount += 1;
303
+ }
304
+ if (event.phase === 'final_answer') {
305
+ stats.finalAnswerCount += 1;
306
+ }
307
+ };
308
+
309
+ export const getAntigravityThreadTranscriptStats = (events: ThreadEvent[]): ThreadTranscriptStats => {
310
+ const stats: ThreadTranscriptStats = {
311
+ assistantMessageCount: 0,
312
+ commentaryCount: 0,
313
+ execCommandCount: 0,
314
+ finalAnswerCount: 0,
315
+ messageCount: 0,
316
+ toolCallCount: 0,
317
+ toolOutputCount: 0,
318
+ userMessageCount: 0,
319
+ webSearchEventCount: 0,
320
+ };
321
+
322
+ for (const event of events) {
323
+ if (event.kind === 'message') {
324
+ updateMessageStats(stats, event);
325
+ }
326
+ if (event.kind === 'tool_call') {
327
+ stats.toolCallCount += 1;
328
+ }
329
+ if (event.kind === 'tool_output') {
330
+ stats.toolOutputCount += 1;
331
+ }
332
+ }
333
+
334
+ return stats;
335
+ };
@@ -0,0 +1,26 @@
1
+ import { queryOptions } from '@tanstack/react-query';
2
+ import {
3
+ getClaudeCodeSessionDetailFn,
4
+ listClaudeCodeSessionsFn,
5
+ listClaudeCodeWorkspacesFn,
6
+ } from './claude-code-server';
7
+
8
+ export const claudeCodeWorkspacesQueryOptions = () =>
9
+ queryOptions({
10
+ queryFn: () => listClaudeCodeWorkspacesFn(),
11
+ queryKey: ['claude-code-workspaces'],
12
+ });
13
+
14
+ export const claudeCodeSessionsQueryOptions = (workspaceKey: string | null) =>
15
+ queryOptions({
16
+ enabled: workspaceKey !== null,
17
+ queryFn: () => listClaudeCodeSessionsFn({ data: { workspaceKey: workspaceKey ?? '' } }),
18
+ queryKey: ['claude-code-sessions', workspaceKey ?? 'none'],
19
+ });
20
+
21
+ export const claudeCodeSessionDetailQueryOptions = (sessionId: string | null) =>
22
+ queryOptions({
23
+ enabled: sessionId !== null,
24
+ queryFn: () => getClaudeCodeSessionDetailFn({ data: { sessionId: sessionId ?? '' } }),
25
+ queryKey: ['claude-code-session', sessionId ?? 'none'],
26
+ });
@@ -0,0 +1,75 @@
1
+ import { createServerFn } from '@tanstack/react-start';
2
+ import { z } from 'zod';
3
+ import { renderSourceSessionDownload } from './source-session-export-server';
4
+
5
+ const workspaceSchema = z.object({
6
+ workspaceKey: z.string().min(1),
7
+ });
8
+
9
+ const sessionSchema = z.object({
10
+ sessionId: z.string().min(1),
11
+ });
12
+
13
+ const exportSessionSchema = z.object({
14
+ includeCommentary: z.boolean().default(true),
15
+ includeMetadata: z.boolean().default(true),
16
+ includeTools: z.boolean().default(true),
17
+ outputFormat: z.enum(['md', 'txt']).default('md'),
18
+ sessionId: z.string().min(1),
19
+ zipArchive: z.boolean().default(false),
20
+ });
21
+
22
+ export const listClaudeCodeWorkspacesFn = createServerFn({ method: 'GET' }).handler(async () => {
23
+ const { listClaudeCodeWorkspaceGroups } = await import('@spiracha/lib/claude-code-db');
24
+ return listClaudeCodeWorkspaceGroups();
25
+ });
26
+
27
+ export const listClaudeCodeSessionsFn = createServerFn({ method: 'GET' })
28
+ .validator(workspaceSchema)
29
+ .handler(async ({ data }) => {
30
+ const { listClaudeCodeSessionsForGroup } = await import('@spiracha/lib/claude-code-db');
31
+ return listClaudeCodeSessionsForGroup(data.workspaceKey);
32
+ });
33
+
34
+ const loadClaudeCodeSessionTranscript = async (sessionId: string) => {
35
+ const { readClaudeCodeSessionTranscript, resolveClaudeCodeProjectsDir } = await import(
36
+ '@spiracha/lib/claude-code-db'
37
+ );
38
+ const transcript = await readClaudeCodeSessionTranscript(resolveClaudeCodeProjectsDir(), sessionId);
39
+ if (!transcript) {
40
+ throw new Error(`Claude Code session not found: ${sessionId}`);
41
+ }
42
+
43
+ return transcript;
44
+ };
45
+
46
+ export const getClaudeCodeSessionDetailFn = createServerFn({ method: 'GET' })
47
+ .validator(sessionSchema)
48
+ .handler(async ({ data }) => {
49
+ return loadClaudeCodeSessionTranscript(data.sessionId);
50
+ });
51
+
52
+ export const exportClaudeCodeSessionFn = createServerFn({ method: 'POST' })
53
+ .validator(exportSessionSchema)
54
+ .handler(async ({ data }) => {
55
+ const { renderClaudeCodeTranscript } = await import('@spiracha/lib/claude-code-transcript');
56
+ const transcript = await loadClaudeCodeSessionTranscript(data.sessionId);
57
+ const content = renderClaudeCodeTranscript(transcript, {
58
+ includeCommentary: data.includeCommentary,
59
+ includeMetadata: data.includeMetadata,
60
+ includeTools: data.includeTools,
61
+ outputFormat: data.outputFormat,
62
+ });
63
+
64
+ if (!content) {
65
+ throw new Error(`Claude Code session has no exportable content: ${data.sessionId}`);
66
+ }
67
+
68
+ return renderSourceSessionDownload({
69
+ content,
70
+ fallbackBaseName: 'claude-code-session',
71
+ fileBaseName: transcript.session.title || transcript.session.sessionId,
72
+ outputFormat: data.outputFormat,
73
+ zipArchive: data.zipArchive,
74
+ });
75
+ });