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,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
+ }