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,12 @@
1
+ import { createFileRoute } from '@tanstack/react-router';
2
+
3
+ export const Route = createFileRoute('/api/v1/resolve')({
4
+ server: {
5
+ handlers: {
6
+ GET: async ({ request }) => {
7
+ const { handleConversationApiRequest } = await import('@spiracha/lib/conversation-api');
8
+ return handleConversationApiRequest(request);
9
+ },
10
+ },
11
+ },
12
+ });
@@ -0,0 +1,12 @@
1
+ import { createFileRoute } from '@tanstack/react-router';
2
+
3
+ export const Route = createFileRoute('/api/v1/sources')({
4
+ server: {
5
+ handlers: {
6
+ GET: async ({ request }) => {
7
+ const { handleConversationApiRequest } = await import('@spiracha/lib/conversation-api');
8
+ return handleConversationApiRequest(request);
9
+ },
10
+ },
11
+ },
12
+ });
@@ -0,0 +1,342 @@
1
+ import type { ClaudeCodeSessionTranscript } from '@spiracha/lib/claude-code-exporter-types';
2
+ import type { ThreadEvent, ThreadTranscriptStats } from '@spiracha/lib/codex-browser-types';
3
+ import { useMutation, useSuspenseQuery } from '@tanstack/react-query';
4
+ import { createFileRoute, Link } from '@tanstack/react-router';
5
+ import { Download } from 'lucide-react';
6
+ import { useMemo, useState } from 'react';
7
+ import { Breadcrumbs } from '#/components/breadcrumbs';
8
+ import { ExportDialog } from '#/components/export-dialog';
9
+ import { JsonPanel } from '#/components/json-panel';
10
+ import { LoadingPanel } from '#/components/loading-panel';
11
+ import { MetadataSection } from '#/components/metadata-section';
12
+ import { MetricCard } from '#/components/metric-card';
13
+ import { PageHeader } from '#/components/page-header';
14
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
15
+ import { TranscriptView } from '#/components/transcript-view';
16
+ import { Button } from '#/components/ui/button';
17
+ import { Checkbox } from '#/components/ui/checkbox';
18
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '#/components/ui/tabs';
19
+ import { claudeCodeSessionDetailQueryOptions } from '#/lib/claude-code-queries';
20
+ import { exportClaudeCodeSessionFn } from '#/lib/claude-code-server';
21
+ import {
22
+ claudeCodeTranscriptToThreadEvents,
23
+ getClaudeCodeThreadTranscriptStats,
24
+ } from '#/lib/claude-code-transcript-events';
25
+ import { downloadTextFile, downloadUrlFile } from '#/lib/download';
26
+ import { formatDateTime, formatList, formatNumber, formatTokens } from '#/lib/formatters';
27
+
28
+ type ExportDialogOptions = {
29
+ includeCommentary: boolean;
30
+ includeMetadata: boolean;
31
+ includeTools: boolean;
32
+ outputFormat: 'md' | 'txt';
33
+ zipArchive: boolean;
34
+ };
35
+
36
+ type TranscriptControlsProps = {
37
+ rawJsonDisabled?: boolean;
38
+ showCommentary: boolean;
39
+ showExtraEvents: boolean;
40
+ showRawJson: boolean;
41
+ showToolCalls: boolean;
42
+ showUserMessages: boolean;
43
+ onShowCommentaryChange: (checked: boolean) => void;
44
+ onShowExtraEventsChange: (checked: boolean) => void;
45
+ onShowRawJsonChange: (checked: boolean) => void;
46
+ onShowToolCallsChange: (checked: boolean) => void;
47
+ onShowUserMessagesChange: (checked: boolean) => void;
48
+ };
49
+
50
+ export const Route = createFileRoute('/claude-code-sessions/$sessionId')({
51
+ component: ClaudeCodeSessionDetailPage,
52
+ errorComponent: ClaudeCodeSessionDetailErrorComponent,
53
+ loader: ({ context, params }) =>
54
+ context.queryClient.ensureQueryData(claudeCodeSessionDetailQueryOptions(params.sessionId)),
55
+ pendingComponent: () => (
56
+ <LoadingPanel
57
+ description="Loading the Claude Code transcript, messages, tool calls, and session metadata."
58
+ title="Loading session"
59
+ />
60
+ ),
61
+ });
62
+
63
+ function ClaudeCodeSessionDetailErrorComponent({ error }: { error: Error }) {
64
+ return <ReloadErrorPanel description={error.message} title="Failed to load Claude Code session" />;
65
+ }
66
+
67
+ const buildSessionMetadata = (detail: ClaudeCodeSessionTranscript) => [
68
+ { label: 'Session ID', value: <span data-mono="true">{detail.session.sessionId}</span> },
69
+ {
70
+ label: 'Workspace',
71
+ value: (
72
+ <Link
73
+ className="text-[var(--accent)]"
74
+ params={{ workspaceKey: detail.session.workspaceKey }}
75
+ to="/claude-code/$workspaceKey"
76
+ >
77
+ {detail.session.workspaceLabel}
78
+ </Link>
79
+ ),
80
+ },
81
+ { label: 'Worktree', value: detail.session.worktree },
82
+ { label: 'CWD', value: detail.session.cwd },
83
+ { label: 'Model', value: detail.session.model ?? 'unknown' },
84
+ { label: 'Version', value: detail.session.version ?? 'unknown' },
85
+ { label: 'Git branch', value: detail.session.gitBranch ?? 'unknown' },
86
+ { label: 'Created', value: <span suppressHydrationWarning>{formatDateTime(detail.session.createdAtMs)}</span> },
87
+ {
88
+ label: 'Last active',
89
+ value: <span suppressHydrationWarning>{formatDateTime(detail.session.lastActiveAtMs)}</span>,
90
+ },
91
+ { label: 'Source file', value: detail.session.filePath },
92
+ ];
93
+
94
+ const buildTranscriptStatsItems = (
95
+ detail: ClaudeCodeSessionTranscript,
96
+ events: ThreadEvent[],
97
+ stats: ThreadTranscriptStats,
98
+ ) => [
99
+ { label: 'Event kinds', value: formatList([...new Set(events.map((event) => event.kind))]) },
100
+ { label: 'Messages', value: formatNumber(stats.messageCount) },
101
+ { label: 'User messages', value: formatNumber(stats.userMessageCount) },
102
+ { label: 'Assistant messages', value: formatNumber(stats.assistantMessageCount) },
103
+ { label: 'Reasoning events', value: formatNumber(events.filter((event) => event.kind === 'reasoning').length) },
104
+ { label: 'Final answers', value: formatNumber(stats.finalAnswerCount) },
105
+ { label: 'Tool calls', value: formatNumber(stats.toolCallCount) },
106
+ { label: 'Tool outputs', value: formatNumber(stats.toolOutputCount) },
107
+ { label: 'Attachments', value: formatNumber(detail.session.attachmentCount) },
108
+ { label: 'Renderable parts', value: formatNumber(detail.renderablePartCount) },
109
+ ];
110
+
111
+ const ClaudeCodeTranscriptControls = ({
112
+ rawJsonDisabled = false,
113
+ showCommentary,
114
+ showExtraEvents,
115
+ showRawJson,
116
+ showToolCalls,
117
+ showUserMessages,
118
+ onShowCommentaryChange,
119
+ onShowExtraEventsChange,
120
+ onShowRawJsonChange,
121
+ onShowToolCallsChange,
122
+ onShowUserMessagesChange,
123
+ }: TranscriptControlsProps) => {
124
+ return (
125
+ <div className="flex flex-wrap gap-4 rounded-xl border border-[var(--border)] bg-[var(--panel)] px-4 py-3 shadow-[var(--panel-shadow)]">
126
+ <div className="flex items-center gap-2 text-sm">
127
+ <Checkbox
128
+ checked={showToolCalls}
129
+ id="claude-code-transcript-show-tool-calls"
130
+ onCheckedChange={(checked) => onShowToolCallsChange(checked === true)}
131
+ />
132
+ <label htmlFor="claude-code-transcript-show-tool-calls">Show tool calls</label>
133
+ </div>
134
+ <div className="flex items-center gap-2 text-sm">
135
+ <Checkbox
136
+ checked={showCommentary}
137
+ id="claude-code-transcript-show-commentary"
138
+ onCheckedChange={(checked) => onShowCommentaryChange(checked === true)}
139
+ />
140
+ <label htmlFor="claude-code-transcript-show-commentary">Show commentary</label>
141
+ </div>
142
+ <div className="flex items-center gap-2 text-sm">
143
+ <Checkbox
144
+ checked={showExtraEvents}
145
+ id="claude-code-transcript-show-extra-events"
146
+ onCheckedChange={(checked) => onShowExtraEventsChange(checked === true)}
147
+ />
148
+ <label htmlFor="claude-code-transcript-show-extra-events">Show extra events</label>
149
+ </div>
150
+ <div className="flex items-center gap-2 text-sm">
151
+ <Checkbox
152
+ checked={showRawJson}
153
+ disabled={rawJsonDisabled}
154
+ id="claude-code-transcript-show-raw-json"
155
+ onCheckedChange={(checked) => onShowRawJsonChange(checked === true)}
156
+ />
157
+ <label htmlFor="claude-code-transcript-show-raw-json">Raw JSON</label>
158
+ </div>
159
+ <div className="flex items-center gap-2 text-sm">
160
+ <Checkbox
161
+ checked={showUserMessages}
162
+ id="claude-code-transcript-show-user-messages"
163
+ onCheckedChange={(checked) => onShowUserMessagesChange(checked === true)}
164
+ />
165
+ <label htmlFor="claude-code-transcript-show-user-messages">User</label>
166
+ </div>
167
+ </div>
168
+ );
169
+ };
170
+
171
+ function ClaudeCodeRawPanels({ detail, events }: { detail: ClaudeCodeSessionTranscript; events: ThreadEvent[] }) {
172
+ return (
173
+ <div className="space-y-4">
174
+ <JsonPanel title="Session summary" value={detail.session} />
175
+ <JsonPanel title="Claude Code entries" value={detail.entries} />
176
+ <JsonPanel title="Raw JSONL events" value={detail.rawEvents} />
177
+ <JsonPanel title="Transcript events" value={events} />
178
+ </div>
179
+ );
180
+ }
181
+
182
+ function ClaudeCodeSessionDetailPage() {
183
+ const detail = useSuspenseQuery(claudeCodeSessionDetailQueryOptions(Route.useParams().sessionId)).data;
184
+ const [pendingExport, setPendingExport] = useState(false);
185
+ const [showToolCalls, setShowToolCalls] = useState(false);
186
+ const [showCommentary, setShowCommentary] = useState(false);
187
+ const [showExtraEvents, setShowExtraEvents] = useState(false);
188
+ const [showRawJson, setShowRawJson] = useState(false);
189
+ const [showUserMessages, setShowUserMessages] = useState(true);
190
+ const transcriptEvents = useMemo(() => claudeCodeTranscriptToThreadEvents(detail), [detail]);
191
+ const transcriptStats = useMemo(() => getClaudeCodeThreadTranscriptStats(transcriptEvents), [transcriptEvents]);
192
+
193
+ const exportSessionMutation = useMutation({
194
+ mutationFn: async (options: ExportDialogOptions) => {
195
+ const download = await exportClaudeCodeSessionFn({
196
+ data: {
197
+ includeCommentary: options.includeCommentary,
198
+ includeMetadata: options.includeMetadata,
199
+ includeTools: options.includeTools,
200
+ outputFormat: options.outputFormat,
201
+ sessionId: detail.session.sessionId,
202
+ zipArchive: options.zipArchive,
203
+ },
204
+ });
205
+ if (download.mode === 'download') {
206
+ downloadTextFile(download.fileName, download.content, download.mimeType);
207
+ return;
208
+ }
209
+
210
+ await downloadUrlFile(download.fileName, download.downloadUrl);
211
+ },
212
+ onSuccess: () => {
213
+ setPendingExport(false);
214
+ },
215
+ });
216
+
217
+ return (
218
+ <div className="space-y-6">
219
+ <PageHeader
220
+ actions={
221
+ <Button
222
+ className="rounded-full"
223
+ type="button"
224
+ variant="outline"
225
+ onClick={() => setPendingExport(true)}
226
+ >
227
+ <Download className="mr-2 size-4" />
228
+ Export
229
+ </Button>
230
+ }
231
+ breadcrumb={
232
+ <Breadcrumbs
233
+ items={[
234
+ { label: 'Claude Code', to: '/claude-code' },
235
+ {
236
+ label: detail.session.workspaceLabel,
237
+ params: { workspaceKey: detail.session.workspaceKey },
238
+ to: '/claude-code/$workspaceKey',
239
+ },
240
+ { label: detail.session.title },
241
+ ]}
242
+ />
243
+ }
244
+ eyebrow="Claude Code session"
245
+ subtitle="Session detail for the selected Claude Code project conversation."
246
+ title={detail.session.title}
247
+ />
248
+
249
+ <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
250
+ <MetricCard label="Messages" value={formatNumber(detail.session.messageCount)} />
251
+ <MetricCard label="Tool calls" value={formatNumber(detail.session.toolCallCount)} />
252
+ <MetricCard label="Tool outputs" value={formatNumber(detail.session.toolResultCount)} />
253
+ <MetricCard label="Tokens" value={formatTokens(detail.session.totalTokens)} />
254
+ </div>
255
+
256
+ <Tabs className="space-y-4" defaultValue="transcript">
257
+ <TabsList className="grid w-fit min-w-[24rem] grid-cols-3 rounded-full border border-[var(--border)] bg-[var(--panel)] p-1">
258
+ <TabsTrigger className="rounded-full px-5 text-sm" value="transcript">
259
+ Transcript
260
+ </TabsTrigger>
261
+ <TabsTrigger className="rounded-full px-5 text-sm" value="metadata">
262
+ Metadata
263
+ </TabsTrigger>
264
+ <TabsTrigger className="rounded-full px-5 text-sm" value="raw">
265
+ Raw
266
+ </TabsTrigger>
267
+ </TabsList>
268
+
269
+ <TabsContent className="space-y-3" value="transcript">
270
+ <ClaudeCodeTranscriptControls
271
+ rawJsonDisabled={transcriptEvents.length === 0}
272
+ showCommentary={showCommentary}
273
+ showExtraEvents={showExtraEvents}
274
+ showRawJson={showRawJson}
275
+ showToolCalls={showToolCalls}
276
+ showUserMessages={showUserMessages}
277
+ onShowCommentaryChange={setShowCommentary}
278
+ onShowExtraEventsChange={setShowExtraEvents}
279
+ onShowRawJsonChange={setShowRawJson}
280
+ onShowToolCallsChange={setShowToolCalls}
281
+ onShowUserMessagesChange={setShowUserMessages}
282
+ />
283
+ {transcriptEvents.length > 0 ? (
284
+ <TranscriptView
285
+ assistantModel={detail.session.model}
286
+ events={transcriptEvents}
287
+ projectPath={detail.session.worktree}
288
+ showCommentary={showCommentary}
289
+ showExtraEvents={showExtraEvents}
290
+ showRawJson={showRawJson}
291
+ showToolCalls={showToolCalls}
292
+ showUserMessages={showUserMessages}
293
+ />
294
+ ) : (
295
+ <section className="rounded-[1.6rem] border border-[var(--border)] bg-[var(--panel)] p-5 shadow-[var(--panel-shadow)]">
296
+ <h3 className="font-semibold text-[var(--muted-foreground)] text-sm uppercase tracking-[0.18em]">
297
+ Transcript
298
+ </h3>
299
+ <p className="mt-4 text-[var(--muted-foreground)] text-sm">
300
+ No renderable Claude Code transcript content was found for this session.
301
+ </p>
302
+ </section>
303
+ )}
304
+ </TabsContent>
305
+
306
+ <TabsContent value="metadata">
307
+ <div className="grid gap-4 xl:grid-cols-[0.95fr_1.05fr]">
308
+ <MetadataSection items={buildSessionMetadata(detail)} title="Session metadata" />
309
+ <MetadataSection
310
+ items={buildTranscriptStatsItems(detail, transcriptEvents, transcriptStats)}
311
+ title="Transcript stats"
312
+ />
313
+ </div>
314
+ </TabsContent>
315
+
316
+ <TabsContent value="raw">
317
+ <ClaudeCodeRawPanels detail={detail} events={transcriptEvents} />
318
+ </TabsContent>
319
+ </Tabs>
320
+
321
+ <ExportDialog
322
+ errorMessage={
323
+ exportSessionMutation.isError
324
+ ? exportSessionMutation.error instanceof Error
325
+ ? exportSessionMutation.error.message
326
+ : 'Export failed'
327
+ : null
328
+ }
329
+ open={pendingExport}
330
+ pending={exportSessionMutation.isPending}
331
+ title={`Export ${detail.session.title}`}
332
+ onExport={(options) => exportSessionMutation.mutate(options)}
333
+ onOpenChange={(open) => {
334
+ setPendingExport(open);
335
+ if (!open) {
336
+ exportSessionMutation.reset();
337
+ }
338
+ }}
339
+ />
340
+ </div>
341
+ );
342
+ }
@@ -0,0 +1,135 @@
1
+ import type { ClaudeCodeSessionSummary, ClaudeCodeWorkspaceGroup } from '@spiracha/lib/claude-code-exporter-types';
2
+ import { useMutation, useSuspenseQuery } from '@tanstack/react-query';
3
+ import { createFileRoute } from '@tanstack/react-router';
4
+ import { useDeferredValue, useState } from 'react';
5
+ import { ClaudeCodeSessionsTable } from '#/components/claude-code-sessions-table';
6
+ import { ExportDialog } from '#/components/export-dialog';
7
+ import { ListSearchInput } from '#/components/list-search-input';
8
+ import { LoadingPanel } from '#/components/loading-panel';
9
+ import { PageHeader } from '#/components/page-header';
10
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
11
+ import { claudeCodeSessionsQueryOptions, claudeCodeWorkspacesQueryOptions } from '#/lib/claude-code-queries';
12
+ import { exportClaudeCodeSessionFn } from '#/lib/claude-code-server';
13
+ import { downloadTextFile, downloadUrlFile } from '#/lib/download';
14
+ import { matchesTextQuery } from '#/lib/text-filter';
15
+
16
+ type ExportDialogOptions = {
17
+ includeCommentary: boolean;
18
+ includeMetadata: boolean;
19
+ includeTools: boolean;
20
+ outputFormat: 'md' | 'txt';
21
+ zipArchive: boolean;
22
+ };
23
+
24
+ const findWorkspaceOrThrow = (workspaces: ClaudeCodeWorkspaceGroup[], workspaceKey: string) => {
25
+ const workspace = workspaces.find((candidate) => candidate.key === workspaceKey);
26
+ if (!workspace) {
27
+ throw new Error(`Claude Code workspace not found: ${workspaceKey}`);
28
+ }
29
+
30
+ return workspace;
31
+ };
32
+
33
+ export const Route = createFileRoute('/claude-code/$workspaceKey')({
34
+ component: ClaudeCodeWorkspacePage,
35
+ errorComponent: ClaudeCodeWorkspaceErrorComponent,
36
+ loader: async ({ context, params }) => {
37
+ const workspaces = await context.queryClient.ensureQueryData(claudeCodeWorkspacesQueryOptions());
38
+ findWorkspaceOrThrow(workspaces, params.workspaceKey);
39
+ await context.queryClient.ensureQueryData(claudeCodeSessionsQueryOptions(params.workspaceKey));
40
+ },
41
+ pendingComponent: () => (
42
+ <LoadingPanel description="Loading Claude Code sessions and transcript metadata." title="Loading workspace" />
43
+ ),
44
+ });
45
+
46
+ function ClaudeCodeWorkspaceErrorComponent({ error }: { error: Error }) {
47
+ return <ReloadErrorPanel description={error.message} title="Failed to load Claude Code workspace" />;
48
+ }
49
+
50
+ function ClaudeCodeWorkspacePage() {
51
+ const params = Route.useParams();
52
+ const workspaces = useSuspenseQuery(claudeCodeWorkspacesQueryOptions()).data;
53
+ const workspace = findWorkspaceOrThrow(workspaces, params.workspaceKey);
54
+ const sessions = useSuspenseQuery(claudeCodeSessionsQueryOptions(workspace.key)).data;
55
+ const [searchInput, setSearchInput] = useState('');
56
+ const [pendingExport, setPendingExport] = useState<ClaudeCodeSessionSummary | null>(null);
57
+ const deferredSearch = useDeferredValue(searchInput);
58
+
59
+ const exportMutation = useMutation({
60
+ mutationFn: async (options: ExportDialogOptions) => {
61
+ if (!pendingExport) {
62
+ throw new Error('No Claude Code session selected for export');
63
+ }
64
+
65
+ const download = await exportClaudeCodeSessionFn({
66
+ data: {
67
+ includeCommentary: options.includeCommentary,
68
+ includeMetadata: options.includeMetadata,
69
+ includeTools: options.includeTools,
70
+ outputFormat: options.outputFormat,
71
+ sessionId: pendingExport.sessionId,
72
+ zipArchive: options.zipArchive,
73
+ },
74
+ });
75
+ if (download.mode === 'download') {
76
+ downloadTextFile(download.fileName, download.content, download.mimeType);
77
+ return;
78
+ }
79
+
80
+ await downloadUrlFile(download.fileName, download.downloadUrl);
81
+ },
82
+ onSuccess: () => {
83
+ setPendingExport(null);
84
+ },
85
+ });
86
+
87
+ const visibleSessions = sessions.filter((session) =>
88
+ matchesTextQuery(deferredSearch, [
89
+ session.title,
90
+ session.sessionId,
91
+ session.model,
92
+ session.version,
93
+ session.gitBranch,
94
+ session.filePath,
95
+ ]),
96
+ );
97
+
98
+ return (
99
+ <div className="space-y-6">
100
+ <PageHeader
101
+ actions={
102
+ <ListSearchInput
103
+ placeholder="Search session title, id, model, or version"
104
+ value={searchInput}
105
+ onValueChange={setSearchInput}
106
+ />
107
+ }
108
+ eyebrow="Claude Code workspace"
109
+ subtitle="Inspect local Claude Code sessions, user prompts, assistant responses, tool calls, and token totals."
110
+ title={workspace.label}
111
+ />
112
+
113
+ <ClaudeCodeSessionsTable sessions={visibleSessions} onExportSession={setPendingExport} />
114
+
115
+ <ExportDialog
116
+ open={pendingExport !== null}
117
+ pending={exportMutation.isPending}
118
+ title={pendingExport ? `Export ${pendingExport.title}` : 'Export session'}
119
+ onExport={(options) => exportMutation.mutate(options)}
120
+ onOpenChange={(open) => {
121
+ if (!open) {
122
+ setPendingExport(null);
123
+ exportMutation.reset();
124
+ }
125
+ }}
126
+ />
127
+
128
+ {exportMutation.isError ? (
129
+ <p className="text-[var(--destructive)] text-sm">
130
+ {exportMutation.error instanceof Error ? exportMutation.error.message : 'Session export failed'}
131
+ </p>
132
+ ) : null}
133
+ </div>
134
+ );
135
+ }
@@ -0,0 +1,48 @@
1
+ import { useSuspenseQuery } from '@tanstack/react-query';
2
+ import { createFileRoute } from '@tanstack/react-router';
3
+ import { useDeferredValue, useState } from 'react';
4
+ import { ClaudeCodeWorkspacesTable } from '#/components/claude-code-workspaces-table';
5
+ import { ListSearchInput } from '#/components/list-search-input';
6
+ import { PageHeader } from '#/components/page-header';
7
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
8
+ import { claudeCodeWorkspacesQueryOptions } from '#/lib/claude-code-queries';
9
+ import { matchesTextQuery } from '#/lib/text-filter';
10
+
11
+ export const Route = createFileRoute('/claude-code/')({
12
+ component: ClaudeCodePage,
13
+ errorComponent: ClaudeCodeErrorComponent,
14
+ loader: ({ context }) => context.queryClient.ensureQueryData(claudeCodeWorkspacesQueryOptions()),
15
+ });
16
+
17
+ function ClaudeCodeErrorComponent({ error }: { error: Error }) {
18
+ return <ReloadErrorPanel description={error.message} title="Failed to load Claude Code workspaces" />;
19
+ }
20
+
21
+ function ClaudeCodePage() {
22
+ const workspaces = useSuspenseQuery(claudeCodeWorkspacesQueryOptions()).data;
23
+ const [searchInput, setSearchInput] = useState('');
24
+ const deferredSearch = useDeferredValue(searchInput);
25
+
26
+ const visibleWorkspaces = workspaces.filter((workspace) =>
27
+ matchesTextQuery(deferredSearch, [workspace.label, workspace.worktree, workspace.key, workspace.directoryName]),
28
+ );
29
+
30
+ return (
31
+ <div className="space-y-6">
32
+ <PageHeader
33
+ actions={
34
+ <ListSearchInput
35
+ placeholder="Search workspace name or path"
36
+ value={searchInput}
37
+ onValueChange={setSearchInput}
38
+ />
39
+ }
40
+ eyebrow="Inventory"
41
+ subtitle="Workspace groups are derived from local Claude Code project JSONL transcripts."
42
+ title="Claude Code"
43
+ />
44
+
45
+ <ClaudeCodeWorkspacesTable workspaces={visibleWorkspaces} />
46
+ </div>
47
+ );
48
+ }