spiracha 1.4.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 (319) hide show
  1. package/AGENTS.md +116 -164
  2. package/README.md +92 -237
  3. package/apps/ui/AGENTS.md +36 -7
  4. package/apps/ui/README.md +79 -6
  5. package/apps/ui/components.json +21 -0
  6. package/apps/ui/package.json +65 -0
  7. package/apps/ui/{dist/client → public}/icon.svg +2 -1
  8. package/apps/ui/src/components/antigravity-conversations-table.tsx +206 -0
  9. package/apps/ui/src/components/antigravity-keychain-panel.tsx +76 -0
  10. package/apps/ui/src/components/antigravity-workspaces-table.tsx +63 -0
  11. package/apps/ui/src/components/app-shell.tsx +124 -0
  12. package/apps/ui/src/components/breadcrumbs.tsx +53 -0
  13. package/apps/ui/src/components/claude-code-sessions-table.tsx +114 -0
  14. package/apps/ui/src/components/claude-code-workspaces-table.tsx +55 -0
  15. package/apps/ui/src/components/cursor-threads-table.tsx +189 -0
  16. package/apps/ui/src/components/cursor-workspaces-table.tsx +140 -0
  17. package/apps/ui/src/components/data-table.tsx +241 -0
  18. package/apps/ui/src/components/delete-confirm-dialog.tsx +88 -0
  19. package/apps/ui/src/components/export-dialog.tsx +184 -0
  20. package/apps/ui/src/components/json-panel.tsx +17 -0
  21. package/apps/ui/src/components/kiro-sessions-table.tsx +112 -0
  22. package/apps/ui/src/components/kiro-workspaces-table.tsx +53 -0
  23. package/apps/ui/src/components/list-search-input.tsx +18 -0
  24. package/apps/ui/src/components/loading-panel.tsx +23 -0
  25. package/apps/ui/src/components/metadata-section.tsx +31 -0
  26. package/apps/ui/src/components/metric-card.tsx +19 -0
  27. package/apps/ui/src/components/opencode-sessions-table.tsx +128 -0
  28. package/apps/ui/src/components/opencode-workspaces-table.tsx +57 -0
  29. package/apps/ui/src/components/page-header.tsx +33 -0
  30. package/apps/ui/src/components/projects-loading-state.tsx +74 -0
  31. package/apps/ui/src/components/projects-table.tsx +108 -0
  32. package/apps/ui/src/components/qoder-sessions-table.tsx +112 -0
  33. package/apps/ui/src/components/qoder-workspaces-table.tsx +53 -0
  34. package/apps/ui/src/components/recent-threads-list.tsx +52 -0
  35. package/apps/ui/src/components/reload-error-panel.tsx +20 -0
  36. package/apps/ui/src/components/text-document-panel.tsx +19 -0
  37. package/apps/ui/src/components/theme-toggle.tsx +48 -0
  38. package/apps/ui/src/components/threads-table.tsx +202 -0
  39. package/apps/ui/src/components/transcript-view.tsx +552 -0
  40. package/apps/ui/src/components/ui/alert-dialog.tsx +160 -0
  41. package/apps/ui/src/components/ui/badge.tsx +45 -0
  42. package/apps/ui/src/components/ui/button.tsx +62 -0
  43. package/apps/ui/src/components/ui/checkbox.tsx +29 -0
  44. package/apps/ui/src/components/ui/dialog.tsx +137 -0
  45. package/apps/ui/src/components/ui/dropdown-menu.tsx +217 -0
  46. package/apps/ui/src/components/ui/input.tsx +21 -0
  47. package/apps/ui/src/components/ui/scroll-area.tsx +46 -0
  48. package/apps/ui/src/components/ui/select.tsx +163 -0
  49. package/apps/ui/src/components/ui/separator.tsx +28 -0
  50. package/apps/ui/src/components/ui/sheet.tsx +107 -0
  51. package/apps/ui/src/components/ui/skeleton.tsx +7 -0
  52. package/apps/ui/src/components/ui/table.tsx +76 -0
  53. package/apps/ui/src/components/ui/tabs.tsx +71 -0
  54. package/apps/ui/src/components/ui/tooltip.tsx +44 -0
  55. package/apps/ui/src/integrations/tanstack-query/devtools.tsx +6 -0
  56. package/apps/ui/src/integrations/tanstack-query/root-provider.tsx +10 -0
  57. package/apps/ui/src/lib/antigravity-conversation-state.ts +28 -0
  58. package/apps/ui/src/lib/antigravity-queries.ts +33 -0
  59. package/apps/ui/src/lib/antigravity-server.ts +128 -0
  60. package/apps/ui/src/lib/antigravity-transcript-events.ts +335 -0
  61. package/apps/ui/src/lib/claude-code-queries.ts +26 -0
  62. package/apps/ui/src/lib/claude-code-server.ts +75 -0
  63. package/apps/ui/src/lib/claude-code-transcript-events.ts +154 -0
  64. package/apps/ui/src/lib/codex-queries.ts +66 -0
  65. package/apps/ui/src/lib/codex-server.ts +209 -0
  66. package/apps/ui/src/lib/cursor-queries.ts +37 -0
  67. package/apps/ui/src/lib/cursor-server.ts +272 -0
  68. package/apps/ui/src/lib/cursor-transcript-events.ts +229 -0
  69. package/apps/ui/src/lib/download.ts +166 -0
  70. package/apps/ui/src/lib/formatters.ts +149 -0
  71. package/apps/ui/src/lib/kiro-queries.ts +22 -0
  72. package/apps/ui/src/lib/kiro-server.ts +73 -0
  73. package/apps/ui/src/lib/kiro-transcript-events.ts +113 -0
  74. package/apps/ui/src/lib/opencode-queries.ts +37 -0
  75. package/apps/ui/src/lib/opencode-server.ts +73 -0
  76. package/apps/ui/src/lib/opencode-transcript-events.ts +221 -0
  77. package/apps/ui/src/lib/package-metadata.ts +16 -0
  78. package/apps/ui/src/lib/path-utils.ts +13 -0
  79. package/apps/ui/src/lib/qoder-queries.ts +22 -0
  80. package/apps/ui/src/lib/qoder-server.ts +79 -0
  81. package/apps/ui/src/lib/qoder-transcript-events.ts +139 -0
  82. package/apps/ui/src/lib/route-search.ts +68 -0
  83. package/apps/ui/src/lib/settings-store.tsx +59 -0
  84. package/apps/ui/src/lib/source-session-export-server.ts +56 -0
  85. package/apps/ui/src/lib/text-filter.ts +22 -0
  86. package/apps/ui/src/lib/thread-id.ts +3 -0
  87. package/apps/ui/src/lib/thread-transcript-stats.ts +57 -0
  88. package/apps/ui/src/lib/utils.ts +7 -0
  89. package/apps/ui/src/routeTree.gen.ts +730 -0
  90. package/apps/ui/src/router.tsx +20 -0
  91. package/apps/ui/src/routes/$threadId.tsx +22 -0
  92. package/apps/ui/src/routes/__root.tsx +127 -0
  93. package/apps/ui/src/routes/analytics.tsx +143 -0
  94. package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +438 -0
  95. package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +127 -0
  96. package/apps/ui/src/routes/antigravity.index.tsx +51 -0
  97. package/apps/ui/src/routes/api.v1.conversation-query.ts +12 -0
  98. package/apps/ui/src/routes/api.v1.conversations.$source.$id.export.ts +12 -0
  99. package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +12 -0
  100. package/apps/ui/src/routes/api.v1.conversations.ts +12 -0
  101. package/apps/ui/src/routes/api.v1.resolve.ts +12 -0
  102. package/apps/ui/src/routes/api.v1.sources.ts +12 -0
  103. package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +342 -0
  104. package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +135 -0
  105. package/apps/ui/src/routes/claude-code.index.tsx +48 -0
  106. package/apps/ui/src/routes/codex.$project.tsx +390 -0
  107. package/apps/ui/src/routes/codex.index.tsx +116 -0
  108. package/apps/ui/src/routes/cursor-threads.$composerId.tsx +435 -0
  109. package/apps/ui/src/routes/cursor.$workspaceKey.tsx +416 -0
  110. package/apps/ui/src/routes/cursor.index.tsx +120 -0
  111. package/apps/ui/src/routes/index.tsx +124 -0
  112. package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +345 -0
  113. package/apps/ui/src/routes/kiro.$workspaceKey.tsx +136 -0
  114. package/apps/ui/src/routes/kiro.index.tsx +48 -0
  115. package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +334 -0
  116. package/apps/ui/src/routes/opencode.$workspaceKey.tsx +135 -0
  117. package/apps/ui/src/routes/opencode.index.tsx +48 -0
  118. package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +341 -0
  119. package/apps/ui/src/routes/qoder.$workspaceKey.tsx +139 -0
  120. package/apps/ui/src/routes/qoder.index.tsx +48 -0
  121. package/apps/ui/src/routes/settings.tsx +91 -0
  122. package/apps/ui/src/routes/threads.$threadId.tsx +619 -0
  123. package/apps/ui/src/styles.css +122 -0
  124. package/apps/ui/tsconfig.json +29 -0
  125. package/apps/ui/vite.config.ts +84 -0
  126. package/bin/spiracha.ts +32 -0
  127. package/package.json +50 -60
  128. package/src/client.ts +290 -0
  129. package/src/lib/antigravity-db.ts +213 -19
  130. package/src/lib/antigravity-exporter-types.ts +1 -0
  131. package/src/lib/claude-code-db.ts +655 -0
  132. package/src/lib/claude-code-exporter-types.ts +110 -0
  133. package/src/lib/claude-code-transcript-phase.ts +25 -0
  134. package/src/lib/claude-code-transcript.ts +180 -0
  135. package/src/lib/codex-analytics.ts +1 -1
  136. package/src/lib/codex-browser-db.ts +856 -61
  137. package/src/lib/codex-browser-export.ts +24 -16
  138. package/src/lib/codex-browser-types.ts +1 -1
  139. package/src/lib/codex-thread-cache.ts +17 -1
  140. package/src/lib/{codex-exporter-types.ts → codex-thread-types.ts} +2 -30
  141. package/src/lib/{codex-exporter-transcript.ts → codex-transcript-renderer.ts} +64 -28
  142. package/src/lib/concurrency.ts +25 -0
  143. package/src/lib/conversation-api.ts +792 -0
  144. package/src/lib/conversation-data/adapter-helpers.ts +110 -0
  145. package/src/lib/conversation-data/antigravity-adapter.ts +148 -0
  146. package/src/lib/conversation-data/claude-code-adapter.ts +175 -0
  147. package/src/lib/conversation-data/codex-adapter.ts +245 -0
  148. package/src/lib/conversation-data/cursor-adapter.ts +171 -0
  149. package/src/lib/conversation-data/index.ts +311 -0
  150. package/src/lib/conversation-data/kiro-adapter.ts +140 -0
  151. package/src/lib/conversation-data/message-selector.ts +37 -0
  152. package/src/lib/conversation-data/opencode-adapter.ts +180 -0
  153. package/src/lib/conversation-data/path-match.ts +79 -0
  154. package/src/lib/conversation-data/qoder-adapter.ts +230 -0
  155. package/src/lib/conversation-data/types.ts +116 -0
  156. package/src/lib/cursor-db.ts +67 -21
  157. package/src/lib/cursor-exporter-types.ts +0 -19
  158. package/src/lib/kiro-db.ts +949 -0
  159. package/src/lib/kiro-exporter-types.ts +100 -0
  160. package/src/lib/kiro-transcript-phase.ts +41 -0
  161. package/src/lib/kiro-transcript.ts +115 -0
  162. package/src/lib/opencode-db.ts +610 -0
  163. package/src/lib/opencode-exporter-types.ts +129 -0
  164. package/src/lib/opencode-think-tags.ts +126 -0
  165. package/src/lib/opencode-transcript-phase.ts +50 -0
  166. package/src/lib/opencode-transcript.ts +194 -0
  167. package/src/lib/qoder-acp-client.ts +268 -0
  168. package/src/lib/qoder-db.ts +1601 -0
  169. package/src/lib/qoder-exporter-types.ts +114 -0
  170. package/src/lib/qoder-transcript-phase.ts +41 -0
  171. package/src/lib/qoder-transcript.ts +112 -0
  172. package/src/lib/shared.ts +25 -0
  173. package/src/lib/ui-export-archive.ts +61 -0
  174. package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +0 -1
  175. package/apps/ui/dist/client/assets/analytics-DK2jdvmI.js +0 -1
  176. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-DmD0sN8X.js +0 -7
  177. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-KAcXtNxI.js +0 -1
  178. package/apps/ui/dist/client/assets/antigravity-keychain-panel-BRHVjFAM.js +0 -1
  179. package/apps/ui/dist/client/assets/antigravity._workspaceKey-ByitGWki.js +0 -1
  180. package/apps/ui/dist/client/assets/antigravity._workspaceKey-CGV7amas.js +0 -1
  181. package/apps/ui/dist/client/assets/antigravity.index-DEEkjlZa.js +0 -1
  182. package/apps/ui/dist/client/assets/antigravity.index-DgW25FEV.js +0 -1
  183. package/apps/ui/dist/client/assets/badge-DfWvPfKF.js +0 -1
  184. package/apps/ui/dist/client/assets/checkbox-CdHitXWQ.js +0 -1
  185. package/apps/ui/dist/client/assets/createServerFn-CgRRVpBH.js +0 -3
  186. package/apps/ui/dist/client/assets/cursor-threads._composerId-CmBFclK8.js +0 -1
  187. package/apps/ui/dist/client/assets/cursor-threads._composerId-Ti2gTm63.js +0 -1
  188. package/apps/ui/dist/client/assets/cursor._workspaceKey-CaAZjGmm.js +0 -1
  189. package/apps/ui/dist/client/assets/cursor._workspaceKey-DzD_c6j9.js +0 -1
  190. package/apps/ui/dist/client/assets/cursor.index-CrnMwDCi.js +0 -1
  191. package/apps/ui/dist/client/assets/cursor.index-PkCFVcl4.js +0 -2
  192. package/apps/ui/dist/client/assets/data-table-Br78_dk3.js +0 -4
  193. package/apps/ui/dist/client/assets/delete-confirm-dialog-BHRmyLHr.js +0 -11
  194. package/apps/ui/dist/client/assets/dist-B9pyYCVU.js +0 -1
  195. package/apps/ui/dist/client/assets/dist-BhZOxAPP.js +0 -1
  196. package/apps/ui/dist/client/assets/dist-DvMS2965.js +0 -1
  197. package/apps/ui/dist/client/assets/download-Bf0QJKD3.js +0 -1
  198. package/apps/ui/dist/client/assets/dropdown-menu-Dy5cLzTy.js +0 -1
  199. package/apps/ui/dist/client/assets/es2015-BkCWttyM.js +0 -41
  200. package/apps/ui/dist/client/assets/export-dialog-C86SYHJn.js +0 -1
  201. package/apps/ui/dist/client/assets/formatters-BM9kB7ed.js +0 -1
  202. package/apps/ui/dist/client/assets/index-CPvAP-jk.js +0 -149
  203. package/apps/ui/dist/client/assets/jsx-runtime-DGeXAQPT.js +0 -1
  204. package/apps/ui/dist/client/assets/metric-card-Dplm0ZiM.js +0 -1
  205. package/apps/ui/dist/client/assets/page-header-Cwa3p6Tl.js +0 -1
  206. package/apps/ui/dist/client/assets/projects._project-Ckf6muWZ.js +0 -1
  207. package/apps/ui/dist/client/assets/projects._project-DSDwH4NF.js +0 -1
  208. package/apps/ui/dist/client/assets/projects.index-DEfhWqa8.js +0 -1
  209. package/apps/ui/dist/client/assets/projects.index-V5ibNZII.js +0 -3
  210. package/apps/ui/dist/client/assets/react-dom-DL96Jor4.js +0 -1
  211. package/apps/ui/dist/client/assets/refresh-ccw-BgKjOiA6.js +0 -1
  212. package/apps/ui/dist/client/assets/reload-error-panel-AHqu0akK.js +0 -1
  213. package/apps/ui/dist/client/assets/routes-Df2tgpyd.js +0 -1
  214. package/apps/ui/dist/client/assets/scroll-text-fM0sMOB3.js +0 -1
  215. package/apps/ui/dist/client/assets/select-Bf2GwfPR.js +0 -1
  216. package/apps/ui/dist/client/assets/settings-5VQIzME0.js +0 -1
  217. package/apps/ui/dist/client/assets/sqlite-error-B6uZjUe8.js +0 -1
  218. package/apps/ui/dist/client/assets/styles-BhRkXgwB.css +0 -1
  219. package/apps/ui/dist/client/assets/tabs-OO4VU5KR.js +0 -7
  220. package/apps/ui/dist/client/assets/text-filter-DVAZySUS.js +0 -2
  221. package/apps/ui/dist/client/assets/threads._threadId-BB9tTsV4.js +0 -1
  222. package/apps/ui/dist/client/assets/threads._threadId-BgDhFj2I.js +0 -1
  223. package/apps/ui/dist/client/assets/useMutation-CC_B7uy5.js +0 -1
  224. package/apps/ui/dist/client/assets/useQuery-C5By6WKU.js +0 -1
  225. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CRW2kqj0.js +0 -232
  226. package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +0 -6
  227. package/apps/ui/dist/server/assets/analytics-CYP_LT5Y.js +0 -16
  228. package/apps/ui/dist/server/assets/analytics-CtpOMVMO.js +0 -146
  229. package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +0 -16
  230. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BtexWY-K.js +0 -613
  231. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +0 -11
  232. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-zMrR6v6R.js +0 -20
  233. package/apps/ui/dist/server/assets/antigravity-db-Bh8_U9uw.js +0 -580
  234. package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +0 -126
  235. package/apps/ui/dist/server/assets/antigravity-keychain-panel-CC7FLmAK.js +0 -55
  236. package/apps/ui/dist/server/assets/antigravity-queries-CGrJO9Vr.js +0 -37
  237. package/apps/ui/dist/server/assets/antigravity-server-CHRjVFqN.js +0 -114
  238. package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +0 -11
  239. package/apps/ui/dist/server/assets/antigravity._workspaceKey-B0QeYUOh.js +0 -28
  240. package/apps/ui/dist/server/assets/antigravity._workspaceKey-C3kP-qyN.js +0 -210
  241. package/apps/ui/dist/server/assets/antigravity.index-CPCYkqCi.js +0 -104
  242. package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +0 -11
  243. package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +0 -26
  244. package/apps/ui/dist/server/assets/button-CmTDnzOn.js +0 -46
  245. package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +0 -19
  246. package/apps/ui/dist/server/assets/codex-queries-CtgeZ7VL.js +0 -99
  247. package/apps/ui/dist/server/assets/codex-server-CNXSJuc2.js +0 -2004
  248. package/apps/ui/dist/server/assets/concurrency-VXtYvlGh.js +0 -18
  249. package/apps/ui/dist/server/assets/createServerRpc-CF_DEwnm.js +0 -12
  250. package/apps/ui/dist/server/assets/createSsrRpc-C754NPki.js +0 -16
  251. package/apps/ui/dist/server/assets/cursor-db-cYZEU3WQ.js +0 -830
  252. package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +0 -34
  253. package/apps/ui/dist/server/assets/cursor-queries-NCIM0Nat.js +0 -67
  254. package/apps/ui/dist/server/assets/cursor-recovery-nq-kR62j.js +0 -361
  255. package/apps/ui/dist/server/assets/cursor-server-C3q7hrp-.js +0 -213
  256. package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +0 -11
  257. package/apps/ui/dist/server/assets/cursor-threads._composerId-BPJFWfJj.js +0 -18
  258. package/apps/ui/dist/server/assets/cursor-threads._composerId-BkMMTQ3v.js +0 -582
  259. package/apps/ui/dist/server/assets/cursor-transcript-2iL3KFSK.js +0 -125
  260. package/apps/ui/dist/server/assets/cursor._workspaceKey-C5PdTaKB.js +0 -28
  261. package/apps/ui/dist/server/assets/cursor._workspaceKey-Ckj7apKI.js +0 -401
  262. package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +0 -11
  263. package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +0 -11
  264. package/apps/ui/dist/server/assets/cursor.index-DkWT-mxw.js +0 -189
  265. package/apps/ui/dist/server/assets/data-table-Cdct823O.js +0 -189
  266. package/apps/ui/dist/server/assets/delete-confirm-dialog-BcBNCxWB.js +0 -144
  267. package/apps/ui/dist/server/assets/download-DMmiy1xf.js +0 -92
  268. package/apps/ui/dist/server/assets/dropdown-menu-Dy_9t6TN.js +0 -36
  269. package/apps/ui/dist/server/assets/empty-plugin-adapters-B3lHh1La.js +0 -5
  270. package/apps/ui/dist/server/assets/export-dialog-BItjWgkZ.js +0 -240
  271. package/apps/ui/dist/server/assets/formatters-FJaGZgJk.js +0 -91
  272. package/apps/ui/dist/server/assets/loading-panel-BGFnWseS.js +0 -27
  273. package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +0 -23
  274. package/apps/ui/dist/server/assets/model-label-B1NWGc65.js +0 -13
  275. package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +0 -29
  276. package/apps/ui/dist/server/assets/path-transforms-DL2IwtYd.js +0 -31
  277. package/apps/ui/dist/server/assets/projects._project-Bpbc3C-L.js +0 -20
  278. package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +0 -12
  279. package/apps/ui/dist/server/assets/projects._project-CvZho6EQ.js +0 -395
  280. package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +0 -12
  281. package/apps/ui/dist/server/assets/projects.index-BkLiF2FF.js +0 -182
  282. package/apps/ui/dist/server/assets/projects.index-DesYXwfi.js +0 -14
  283. package/apps/ui/dist/server/assets/reload-error-panel-BJMxY3U1.js +0 -25
  284. package/apps/ui/dist/server/assets/route-search-ts4W9MJ9.js +0 -38
  285. package/apps/ui/dist/server/assets/router-6m-ihwqA.js +0 -410
  286. package/apps/ui/dist/server/assets/routes-Bsact1uB.js +0 -184
  287. package/apps/ui/dist/server/assets/routes-BzkJgq4W.js +0 -34
  288. package/apps/ui/dist/server/assets/select-GW76p-ld.js +0 -76
  289. package/apps/ui/dist/server/assets/settings-OayxIYQQ.js +0 -100
  290. package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +0 -52
  291. package/apps/ui/dist/server/assets/shared-CPRNYIql.js +0 -134
  292. package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +0 -13
  293. package/apps/ui/dist/server/assets/start-CI_0bSiY.js +0 -4
  294. package/apps/ui/dist/server/assets/tabs-CGA13IZM.js +0 -502
  295. package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +0 -36
  296. package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +0 -26
  297. package/apps/ui/dist/server/assets/threads._threadId-Bs0yuqO9.js +0 -18
  298. package/apps/ui/dist/server/assets/threads._threadId-D2GYkVn6.js +0 -639
  299. package/apps/ui/dist/server/assets/ui-export-files-BHLX9bhN.js +0 -83
  300. package/apps/ui/dist/server/assets/utils-C_uf36nf.js +0 -8
  301. package/apps/ui/dist/server/server.js +0 -5847
  302. package/bin/codex-chats-claude.js +0 -5
  303. package/bin/codex-chats.js +0 -5
  304. package/bin/spiracha.js +0 -5
  305. package/src/export-chats.ts +0 -120
  306. package/src/export-claude.ts +0 -36
  307. package/src/export-cursor.ts +0 -244
  308. package/src/lib/claude-exporter.ts +0 -864
  309. package/src/lib/codex-exporter-cli.ts +0 -277
  310. package/src/lib/codex-exporter-db.ts +0 -319
  311. package/src/lib/codex-exporter.ts +0 -115
  312. package/src/lib/cursor-exporter.ts +0 -266
  313. package/src/lib/interactive-cli.ts +0 -433
  314. package/src/lib/native-open.ts +0 -54
  315. package/src/mcp-server.ts +0 -137
  316. package/src/spiracha.ts +0 -116
  317. package/src/ui-cli.ts +0 -310
  318. /package/apps/ui/{dist/client → public}/manifest.json +0 -0
  319. /package/apps/ui/{dist/client → public}/robots.txt +0 -0
@@ -0,0 +1,390 @@
1
+ import type { ThreadListEntry } from '@spiracha/lib/codex-browser-types';
2
+ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
3
+ import { createFileRoute, useNavigate } from '@tanstack/react-router';
4
+ import { RefreshCcw } from 'lucide-react';
5
+ import { startTransition, useDeferredValue, useMemo, useState } from 'react';
6
+ import { DeleteConfirmDialog } from '#/components/delete-confirm-dialog';
7
+ import { ExportDialog } from '#/components/export-dialog';
8
+ import { ListSearchInput } from '#/components/list-search-input';
9
+ import { LoadingPanel } from '#/components/loading-panel';
10
+ import { PageHeader } from '#/components/page-header';
11
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
12
+ import { ThreadsTable } from '#/components/threads-table';
13
+ import { Button } from '#/components/ui/button';
14
+ import { projectThreadsQueryOptions } from '#/lib/codex-queries';
15
+ import {
16
+ deleteThreadFn,
17
+ deleteThreadsFn,
18
+ exportThreadFn,
19
+ exportThreadsFn,
20
+ recoverProjectThreadsFn,
21
+ } from '#/lib/codex-server';
22
+ import { downloadTextFile, downloadUrlFile } from '#/lib/download';
23
+ import { parseTextQuerySearch, withTextQuerySearch } from '#/lib/route-search';
24
+ import { useSettings } from '#/lib/settings-store';
25
+ import { matchesTextQuery } from '#/lib/text-filter';
26
+
27
+ type PendingThreadDelete = {
28
+ threads: ThreadListEntry[];
29
+ };
30
+
31
+ type PendingThreadExport = {
32
+ threadIds: string[];
33
+ threadLabel: string;
34
+ };
35
+
36
+ const shouldForceZipArchive = (pendingExport: PendingThreadExport | null) => {
37
+ return Boolean(pendingExport && pendingExport.threadIds.length > 1);
38
+ };
39
+
40
+ const getDeleteConfirmLabel = (pendingDelete: PendingThreadDelete | null, isPending: boolean) => {
41
+ if (isPending) {
42
+ return 'Deleting...';
43
+ }
44
+
45
+ if (pendingDelete && pendingDelete.threads.length > 1) {
46
+ return 'Delete threads';
47
+ }
48
+
49
+ return 'Delete thread';
50
+ };
51
+
52
+ const getDeleteDescription = (pendingDelete: PendingThreadDelete | null) => {
53
+ if (!pendingDelete) {
54
+ return '';
55
+ }
56
+
57
+ if (pendingDelete.threads.length === 1) {
58
+ return `Delete the thread "${pendingDelete.threads[0]!.thread.title}" from the Codex database. Leave Session files unchecked if you only want to remove the current DB row.`;
59
+ }
60
+
61
+ return `Delete ${pendingDelete.threads.length} selected threads from the Codex database. Enable Delete Session files if you also want to remove their rollout JSONL files.`;
62
+ };
63
+
64
+ const getDeleteTitle = (pendingDelete: PendingThreadDelete | null) => {
65
+ if (pendingDelete && pendingDelete.threads.length > 1) {
66
+ return `Delete ${pendingDelete.threads.length} Codex threads?`;
67
+ }
68
+
69
+ return 'Delete Codex thread?';
70
+ };
71
+
72
+ const decodeProjectParam = (project: string) => {
73
+ try {
74
+ return decodeURIComponent(project);
75
+ } catch {
76
+ return project;
77
+ }
78
+ };
79
+
80
+ export const Route = createFileRoute('/codex/$project')({
81
+ component: ProjectDetailPage,
82
+ errorComponent: ProjectDetailErrorComponent,
83
+ validateSearch: parseTextQuerySearch,
84
+ });
85
+
86
+ function ProjectDetailErrorComponent({ error }: { error: Error }) {
87
+ const isSqlite = error.message.includes('unable to open database') || error.message.includes('database is locked');
88
+ return (
89
+ <ReloadErrorPanel
90
+ description={
91
+ isSqlite ? 'Codex may have an exclusive lock on the database. Reload to retry.' : error.message
92
+ }
93
+ title={isSqlite ? 'Database unavailable' : 'Failed to load Codex project'}
94
+ />
95
+ );
96
+ }
97
+
98
+ function ProjectThreadsLoadingState({ project }: { project: string }) {
99
+ return (
100
+ <div aria-busy="true" aria-live="polite" className="space-y-6">
101
+ <PageHeader
102
+ eyebrow="Codex project"
103
+ subtitle="Loading project threads. Large local histories can take a moment."
104
+ title={project}
105
+ />
106
+ <div role="status">
107
+ <LoadingPanel description="Reading thread rows and rollout metadata." title="Loading threads" />
108
+ </div>
109
+ </div>
110
+ );
111
+ }
112
+
113
+ const toError = (error: unknown) => (error instanceof Error ? error : new Error(String(error)));
114
+
115
+ function ProjectDetailPage() {
116
+ const navigate = useNavigate({ from: Route.fullPath });
117
+ const params = Route.useParams();
118
+ const project = useMemo(() => decodeProjectParam(params.project), [params.project]);
119
+ const queryClient = useQueryClient();
120
+ const threadsQuery = useQuery(projectThreadsQueryOptions(project));
121
+ const threads = threadsQuery.data ?? [];
122
+ const { settings } = useSettings();
123
+ const search = Route.useSearch();
124
+ const searchInput = search.q ?? '';
125
+ const [pendingDelete, setPendingDelete] = useState<PendingThreadDelete | null>(null);
126
+ const [pendingExport, setPendingExport] = useState<PendingThreadExport | null>(null);
127
+ const deferredSearch = useDeferredValue(searchInput.trim().toLowerCase());
128
+
129
+ const deleteThreadMutation = useMutation({
130
+ mutationFn: (input: { deleteSessionFiles: boolean; threadIds: string[] }) => {
131
+ if (input.threadIds.length === 1) {
132
+ return deleteThreadFn({
133
+ data: {
134
+ deleteSessionFiles: input.deleteSessionFiles,
135
+ threadId: input.threadIds[0]!,
136
+ },
137
+ });
138
+ }
139
+
140
+ return deleteThreadsFn({ data: input });
141
+ },
142
+ onSuccess: async () => {
143
+ await Promise.all([
144
+ queryClient.invalidateQueries({ queryKey: ['analytics'] }),
145
+ queryClient.invalidateQueries({ queryKey: ['dashboard'] }),
146
+ queryClient.invalidateQueries({ queryKey: ['project-threads', project] }),
147
+ queryClient.invalidateQueries({ queryKey: ['projects'] }),
148
+ ]);
149
+ setPendingDelete(null);
150
+ },
151
+ });
152
+
153
+ const recoverProjectMutation = useMutation({
154
+ mutationFn: () =>
155
+ recoverProjectThreadsFn({
156
+ data: {
157
+ project,
158
+ },
159
+ }),
160
+ onSuccess: async () => {
161
+ await Promise.all([
162
+ queryClient.invalidateQueries({ queryKey: ['analytics'] }),
163
+ queryClient.invalidateQueries({ queryKey: ['dashboard'] }),
164
+ queryClient.invalidateQueries({ queryKey: ['project-threads', project] }),
165
+ queryClient.invalidateQueries({ queryKey: ['projects'] }),
166
+ ]);
167
+ },
168
+ });
169
+
170
+ const exportThreadMutation = useMutation({
171
+ mutationFn: async (options: {
172
+ includeCommentary: boolean;
173
+ includeTools: boolean;
174
+ includeMetadata: boolean;
175
+ outputFormat: 'md' | 'txt';
176
+ zipArchive: boolean;
177
+ }) => {
178
+ if (!pendingExport) {
179
+ throw new Error('No thread selected for export');
180
+ }
181
+
182
+ console.info('[spiracha:export-ui] request', {
183
+ outputFormat: options.outputFormat,
184
+ project,
185
+ selectedThreadCount: pendingExport.threadIds.length,
186
+ selectedThreadIds: pendingExport.threadIds,
187
+ zipArchive: options.zipArchive,
188
+ });
189
+
190
+ const download =
191
+ pendingExport.threadIds.length === 1
192
+ ? await exportThreadFn({
193
+ data: {
194
+ ...options,
195
+ ...settings,
196
+ threadId: pendingExport.threadIds[0]!,
197
+ },
198
+ })
199
+ : await exportThreadsFn({
200
+ data: {
201
+ ...options,
202
+ ...settings,
203
+ threadIds: pendingExport.threadIds,
204
+ },
205
+ });
206
+
207
+ console.info('[spiracha:export-ui] response', {
208
+ downloadUrl: download.mode === 'download_url' ? download.downloadUrl : null,
209
+ fileName: download.fileName,
210
+ mode: download.mode,
211
+ project,
212
+ selectedThreadCount: pendingExport.threadIds.length,
213
+ });
214
+
215
+ if (download.mode === 'download') {
216
+ downloadTextFile(download.fileName, download.content, download.mimeType);
217
+ return;
218
+ }
219
+
220
+ await downloadUrlFile(download.fileName, download.downloadUrl);
221
+ },
222
+ onError: (error) => {
223
+ console.error('[spiracha:export-ui] failed', {
224
+ error: error instanceof Error ? error.message : String(error),
225
+ project,
226
+ selectedThreadCount: pendingExport?.threadIds.length ?? 0,
227
+ selectedThreadIds: pendingExport?.threadIds ?? [],
228
+ });
229
+ },
230
+ onSuccess: () => {
231
+ setPendingExport(null);
232
+ },
233
+ });
234
+
235
+ const visibleThreads = useMemo(
236
+ () =>
237
+ threads.filter((thread) => {
238
+ return matchesTextQuery(deferredSearch, [
239
+ thread.thread.title,
240
+ thread.thread.preview,
241
+ thread.thread.model,
242
+ thread.thread.id,
243
+ ]);
244
+ }),
245
+ [deferredSearch, threads],
246
+ );
247
+ const visibleThreadsById = useMemo(
248
+ () => new Map(visibleThreads.map((thread) => [thread.thread.id, thread])),
249
+ [visibleThreads],
250
+ );
251
+ const updateSearchInput = (value: string) => {
252
+ startTransition(() => {
253
+ void navigate({
254
+ params: true,
255
+ replace: true,
256
+ search: (previous: Record<string, unknown>) => withTextQuerySearch(previous, value),
257
+ });
258
+ });
259
+ };
260
+
261
+ const lookupSelectedThreads = (threadIds: string[]) => {
262
+ return threadIds
263
+ .map((threadId) => visibleThreadsById.get(threadId) ?? null)
264
+ .filter((thread): thread is ThreadListEntry => thread !== null);
265
+ };
266
+
267
+ if (threadsQuery.isLoading) {
268
+ return <ProjectThreadsLoadingState project={project} />;
269
+ }
270
+
271
+ if (threadsQuery.isError) {
272
+ return <ProjectDetailErrorComponent error={toError(threadsQuery.error)} />;
273
+ }
274
+
275
+ return (
276
+ <div aria-busy={threadsQuery.isFetching || undefined} className="space-y-6">
277
+ <PageHeader
278
+ actions={
279
+ <div className="flex flex-col gap-2 sm:flex-row">
280
+ <Button
281
+ className="rounded-full"
282
+ disabled={recoverProjectMutation.isPending}
283
+ type="button"
284
+ variant="outline"
285
+ onClick={() => recoverProjectMutation.mutate()}
286
+ >
287
+ <RefreshCcw className="mr-2 size-4" />
288
+ {recoverProjectMutation.isPending ? 'Recovering...' : 'Recover'}
289
+ </Button>
290
+ <ListSearchInput
291
+ placeholder="Search thread title, preview, or model"
292
+ value={searchInput}
293
+ onValueChange={updateSearchInput}
294
+ />
295
+ </div>
296
+ }
297
+ eyebrow="Codex project"
298
+ subtitle="Sort by any column, inspect tool call volume, manage thread records, or repair stale Codex thread metadata for this derived project."
299
+ title={project}
300
+ />
301
+
302
+ {threadsQuery.isFetching && !threadsQuery.isLoading ? (
303
+ <p role="status" className="text-[var(--muted-foreground)] text-sm">
304
+ Refreshing project threads...
305
+ </p>
306
+ ) : null}
307
+
308
+ {recoverProjectMutation.isError ? (
309
+ <p className="text-[var(--destructive)] text-sm">
310
+ {recoverProjectMutation.error instanceof Error
311
+ ? recoverProjectMutation.error.message
312
+ : 'Project recovery failed'}
313
+ </p>
314
+ ) : null}
315
+
316
+ {recoverProjectMutation.isSuccess ? (
317
+ <p className="text-[var(--success)] text-sm">Project thread metadata recovery completed.</p>
318
+ ) : null}
319
+
320
+ <ThreadsTable
321
+ threads={visibleThreads}
322
+ onDeleteThread={(thread) => setPendingDelete({ threads: [thread] })}
323
+ onDeleteThreads={(threadIds) => {
324
+ const selectedThreads = lookupSelectedThreads(threadIds);
325
+ if (selectedThreads.length === 0) {
326
+ return;
327
+ }
328
+
329
+ setPendingDelete({ threads: selectedThreads });
330
+ }}
331
+ onExportThread={(thread) =>
332
+ setPendingExport({
333
+ threadIds: [thread.thread.id],
334
+ threadLabel: thread.thread.title,
335
+ })
336
+ }
337
+ onExportThreads={(threadIds) => {
338
+ const selectedThreads = lookupSelectedThreads(threadIds);
339
+ if (selectedThreads.length === 0) {
340
+ return;
341
+ }
342
+
343
+ setPendingExport({
344
+ threadIds: selectedThreads.map((thread) => thread.thread.id),
345
+ threadLabel:
346
+ selectedThreads.length === 1
347
+ ? selectedThreads[0]!.thread.title
348
+ : `${selectedThreads.length} selected threads`,
349
+ });
350
+ }}
351
+ />
352
+
353
+ <DeleteConfirmDialog
354
+ confirmLabel={getDeleteConfirmLabel(pendingDelete, deleteThreadMutation.isPending)}
355
+ defaultDeleteSessionFiles
356
+ description={getDeleteDescription(pendingDelete)}
357
+ open={pendingDelete !== null}
358
+ showDeleteSessionFilesOption
359
+ title={getDeleteTitle(pendingDelete)}
360
+ onConfirm={({ deleteSessionFiles }) => {
361
+ if (!pendingDelete) {
362
+ return;
363
+ }
364
+ deleteThreadMutation.mutate({
365
+ deleteSessionFiles,
366
+ threadIds: pendingDelete.threads.map((thread) => thread.thread.id),
367
+ });
368
+ }}
369
+ onOpenChange={(open) => {
370
+ if (!open) {
371
+ setPendingDelete(null);
372
+ }
373
+ }}
374
+ />
375
+
376
+ <ExportDialog
377
+ forceZipArchive={shouldForceZipArchive(pendingExport)}
378
+ open={pendingExport !== null}
379
+ pending={exportThreadMutation.isPending}
380
+ title={pendingExport ? `Export ${pendingExport.threadLabel}` : 'Export thread'}
381
+ onExport={(options) => exportThreadMutation.mutate(options)}
382
+ onOpenChange={(open) => {
383
+ if (!open) {
384
+ setPendingExport(null);
385
+ }
386
+ }}
387
+ />
388
+ </div>
389
+ );
390
+ }
@@ -0,0 +1,116 @@
1
+ import type { ProjectSummary } from '@spiracha/lib/codex-browser-types';
2
+ import { useMutation, useQueryClient, useSuspenseQuery } from '@tanstack/react-query';
3
+ import { createFileRoute, useNavigate } from '@tanstack/react-router';
4
+ import { startTransition, useDeferredValue, useState } from 'react';
5
+ import { DeleteConfirmDialog } from '#/components/delete-confirm-dialog';
6
+ import { ListSearchInput } from '#/components/list-search-input';
7
+ import { PageHeader } from '#/components/page-header';
8
+ import { ProjectsLoadingState } from '#/components/projects-loading-state';
9
+ import { ProjectsTable } from '#/components/projects-table';
10
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
11
+ import { projectsQueryOptions } from '#/lib/codex-queries';
12
+ import { deleteProjectFn } from '#/lib/codex-server';
13
+ import { parseTextQuerySearch, withTextQuerySearch } from '#/lib/route-search';
14
+ import { matchesTextQuery } from '#/lib/text-filter';
15
+
16
+ export const Route = createFileRoute('/codex/')({
17
+ component: ProjectsPage,
18
+ errorComponent: ProjectsErrorComponent,
19
+ loader: ({ context }) => context.queryClient.ensureQueryData(projectsQueryOptions()),
20
+ pendingComponent: ProjectsLoadingState,
21
+ validateSearch: parseTextQuerySearch,
22
+ });
23
+
24
+ function ProjectsErrorComponent({ error }: { error: Error }) {
25
+ const isSqlite = error.message.includes('unable to open database') || error.message.includes('database is locked');
26
+ return (
27
+ <ReloadErrorPanel
28
+ description={
29
+ isSqlite ? 'Codex may have an exclusive lock on the database. Reload to retry.' : error.message
30
+ }
31
+ title={isSqlite ? 'Database unavailable' : 'Failed to load Codex inventory'}
32
+ />
33
+ );
34
+ }
35
+
36
+ function ProjectsPage() {
37
+ const navigate = useNavigate({ from: Route.fullPath });
38
+ const queryClient = useQueryClient();
39
+ const projects = useSuspenseQuery(projectsQueryOptions()).data;
40
+ const search = Route.useSearch();
41
+ const searchInput = search.q ?? '';
42
+ const [pendingDelete, setPendingDelete] = useState<ProjectSummary | null>(null);
43
+ const deferredSearch = useDeferredValue(searchInput.trim().toLowerCase());
44
+
45
+ const deleteProjectMutation = useMutation({
46
+ mutationFn: (input: { deleteSessionFiles: boolean; project: string }) => deleteProjectFn({ data: input }),
47
+ onSuccess: async () => {
48
+ await Promise.all([
49
+ queryClient.invalidateQueries({ queryKey: ['analytics'] }),
50
+ queryClient.invalidateQueries({ queryKey: ['dashboard'] }),
51
+ queryClient.invalidateQueries({ queryKey: ['projects'] }),
52
+ ]);
53
+ setPendingDelete(null);
54
+ },
55
+ });
56
+
57
+ const visibleProjects = projects.filter((project) => {
58
+ return matchesTextQuery(deferredSearch, [
59
+ project.name,
60
+ project.cwdPaths.join('\n'),
61
+ project.modelNames.join('\n'),
62
+ ]);
63
+ });
64
+
65
+ return (
66
+ <div className="space-y-6">
67
+ <PageHeader
68
+ actions={
69
+ <ListSearchInput
70
+ placeholder="Search project name, cwd, or model"
71
+ value={searchInput}
72
+ onValueChange={(value) => {
73
+ startTransition(() => {
74
+ void navigate({
75
+ replace: true,
76
+ search: (previous: Record<string, unknown>) => withTextQuerySearch(previous, value),
77
+ });
78
+ });
79
+ }}
80
+ />
81
+ }
82
+ eyebrow="Inventory"
83
+ subtitle="Derived projects are grouped from the final basename of each thread cwd, matching the existing CLI behavior."
84
+ title="Codex"
85
+ />
86
+
87
+ <ProjectsTable projects={visibleProjects} onDeleteProject={setPendingDelete} />
88
+
89
+ <DeleteConfirmDialog
90
+ confirmLabel={deleteProjectMutation.isPending ? 'Deleting...' : 'Delete project'}
91
+ description={
92
+ pendingDelete
93
+ ? `Delete ${pendingDelete.threadCount} thread records for the derived project "${pendingDelete.name}" from the Codex database. Enable Delete Session files to remove the rollout JSONL files too.`
94
+ : ''
95
+ }
96
+ open={pendingDelete !== null}
97
+ showDeleteSessionFilesOption
98
+ title="Delete Codex project?"
99
+ onConfirm={({ deleteSessionFiles }) => {
100
+ if (!pendingDelete) {
101
+ return;
102
+ }
103
+ deleteProjectMutation.mutate({
104
+ deleteSessionFiles,
105
+ project: pendingDelete.name,
106
+ });
107
+ }}
108
+ onOpenChange={(open) => {
109
+ if (!open) {
110
+ setPendingDelete(null);
111
+ }
112
+ }}
113
+ />
114
+ </div>
115
+ );
116
+ }