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,16 @@
1
+ import packageJsonRaw from '../../../../package.json?raw';
2
+
3
+ type PackageMetadata = {
4
+ homepage: string;
5
+ version: string;
6
+ };
7
+
8
+ const parsePackageMetadata = (): PackageMetadata => {
9
+ const packageJson = JSON.parse(packageJsonRaw) as Partial<PackageMetadata>;
10
+ return {
11
+ homepage: typeof packageJson.homepage === 'string' ? packageJson.homepage : '',
12
+ version: typeof packageJson.version === 'string' ? packageJson.version : '0.0.0',
13
+ };
14
+ };
15
+
16
+ export const packageMetadata = parsePackageMetadata();
@@ -0,0 +1,13 @@
1
+ import { applyPathTransforms as applySharedPathTransforms } from '@spiracha/lib/path-transforms';
2
+ import type { Settings } from './settings-store';
3
+
4
+ export const applyPathTransforms = (
5
+ text: string,
6
+ settings: Pick<Settings, 'convertToProjectRoot' | 'redactUsername'>,
7
+ projectPath: string | null,
8
+ ) => {
9
+ return applySharedPathTransforms(text, {
10
+ ...settings,
11
+ projectPath,
12
+ });
13
+ };
@@ -0,0 +1,22 @@
1
+ import { queryOptions } from '@tanstack/react-query';
2
+ import { getQoderSessionDetailFn, listQoderSessionsFn, listQoderWorkspacesFn } from './qoder-server';
3
+
4
+ export const qoderWorkspacesQueryOptions = () =>
5
+ queryOptions({
6
+ queryFn: () => listQoderWorkspacesFn(),
7
+ queryKey: ['qoder-workspaces'],
8
+ });
9
+
10
+ export const qoderSessionsQueryOptions = (workspaceKey: string | null) =>
11
+ queryOptions({
12
+ enabled: workspaceKey !== null,
13
+ queryFn: () => listQoderSessionsFn({ data: { workspaceKey: workspaceKey ?? '' } }),
14
+ queryKey: ['qoder-sessions', workspaceKey ?? 'none'],
15
+ });
16
+
17
+ export const qoderSessionDetailQueryOptions = (sessionId: string | null) =>
18
+ queryOptions({
19
+ enabled: sessionId !== null,
20
+ queryFn: () => getQoderSessionDetailFn({ data: { sessionId: sessionId ?? '' } }),
21
+ queryKey: ['qoder-session', sessionId ?? 'none'],
22
+ });
@@ -0,0 +1,79 @@
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 listQoderWorkspacesFn = createServerFn({ method: 'GET' }).handler(async () => {
23
+ const { listQoderWorkspaceGroups } = await import('@spiracha/lib/qoder-db');
24
+ return listQoderWorkspaceGroups();
25
+ });
26
+
27
+ export const listQoderSessionsFn = createServerFn({ method: 'GET' })
28
+ .validator(workspaceSchema)
29
+ .handler(async ({ data }) => {
30
+ const { listQoderSessionsForGroup } = await import('@spiracha/lib/qoder-db');
31
+ return listQoderSessionsForGroup(data.workspaceKey);
32
+ });
33
+
34
+ const loadQoderSessionTranscript = async (sessionId: string) => {
35
+ const { readQoderSessionTranscript, resolveQoderGlobalStateDb, resolveQoderWorkspaceStorageDir } = await import(
36
+ '@spiracha/lib/qoder-db'
37
+ );
38
+ const transcript = await readQoderSessionTranscript(
39
+ resolveQoderGlobalStateDb(),
40
+ resolveQoderWorkspaceStorageDir(),
41
+ sessionId,
42
+ );
43
+ if (!transcript) {
44
+ throw new Error(`Qoder session not found: ${sessionId}`);
45
+ }
46
+
47
+ return transcript;
48
+ };
49
+
50
+ export const getQoderSessionDetailFn = createServerFn({ method: 'GET' })
51
+ .validator(sessionSchema)
52
+ .handler(async ({ data }) => {
53
+ return loadQoderSessionTranscript(data.sessionId);
54
+ });
55
+
56
+ export const exportQoderSessionFn = createServerFn({ method: 'POST' })
57
+ .validator(exportSessionSchema)
58
+ .handler(async ({ data }) => {
59
+ const { renderQoderTranscript } = await import('@spiracha/lib/qoder-transcript');
60
+ const transcript = await loadQoderSessionTranscript(data.sessionId);
61
+ const content = renderQoderTranscript(transcript, {
62
+ includeCommentary: data.includeCommentary,
63
+ includeMetadata: data.includeMetadata,
64
+ includeTools: data.includeTools,
65
+ outputFormat: data.outputFormat,
66
+ });
67
+
68
+ if (!content) {
69
+ throw new Error(`Qoder session has no exportable content: ${data.sessionId}`);
70
+ }
71
+
72
+ return renderSourceSessionDownload({
73
+ content,
74
+ fallbackBaseName: 'qoder-session',
75
+ fileBaseName: transcript.session.title || transcript.session.sessionId,
76
+ outputFormat: data.outputFormat,
77
+ zipArchive: data.zipArchive,
78
+ });
79
+ });
@@ -0,0 +1,139 @@
1
+ import type { ThreadEvent, ThreadTranscriptStats } from '@spiracha/lib/codex-browser-types';
2
+ import type {
3
+ QoderSessionTranscript,
4
+ QoderTranscriptEntry,
5
+ QoderTranscriptPart,
6
+ } from '@spiracha/lib/qoder-exporter-types';
7
+ import { getFinalQoderAssistantMessageEntryIds, getQoderMessagePhase } from '@spiracha/lib/qoder-transcript-phase';
8
+ import type { JsonValue } from '@spiracha/lib/shared';
9
+ import { getThreadTranscriptStats } from './thread-transcript-stats';
10
+
11
+ const buildRaw = (
12
+ entry: QoderTranscriptEntry,
13
+ part: QoderTranscriptPart,
14
+ eventType: string,
15
+ ): Record<string, JsonValue> => ({
16
+ entryId: entry.entryId,
17
+ eventType,
18
+ requestId: entry.requestId,
19
+ role: entry.role,
20
+ source: 'qoder_local_history',
21
+ type: part.type,
22
+ ...part.raw,
23
+ });
24
+
25
+ const buildMessageEvent = (
26
+ transcript: QoderSessionTranscript,
27
+ entry: QoderTranscriptEntry,
28
+ part: QoderTranscriptPart,
29
+ sequence: number,
30
+ text: string,
31
+ phase: Extract<ThreadEvent, { kind: 'message' }>['phase'],
32
+ ): ThreadEvent => ({
33
+ isHiddenByDefault: entry.role !== 'assistant' && entry.role !== 'user',
34
+ kind: 'message',
35
+ memoryCitation: null,
36
+ model: transcript.session.model ?? 'Qoder',
37
+ phase,
38
+ raw: buildRaw(entry, part, 'message'),
39
+ role: entry.role,
40
+ sequence,
41
+ text,
42
+ timestamp: entry.timestamp,
43
+ variant: entry.role === 'user' ? 'user_message' : entry.role === 'assistant' ? 'agent_message' : 'message',
44
+ });
45
+
46
+ const getPartString = (part: QoderTranscriptPart, key: string): string | null => {
47
+ const value = part.raw[key];
48
+ return typeof value === 'string' && value.trim() ? value : null;
49
+ };
50
+
51
+ const buildToolCallEvent = (
52
+ transcript: QoderSessionTranscript,
53
+ entry: QoderTranscriptEntry,
54
+ part: QoderTranscriptPart,
55
+ sequence: number,
56
+ command: string,
57
+ ): ThreadEvent => ({
58
+ argumentsParseFailed: false,
59
+ argumentsText: command,
60
+ callId: entry.entryId,
61
+ command,
62
+ kind: 'tool_call',
63
+ name: getPartString(part, 'toolName') ?? 'qoder_file_operation',
64
+ raw: buildRaw(entry, part, 'tool_call'),
65
+ sequence,
66
+ timestamp: entry.timestamp,
67
+ workdir: transcript.session.worktree,
68
+ });
69
+
70
+ const buildToolOutputEvent = (
71
+ entry: QoderTranscriptEntry,
72
+ part: QoderTranscriptPart,
73
+ sequence: number,
74
+ outputText: string,
75
+ ): ThreadEvent => ({
76
+ callId: getPartString(part, 'toolCallId'),
77
+ exitCode: null,
78
+ kind: 'tool_output',
79
+ outputText,
80
+ raw: buildRaw(entry, part, 'tool_output'),
81
+ sequence,
82
+ summary: outputText,
83
+ timestamp: entry.timestamp,
84
+ wallTime: null,
85
+ });
86
+
87
+ const partToEvents = (
88
+ transcript: QoderSessionTranscript,
89
+ entry: QoderTranscriptEntry,
90
+ part: QoderTranscriptPart,
91
+ sequence: number,
92
+ finalAssistantMessageEntryIds: Set<string>,
93
+ ): ThreadEvent[] => {
94
+ if (entry.entryType === 'tool_call' && part.type === 'text') {
95
+ const command = part.text?.trim();
96
+ return command ? [buildToolCallEvent(transcript, entry, part, sequence, command)] : [];
97
+ }
98
+
99
+ if (entry.entryType === 'tool_output' && part.type === 'text') {
100
+ const outputText = part.text?.trim();
101
+ return outputText ? [buildToolOutputEvent(entry, part, sequence, outputText)] : [];
102
+ }
103
+
104
+ if (part.type === 'text') {
105
+ const text = part.text?.trim();
106
+ return text
107
+ ? [
108
+ buildMessageEvent(
109
+ transcript,
110
+ entry,
111
+ part,
112
+ sequence,
113
+ text,
114
+ getQoderMessagePhase(entry, finalAssistantMessageEntryIds),
115
+ ),
116
+ ]
117
+ : [];
118
+ }
119
+
120
+ return [];
121
+ };
122
+
123
+ export const qoderTranscriptToThreadEvents = (transcript: QoderSessionTranscript): ThreadEvent[] => {
124
+ const events: ThreadEvent[] = [];
125
+ const finalAssistantMessageEntryIds = getFinalQoderAssistantMessageEntryIds(transcript.entries);
126
+ let sequence = 0;
127
+
128
+ for (const entry of transcript.entries) {
129
+ for (const part of entry.parts) {
130
+ events.push(...partToEvents(transcript, entry, part, sequence, finalAssistantMessageEntryIds));
131
+ sequence += 1;
132
+ }
133
+ }
134
+ return events;
135
+ };
136
+
137
+ export const getQoderThreadTranscriptStats = (events: ThreadEvent[]): ThreadTranscriptStats => {
138
+ return getThreadTranscriptStats(events);
139
+ };
@@ -0,0 +1,68 @@
1
+ export type TextQuerySearch = {
2
+ q?: string;
3
+ };
4
+
5
+ export type AnalyticsSearch = {
6
+ project?: string;
7
+ };
8
+
9
+ type SearchRecord = Record<string, unknown>;
10
+
11
+ const asNonBlankString = (value: unknown) => {
12
+ if (typeof value !== 'string') {
13
+ return undefined;
14
+ }
15
+
16
+ const trimmed = value.trim();
17
+ return trimmed.length > 0 ? trimmed : undefined;
18
+ };
19
+
20
+ export const parseTextQuerySearch = (search: SearchRecord): TextQuerySearch => {
21
+ const q = asNonBlankString(search.q);
22
+ return q ? { q } : {};
23
+ };
24
+
25
+ export const parseAnalyticsSearch = (search: SearchRecord): AnalyticsSearch => {
26
+ const project = asNonBlankString(search.project);
27
+ return project ? { project } : {};
28
+ };
29
+
30
+ export const withTextQuerySearch = (current: SearchRecord, query: string): SearchRecord & TextQuerySearch => {
31
+ const next = { ...current };
32
+ const q = asNonBlankString(query);
33
+ if (q) {
34
+ next.q = q;
35
+ } else {
36
+ delete next.q;
37
+ }
38
+
39
+ return next as SearchRecord & TextQuerySearch;
40
+ };
41
+
42
+ export const withAnalyticsProjectSearch = (
43
+ current: SearchRecord,
44
+ project: string | null,
45
+ ): SearchRecord & AnalyticsSearch => {
46
+ const next = { ...current };
47
+ const trimmedProject = asNonBlankString(project);
48
+ if (trimmedProject) {
49
+ next.project = trimmedProject;
50
+ } else {
51
+ delete next.project;
52
+ }
53
+
54
+ return next as SearchRecord & AnalyticsSearch;
55
+ };
56
+
57
+ const ALL_PROJECTS_SELECT_VALUE = '__all__';
58
+ const PROJECT_SELECT_PREFIX = 'project:';
59
+
60
+ export const encodeAnalyticsProjectSelectValue = (project: string | null) => {
61
+ return project ? `${PROJECT_SELECT_PREFIX}${project}` : ALL_PROJECTS_SELECT_VALUE;
62
+ };
63
+
64
+ export const decodeAnalyticsProjectSelectValue = (value: string) => {
65
+ return value === ALL_PROJECTS_SELECT_VALUE || !value.startsWith(PROJECT_SELECT_PREFIX)
66
+ ? null
67
+ : value.slice(PROJECT_SELECT_PREFIX.length);
68
+ };
@@ -0,0 +1,59 @@
1
+ import type { ReactNode } from 'react';
2
+ import { createContext, useContext, useEffect, useState } from 'react';
3
+
4
+ export type Settings = {
5
+ convertToProjectRoot: boolean;
6
+ redactUsername: boolean;
7
+ };
8
+
9
+ type SettingsContextValue = {
10
+ settings: Settings;
11
+ updateSetting: <K extends keyof Settings>(key: K, value: Settings[K]) => void;
12
+ };
13
+
14
+ const STORAGE_KEY = 'spiracha-settings';
15
+
16
+ const defaultSettings: Settings = {
17
+ convertToProjectRoot: false,
18
+ redactUsername: false,
19
+ };
20
+
21
+ const SettingsContext = createContext<SettingsContextValue>({
22
+ settings: defaultSettings,
23
+ updateSetting: () => {},
24
+ });
25
+
26
+ const loadSettings = (): Settings => {
27
+ if (typeof window === 'undefined') {
28
+ return defaultSettings;
29
+ }
30
+ try {
31
+ const stored = window.localStorage.getItem(STORAGE_KEY);
32
+ return stored ? { ...defaultSettings, ...(JSON.parse(stored) as Partial<Settings>) } : defaultSettings;
33
+ } catch {
34
+ return defaultSettings;
35
+ }
36
+ };
37
+
38
+ export function SettingsProvider({ children }: { children: ReactNode }) {
39
+ const [settings, setSettings] = useState<Settings>(defaultSettings);
40
+
41
+ // Load from localStorage on mount (client only — avoids SSR hydration mismatch)
42
+ useEffect(() => {
43
+ setSettings(loadSettings());
44
+ }, []);
45
+
46
+ const updateSetting = <K extends keyof Settings>(key: K, value: Settings[K]) => {
47
+ setSettings((prev) => {
48
+ const next = { ...prev, [key]: value };
49
+ try {
50
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(next));
51
+ } catch {}
52
+ return next;
53
+ });
54
+ };
55
+
56
+ return <SettingsContext.Provider value={{ settings, updateSetting }}>{children}</SettingsContext.Provider>;
57
+ }
58
+
59
+ export const useSettings = () => useContext(SettingsContext);
@@ -0,0 +1,56 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdtemp, rm } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { getExportMimeType, sanitizeExportFileName, zipExportDirectory } from '@spiracha/lib/ui-export-archive';
6
+ import { buildUiExportDownloadUrl, ensureUiExportDir } from '@spiracha/lib/ui-export-files';
7
+
8
+ type ExportFormat = 'md' | 'txt';
9
+
10
+ type RenderSourceSessionDownloadOptions = {
11
+ content: string;
12
+ fallbackBaseName: string;
13
+ fileBaseName: string;
14
+ outputFormat: ExportFormat;
15
+ zipArchive: boolean;
16
+ };
17
+
18
+ export const toSafeSourceExportName = (value: string, fallback: string) => {
19
+ return sanitizeExportFileName(value) || fallback;
20
+ };
21
+
22
+ export const renderSourceSessionDownload = async ({
23
+ content,
24
+ fallbackBaseName,
25
+ fileBaseName,
26
+ outputFormat,
27
+ zipArchive,
28
+ }: RenderSourceSessionDownloadOptions) => {
29
+ const safeBaseName = toSafeSourceExportName(fileBaseName, fallbackBaseName);
30
+ if (!zipArchive) {
31
+ return {
32
+ content,
33
+ fileName: `${safeBaseName}.${outputFormat}`,
34
+ mimeType: getExportMimeType(outputFormat),
35
+ mode: 'download' as const,
36
+ };
37
+ }
38
+
39
+ const exportDir = await ensureUiExportDir();
40
+ const workspaceDir = await mkdtemp(path.join(os.tmpdir(), `${safeBaseName}-`));
41
+ const zipPath = path.join(exportDir, `${safeBaseName}-${randomUUID()}.zip`);
42
+
43
+ try {
44
+ await Bun.write(path.join(workspaceDir, `${safeBaseName}.${outputFormat}`), content);
45
+ await zipExportDirectory(workspaceDir, zipPath);
46
+ } finally {
47
+ await rm(workspaceDir, { force: true, recursive: true });
48
+ }
49
+
50
+ return {
51
+ downloadUrl: buildUiExportDownloadUrl(zipPath),
52
+ fileName: `${safeBaseName}.zip`,
53
+ mimeType: 'application/zip',
54
+ mode: 'download_url' as const,
55
+ };
56
+ };
@@ -0,0 +1,22 @@
1
+ type SearchValue = boolean | number | string | null | undefined;
2
+
3
+ const normalizeSearchToken = (value: string) => value.trim().toLowerCase();
4
+
5
+ export const tokenizeSearchQuery = (query: string): string[] => {
6
+ const normalized = normalizeSearchToken(query);
7
+ return normalized ? normalized.split(/\s+/u).filter(Boolean) : [];
8
+ };
9
+
10
+ export const matchesTextQuery = (query: string, values: SearchValue[]): boolean => {
11
+ const tokens = tokenizeSearchQuery(query);
12
+ if (tokens.length === 0) {
13
+ return true;
14
+ }
15
+
16
+ const haystack = values
17
+ .filter((value) => value !== null && value !== undefined)
18
+ .map((value) => String(value).toLowerCase())
19
+ .join('\n');
20
+
21
+ return tokens.every((token) => haystack.includes(token));
22
+ };
@@ -0,0 +1,3 @@
1
+ const THREAD_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
2
+
3
+ export const isCodexThreadId = (value: string) => THREAD_ID_PATTERN.test(value);
@@ -0,0 +1,57 @@
1
+ import type { ThreadEvent, ThreadTranscriptStats } from '@spiracha/lib/codex-browser-types';
2
+
3
+ const EXEC_TOOL_NAMES = new Set(['bash', 'exec', 'execute', 'execute_command', 'run_command', 'shell', 'terminal']);
4
+
5
+ const isExecToolName = (name: string | null | undefined): boolean => {
6
+ return EXEC_TOOL_NAMES.has((name ?? '').trim().toLowerCase());
7
+ };
8
+
9
+ const updateMessageStats = (stats: ThreadTranscriptStats, event: Extract<ThreadEvent, { kind: 'message' }>) => {
10
+ stats.messageCount += 1;
11
+ if (event.role === 'assistant') {
12
+ stats.assistantMessageCount += 1;
13
+ }
14
+ if (event.role === 'user') {
15
+ stats.userMessageCount += 1;
16
+ }
17
+ if (event.phase === 'commentary') {
18
+ stats.commentaryCount += 1;
19
+ }
20
+ if (event.phase === 'final_answer') {
21
+ stats.finalAnswerCount += 1;
22
+ }
23
+ };
24
+
25
+ export const getThreadTranscriptStats = (events: ThreadEvent[]): ThreadTranscriptStats => {
26
+ const stats: ThreadTranscriptStats = {
27
+ assistantMessageCount: 0,
28
+ commentaryCount: 0,
29
+ execCommandCount: 0,
30
+ finalAnswerCount: 0,
31
+ messageCount: 0,
32
+ toolCallCount: 0,
33
+ toolOutputCount: 0,
34
+ userMessageCount: 0,
35
+ webSearchEventCount: 0,
36
+ };
37
+
38
+ for (const event of events) {
39
+ if (event.kind === 'message') {
40
+ updateMessageStats(stats, event);
41
+ }
42
+ if (event.kind === 'tool_call') {
43
+ stats.toolCallCount += 1;
44
+ if (isExecToolName(event.name)) {
45
+ stats.execCommandCount += 1;
46
+ }
47
+ }
48
+ if (event.kind === 'tool_output') {
49
+ stats.toolOutputCount += 1;
50
+ }
51
+ if (event.kind === 'web_search') {
52
+ stats.webSearchEventCount += 1;
53
+ }
54
+ }
55
+
56
+ return stats;
57
+ };
@@ -0,0 +1,7 @@
1
+ import type { ClassValue } from 'clsx';
2
+ import { clsx } from 'clsx';
3
+ import { twMerge } from 'tailwind-merge';
4
+
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs));
7
+ }