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,438 @@
1
+ import { useMutation, useSuspenseQuery } from '@tanstack/react-query';
2
+ import { createFileRoute, Link } from '@tanstack/react-router';
3
+ import { Download, ScrollText } from 'lucide-react';
4
+ import { useMemo, useState } from 'react';
5
+ import { AntigravityKeychainPanel } from '#/components/antigravity-keychain-panel';
6
+ import { Breadcrumbs } from '#/components/breadcrumbs';
7
+ import { JsonPanel } from '#/components/json-panel';
8
+ import { LoadingPanel } from '#/components/loading-panel';
9
+ import { MetadataSection } from '#/components/metadata-section';
10
+ import { MetricCard } from '#/components/metric-card';
11
+ import { PageHeader } from '#/components/page-header';
12
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
13
+ import { TextDocumentPanel } from '#/components/text-document-panel';
14
+ import { TranscriptView } from '#/components/transcript-view';
15
+ import { Button } from '#/components/ui/button';
16
+ import { Checkbox } from '#/components/ui/checkbox';
17
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '#/components/ui/tabs';
18
+ import { canExportAntigravityConversation } from '#/lib/antigravity-conversation-state';
19
+ import {
20
+ antigravityConversationDetailQueryOptions,
21
+ antigravityDecryptionQueryOptions,
22
+ } from '#/lib/antigravity-queries';
23
+ import {
24
+ exportAntigravityArtifactsFn,
25
+ exportAntigravityConversationFn,
26
+ type getAntigravityConversationDetailFn,
27
+ } from '#/lib/antigravity-server';
28
+ import {
29
+ antigravityMarkdownToThreadEvents,
30
+ getAntigravityThreadTranscriptStats,
31
+ } from '#/lib/antigravity-transcript-events';
32
+ import { downloadTextFile } from '#/lib/download';
33
+ import { formatBytes, formatDateTime, formatNumber } from '#/lib/formatters';
34
+
35
+ type AntigravityConversationDetail = Awaited<ReturnType<typeof getAntigravityConversationDetailFn>>;
36
+
37
+ type TranscriptControlsProps = {
38
+ rawJsonDisabled?: boolean;
39
+ showCommentary: boolean;
40
+ showExtraEvents: boolean;
41
+ showRawJson: boolean;
42
+ showToolCalls: boolean;
43
+ showUserMessages: boolean;
44
+ onShowCommentaryChange: (checked: boolean) => void;
45
+ onShowExtraEventsChange: (checked: boolean) => void;
46
+ onShowRawJsonChange: (checked: boolean) => void;
47
+ onShowToolCallsChange: (checked: boolean) => void;
48
+ onShowUserMessagesChange: (checked: boolean) => void;
49
+ };
50
+
51
+ const buildConversationMetadata = (detail: AntigravityConversationDetail) => {
52
+ return [
53
+ { label: 'Conversation ID', value: <span data-mono="true">{detail.conversation.conversationId}</span> },
54
+ {
55
+ label: 'Workspace',
56
+ value: (
57
+ <Link
58
+ className="text-[var(--accent)]"
59
+ params={{ workspaceKey: detail.conversation.workspaceKey }}
60
+ to="/antigravity/$workspaceKey"
61
+ >
62
+ {detail.conversation.workspaceLabel}
63
+ </Link>
64
+ ),
65
+ },
66
+ {
67
+ label: 'Created',
68
+ value: <span suppressHydrationWarning>{formatDateTime(detail.conversation.createdAtMs)}</span>,
69
+ },
70
+ {
71
+ label: 'Updated',
72
+ value: <span suppressHydrationWarning>{formatDateTime(detail.conversation.lastUpdatedAtMs)}</span>,
73
+ },
74
+ { label: 'Transcript source', value: detail.conversation.transcriptSource ?? 'n/a' },
75
+ { label: 'Conversation path', value: detail.conversation.conversationPath ?? 'n/a' },
76
+ { label: 'Transcript path', value: detail.conversation.transcriptPath ?? 'n/a' },
77
+ { label: 'Summary path', value: detail.conversation.summaryPath ?? 'n/a' },
78
+ { label: 'Source root', value: detail.conversation.sourceRoot ?? 'n/a' },
79
+ ];
80
+ };
81
+
82
+ const buildTranscriptStatsItems = (
83
+ detail: AntigravityConversationDetail,
84
+ events: ReturnType<typeof antigravityMarkdownToThreadEvents>,
85
+ ) => {
86
+ if (detail.transcriptLocked) {
87
+ return [
88
+ { label: 'Transcript load', value: 'Transcript is locked until Antigravity Keychain access is enabled.' },
89
+ ];
90
+ }
91
+
92
+ if (!detail.conversationMarkdown) {
93
+ return [{ label: 'Transcript load', value: 'No renderable transcript content was found.' }];
94
+ }
95
+
96
+ const stats = getAntigravityThreadTranscriptStats(events);
97
+ return [
98
+ { label: 'Event kinds', value: [...new Set(events.map((event) => event.kind))].join(', ') || 'n/a' },
99
+ { label: 'Messages', value: formatNumber(stats.messageCount) },
100
+ { label: 'User messages', value: formatNumber(stats.userMessageCount) },
101
+ { label: 'Assistant messages', value: formatNumber(stats.assistantMessageCount) },
102
+ { label: 'Commentary updates', value: formatNumber(stats.commentaryCount) },
103
+ { label: 'Final answers', value: formatNumber(stats.finalAnswerCount) },
104
+ { label: 'Tool calls', value: formatNumber(stats.toolCallCount) },
105
+ { label: 'Tool outputs', value: formatNumber(stats.toolOutputCount) },
106
+ ];
107
+ };
108
+
109
+ export const Route = createFileRoute('/antigravity-conversations/$conversationId')({
110
+ component: AntigravityConversationDetailPage,
111
+ errorComponent: AntigravityConversationDetailErrorComponent,
112
+ loader: async ({ context, params }) => {
113
+ await Promise.all([
114
+ context.queryClient.ensureQueryData(antigravityDecryptionQueryOptions()),
115
+ context.queryClient.ensureQueryData(antigravityConversationDetailQueryOptions(params.conversationId)),
116
+ ]);
117
+ },
118
+ pendingComponent: () => (
119
+ <LoadingPanel
120
+ description="Loading the Antigravity conversation transcript, artifact data, and workspace context."
121
+ title="Loading conversation"
122
+ />
123
+ ),
124
+ });
125
+
126
+ function AntigravityConversationDetailErrorComponent({ error }: { error: Error }) {
127
+ return <ReloadErrorPanel description={error.message} title="Failed to load Antigravity conversation" />;
128
+ }
129
+
130
+ function AntigravityConversationHeaderActions({
131
+ canExportArtifacts,
132
+ canExportConversation,
133
+ exportArtifactsPending,
134
+ exportConversationPending,
135
+ showConversationExport,
136
+ onExportArtifacts,
137
+ onExportConversation,
138
+ }: {
139
+ canExportArtifacts: boolean;
140
+ canExportConversation: boolean;
141
+ exportArtifactsPending: boolean;
142
+ exportConversationPending: boolean;
143
+ showConversationExport: boolean;
144
+ onExportArtifacts: () => void;
145
+ onExportConversation: () => void;
146
+ }) {
147
+ return (
148
+ <div className="flex flex-wrap gap-2">
149
+ {showConversationExport ? (
150
+ <Button
151
+ className="rounded-full"
152
+ disabled={!canExportConversation || exportConversationPending}
153
+ type="button"
154
+ variant="outline"
155
+ onClick={onExportConversation}
156
+ >
157
+ <Download className="mr-2 size-4" />
158
+ Export conversation
159
+ </Button>
160
+ ) : null}
161
+ {canExportArtifacts ? (
162
+ <Button
163
+ className="rounded-full"
164
+ disabled={exportArtifactsPending}
165
+ type="button"
166
+ variant="outline"
167
+ onClick={onExportArtifacts}
168
+ >
169
+ <ScrollText className="mr-2 size-4" />
170
+ Export artifacts
171
+ </Button>
172
+ ) : null}
173
+ </div>
174
+ );
175
+ }
176
+
177
+ const AntigravityTranscriptControls = ({
178
+ rawJsonDisabled = false,
179
+ showCommentary,
180
+ showExtraEvents,
181
+ showRawJson,
182
+ showToolCalls,
183
+ showUserMessages,
184
+ onShowCommentaryChange,
185
+ onShowExtraEventsChange,
186
+ onShowRawJsonChange,
187
+ onShowToolCallsChange,
188
+ onShowUserMessagesChange,
189
+ }: TranscriptControlsProps) => {
190
+ return (
191
+ <div className="flex flex-wrap gap-4 rounded-xl border border-[var(--border)] bg-[var(--panel)] px-4 py-3 shadow-[var(--panel-shadow)]">
192
+ <div className="flex items-center gap-2 text-sm">
193
+ <Checkbox
194
+ checked={showToolCalls}
195
+ id="antigravity-transcript-show-tool-calls"
196
+ onCheckedChange={(checked) => onShowToolCallsChange(checked === true)}
197
+ />
198
+ <label htmlFor="antigravity-transcript-show-tool-calls">Show tool calls</label>
199
+ </div>
200
+ <div className="flex items-center gap-2 text-sm">
201
+ <Checkbox
202
+ checked={showCommentary}
203
+ id="antigravity-transcript-show-commentary"
204
+ onCheckedChange={(checked) => onShowCommentaryChange(checked === true)}
205
+ />
206
+ <label htmlFor="antigravity-transcript-show-commentary">Show commentary</label>
207
+ </div>
208
+ <div className="flex items-center gap-2 text-sm">
209
+ <Checkbox
210
+ checked={showExtraEvents}
211
+ id="antigravity-transcript-show-extra-events"
212
+ onCheckedChange={(checked) => onShowExtraEventsChange(checked === true)}
213
+ />
214
+ <label htmlFor="antigravity-transcript-show-extra-events">Show extra events</label>
215
+ </div>
216
+ <div className="flex items-center gap-2 text-sm">
217
+ <Checkbox
218
+ checked={showRawJson}
219
+ disabled={rawJsonDisabled}
220
+ id="antigravity-transcript-show-raw-json"
221
+ onCheckedChange={(checked) => onShowRawJsonChange(checked === true)}
222
+ />
223
+ <label htmlFor="antigravity-transcript-show-raw-json">Raw JSON</label>
224
+ </div>
225
+ <div className="flex items-center gap-2 text-sm">
226
+ <Checkbox
227
+ checked={showUserMessages}
228
+ id="antigravity-transcript-show-user-messages"
229
+ onCheckedChange={(checked) => onShowUserMessagesChange(checked === true)}
230
+ />
231
+ <label htmlFor="antigravity-transcript-show-user-messages">User</label>
232
+ </div>
233
+ </div>
234
+ );
235
+ };
236
+
237
+ function EmptyAntigravityTranscript({ detail }: { detail: AntigravityConversationDetail }) {
238
+ return (
239
+ <section className="rounded-[1.6rem] border border-[var(--border)] bg-[var(--panel)] p-5 shadow-[var(--panel-shadow)]">
240
+ <h3 className="font-semibold text-[var(--muted-foreground)] text-sm uppercase tracking-[0.18em]">
241
+ Transcript
242
+ </h3>
243
+ <p className="mt-4 text-[var(--muted-foreground)] text-sm">
244
+ {detail.transcriptLocked
245
+ ? 'Unlock Antigravity transcript export to inspect the rendered conversation content here.'
246
+ : detail.artifactsMarkdown
247
+ ? 'No transcript preview is available for this conversation. Generated artifacts are available in the Raw tab.'
248
+ : 'No transcript preview is available for this conversation.'}
249
+ </p>
250
+ </section>
251
+ );
252
+ }
253
+
254
+ function AntigravityRawPanels({
255
+ detail,
256
+ events,
257
+ }: {
258
+ detail: AntigravityConversationDetail;
259
+ events: ReturnType<typeof antigravityMarkdownToThreadEvents>;
260
+ }) {
261
+ return (
262
+ <div className="space-y-4">
263
+ <JsonPanel title="Conversation summary" value={detail.conversation} />
264
+ <JsonPanel title="Transcript events" value={events} />
265
+ {detail.conversationMarkdown ? (
266
+ <TextDocumentPanel
267
+ content={detail.conversationMarkdown}
268
+ description="Rendered transcript Markdown used for export."
269
+ title="Transcript Markdown"
270
+ />
271
+ ) : null}
272
+ {detail.artifactsMarkdown ? (
273
+ <TextDocumentPanel
274
+ content={detail.artifactsMarkdown}
275
+ description="Generated artifacts."
276
+ title="Artifacts"
277
+ />
278
+ ) : null}
279
+ </div>
280
+ );
281
+ }
282
+
283
+ function AntigravityConversationDetailPage() {
284
+ const decryptionState = useSuspenseQuery(antigravityDecryptionQueryOptions()).data;
285
+ const detail = useSuspenseQuery(antigravityConversationDetailQueryOptions(Route.useParams().conversationId)).data;
286
+ const [showToolCalls, setShowToolCalls] = useState(false);
287
+ const [showCommentary, setShowCommentary] = useState(false);
288
+ const [showExtraEvents, setShowExtraEvents] = useState(false);
289
+ const [showRawJson, setShowRawJson] = useState(false);
290
+ const [showUserMessages, setShowUserMessages] = useState(true);
291
+ const transcriptEvents = useMemo(
292
+ () => antigravityMarkdownToThreadEvents(detail.conversationMarkdown),
293
+ [detail.conversationMarkdown],
294
+ );
295
+ const canExportConversation = canExportAntigravityConversation(
296
+ detail.conversation,
297
+ Boolean(decryptionState?.isUnlocked),
298
+ );
299
+ const canExportArtifacts = detail.artifactsMarkdown !== null;
300
+ const showConversationExport = canExportConversation || detail.transcriptLocked;
301
+
302
+ const exportConversationMutation = useMutation({
303
+ mutationFn: () =>
304
+ exportAntigravityConversationFn({ data: { conversationId: detail.conversation.conversationId } }),
305
+ onSuccess: (result) => {
306
+ downloadTextFile(result.filename, result.content, 'text/markdown; charset=utf-8');
307
+ },
308
+ });
309
+
310
+ const exportArtifactsMutation = useMutation({
311
+ mutationFn: () =>
312
+ exportAntigravityArtifactsFn({ data: { conversationId: detail.conversation.conversationId } }),
313
+ onSuccess: (result) => {
314
+ downloadTextFile(result.filename, result.content, 'text/markdown; charset=utf-8');
315
+ },
316
+ });
317
+
318
+ return (
319
+ <div className="space-y-6">
320
+ <PageHeader
321
+ actions={
322
+ <AntigravityConversationHeaderActions
323
+ canExportArtifacts={canExportArtifacts}
324
+ canExportConversation={canExportConversation}
325
+ exportArtifactsPending={exportArtifactsMutation.isPending}
326
+ exportConversationPending={exportConversationMutation.isPending}
327
+ showConversationExport={showConversationExport}
328
+ onExportArtifacts={() => exportArtifactsMutation.mutate()}
329
+ onExportConversation={() => exportConversationMutation.mutate()}
330
+ />
331
+ }
332
+ breadcrumb={
333
+ <Breadcrumbs
334
+ items={[
335
+ { label: 'Antigravity', to: '/antigravity' },
336
+ {
337
+ label: detail.conversation.workspaceLabel,
338
+ params: { workspaceKey: detail.conversation.workspaceKey },
339
+ to: '/antigravity/$workspaceKey',
340
+ },
341
+ { label: detail.conversation.title },
342
+ ]}
343
+ />
344
+ }
345
+ eyebrow="Antigravity conversation"
346
+ subtitle="Conversation detail for the selected Antigravity workspace session."
347
+ title={detail.conversation.title}
348
+ />
349
+
350
+ <AntigravityKeychainPanel />
351
+
352
+ <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-4">
353
+ <MetricCard label="Transcript entries" value={formatNumber(detail.conversation.transcriptEntryCount)} />
354
+ <MetricCard label="Artifacts" value={formatNumber(detail.conversation.artifactCount)} />
355
+ <MetricCard label="Size" value={formatBytes(detail.conversation.conversationBytes)} />
356
+ <MetricCard
357
+ helper={detail.conversation.transcriptSource ?? 'summary'}
358
+ label="Indexed items"
359
+ value={formatNumber(detail.conversation.indexedItemCount ?? 0)}
360
+ />
361
+ </div>
362
+
363
+ <Tabs className="space-y-4" defaultValue="transcript">
364
+ <TabsList className="grid w-fit min-w-[24rem] grid-cols-3 rounded-full border border-[var(--border)] bg-[var(--panel)] p-1">
365
+ <TabsTrigger className="rounded-full px-5 text-sm" value="transcript">
366
+ Transcript
367
+ </TabsTrigger>
368
+ <TabsTrigger className="rounded-full px-5 text-sm" value="metadata">
369
+ Metadata
370
+ </TabsTrigger>
371
+ <TabsTrigger className="rounded-full px-5 text-sm" value="raw">
372
+ Raw
373
+ </TabsTrigger>
374
+ </TabsList>
375
+
376
+ <TabsContent className="space-y-3" value="transcript">
377
+ <AntigravityTranscriptControls
378
+ rawJsonDisabled={transcriptEvents.length === 0}
379
+ showCommentary={showCommentary}
380
+ showExtraEvents={showExtraEvents}
381
+ showRawJson={showRawJson}
382
+ showToolCalls={showToolCalls}
383
+ showUserMessages={showUserMessages}
384
+ onShowCommentaryChange={setShowCommentary}
385
+ onShowExtraEventsChange={setShowExtraEvents}
386
+ onShowRawJsonChange={setShowRawJson}
387
+ onShowToolCallsChange={setShowToolCalls}
388
+ onShowUserMessagesChange={setShowUserMessages}
389
+ />
390
+ {transcriptEvents.length > 0 ? (
391
+ <TranscriptView
392
+ assistantModel={null}
393
+ events={transcriptEvents}
394
+ projectPath={detail.conversation.workspaceFolder}
395
+ showCommentary={showCommentary}
396
+ showExtraEvents={showExtraEvents}
397
+ showRawJson={showRawJson}
398
+ showToolCalls={showToolCalls}
399
+ showUserMessages={showUserMessages}
400
+ />
401
+ ) : (
402
+ <EmptyAntigravityTranscript detail={detail} />
403
+ )}
404
+ </TabsContent>
405
+
406
+ <TabsContent value="metadata">
407
+ <div className="grid gap-4 xl:grid-cols-[0.95fr_1.05fr]">
408
+ <MetadataSection items={buildConversationMetadata(detail)} title="Conversation metadata" />
409
+ <MetadataSection
410
+ items={buildTranscriptStatsItems(detail, transcriptEvents)}
411
+ title="Transcript stats"
412
+ />
413
+ </div>
414
+ </TabsContent>
415
+
416
+ <TabsContent value="raw">
417
+ <AntigravityRawPanels detail={detail} events={transcriptEvents} />
418
+ </TabsContent>
419
+ </Tabs>
420
+
421
+ {exportConversationMutation.isError ? (
422
+ <p className="text-[var(--destructive)] text-sm">
423
+ {exportConversationMutation.error instanceof Error
424
+ ? exportConversationMutation.error.message
425
+ : 'Conversation export failed'}
426
+ </p>
427
+ ) : null}
428
+
429
+ {exportArtifactsMutation.isError ? (
430
+ <p className="text-[var(--destructive)] text-sm">
431
+ {exportArtifactsMutation.error instanceof Error
432
+ ? exportArtifactsMutation.error.message
433
+ : 'Artifact export failed'}
434
+ </p>
435
+ ) : null}
436
+ </div>
437
+ );
438
+ }
@@ -0,0 +1,127 @@
1
+ import type { AntigravityConversation, AntigravityWorkspaceGroup } from '@spiracha/lib/antigravity-exporter-types';
2
+ import { useMutation, useSuspenseQuery } from '@tanstack/react-query';
3
+ import { createFileRoute } from '@tanstack/react-router';
4
+ import { useDeferredValue, useState } from 'react';
5
+ import { AntigravityConversationsTable } from '#/components/antigravity-conversations-table';
6
+ import { AntigravityKeychainPanel } from '#/components/antigravity-keychain-panel';
7
+ import { ListSearchInput } from '#/components/list-search-input';
8
+ import { LoadingPanel } from '#/components/loading-panel';
9
+ import { PageHeader } from '#/components/page-header';
10
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
11
+ import {
12
+ antigravityConversationsQueryOptions,
13
+ antigravityDecryptionQueryOptions,
14
+ antigravityWorkspacesQueryOptions,
15
+ } from '#/lib/antigravity-queries';
16
+ import { exportAntigravityArtifactsFn, exportAntigravityConversationFn } from '#/lib/antigravity-server';
17
+ import { downloadTextFile } from '#/lib/download';
18
+ import { matchesTextQuery } from '#/lib/text-filter';
19
+
20
+ const findWorkspaceOrThrow = (workspaces: AntigravityWorkspaceGroup[], workspaceKey: string) => {
21
+ const workspace = workspaces.find((candidate) => candidate.key === workspaceKey);
22
+ if (!workspace) {
23
+ throw new Error(`Antigravity workspace not found: ${workspaceKey}`);
24
+ }
25
+
26
+ return workspace;
27
+ };
28
+
29
+ export const Route = createFileRoute('/antigravity/$workspaceKey')({
30
+ component: AntigravityWorkspacePage,
31
+ errorComponent: AntigravityWorkspaceErrorComponent,
32
+ loader: async ({ context, params }) => {
33
+ const workspaces = await context.queryClient.ensureQueryData(antigravityWorkspacesQueryOptions());
34
+ findWorkspaceOrThrow(workspaces, params.workspaceKey);
35
+ await Promise.all([
36
+ context.queryClient.ensureQueryData(antigravityDecryptionQueryOptions()),
37
+ context.queryClient.ensureQueryData(antigravityConversationsQueryOptions(params.workspaceKey)),
38
+ ]);
39
+ },
40
+ pendingComponent: () => (
41
+ <LoadingPanel
42
+ description="Loading Antigravity conversations, artifacts, and transcript availability."
43
+ title="Loading workspace"
44
+ />
45
+ ),
46
+ });
47
+
48
+ function AntigravityWorkspaceErrorComponent({ error }: { error: Error }) {
49
+ return <ReloadErrorPanel description={error.message} title="Failed to load Antigravity workspace" />;
50
+ }
51
+
52
+ function AntigravityWorkspacePage() {
53
+ const params = Route.useParams();
54
+ const workspaces = useSuspenseQuery(antigravityWorkspacesQueryOptions()).data;
55
+ const workspace = findWorkspaceOrThrow(workspaces, params.workspaceKey);
56
+ const conversations = useSuspenseQuery(antigravityConversationsQueryOptions(workspace.key)).data;
57
+ const decryptionState = useSuspenseQuery(antigravityDecryptionQueryOptions()).data ?? null;
58
+ const [searchInput, setSearchInput] = useState('');
59
+ const deferredSearch = useDeferredValue(searchInput);
60
+
61
+ const exportConversationMutation = useMutation({
62
+ mutationFn: (conversation: AntigravityConversation) =>
63
+ exportAntigravityConversationFn({ data: { conversationId: conversation.conversationId } }),
64
+ onSuccess: (result) => {
65
+ downloadTextFile(result.filename, result.content, 'text/markdown; charset=utf-8');
66
+ },
67
+ });
68
+
69
+ const exportArtifactsMutation = useMutation({
70
+ mutationFn: (conversation: AntigravityConversation) =>
71
+ exportAntigravityArtifactsFn({ data: { conversationId: conversation.conversationId } }),
72
+ onSuccess: (result) => {
73
+ downloadTextFile(result.filename, result.content, 'text/markdown; charset=utf-8');
74
+ },
75
+ });
76
+
77
+ const visibleConversations = conversations.filter((conversation) =>
78
+ matchesTextQuery(deferredSearch, [
79
+ conversation.title,
80
+ conversation.conversationId,
81
+ conversation.transcriptSource,
82
+ conversation.workspaceLabel,
83
+ ]),
84
+ );
85
+
86
+ return (
87
+ <div className="space-y-6">
88
+ <PageHeader
89
+ actions={
90
+ <ListSearchInput
91
+ placeholder="Search title, id, or transcript source"
92
+ value={searchInput}
93
+ onValueChange={setSearchInput}
94
+ />
95
+ }
96
+ eyebrow="Antigravity workspace"
97
+ subtitle="Inspect conversation coverage across Antigravity transcripts, raw payloads, and generated artifacts."
98
+ title={workspace.label}
99
+ />
100
+
101
+ <AntigravityKeychainPanel />
102
+
103
+ <AntigravityConversationsTable
104
+ conversations={visibleConversations}
105
+ decryptionState={decryptionState}
106
+ onExportArtifacts={(conversation) => exportArtifactsMutation.mutate(conversation)}
107
+ onExportConversation={(conversation) => exportConversationMutation.mutate(conversation)}
108
+ />
109
+
110
+ {exportConversationMutation.isError ? (
111
+ <p className="text-[var(--destructive)] text-sm">
112
+ {exportConversationMutation.error instanceof Error
113
+ ? exportConversationMutation.error.message
114
+ : 'Conversation export failed'}
115
+ </p>
116
+ ) : null}
117
+
118
+ {exportArtifactsMutation.isError ? (
119
+ <p className="text-[var(--destructive)] text-sm">
120
+ {exportArtifactsMutation.error instanceof Error
121
+ ? exportArtifactsMutation.error.message
122
+ : 'Artifact export failed'}
123
+ </p>
124
+ ) : null}
125
+ </div>
126
+ );
127
+ }
@@ -0,0 +1,51 @@
1
+ import { useSuspenseQuery } from '@tanstack/react-query';
2
+ import { createFileRoute } from '@tanstack/react-router';
3
+ import { useDeferredValue, useState } from 'react';
4
+ import { AntigravityKeychainPanel } from '#/components/antigravity-keychain-panel';
5
+ import { AntigravityWorkspacesTable } from '#/components/antigravity-workspaces-table';
6
+ import { ListSearchInput } from '#/components/list-search-input';
7
+ import { PageHeader } from '#/components/page-header';
8
+ import { ReloadErrorPanel } from '#/components/reload-error-panel';
9
+ import { antigravityWorkspacesQueryOptions } from '#/lib/antigravity-queries';
10
+ import { matchesTextQuery } from '#/lib/text-filter';
11
+
12
+ export const Route = createFileRoute('/antigravity/')({
13
+ component: AntigravityPage,
14
+ errorComponent: AntigravityErrorComponent,
15
+ loader: ({ context }) => context.queryClient.ensureQueryData(antigravityWorkspacesQueryOptions()),
16
+ });
17
+
18
+ function AntigravityErrorComponent({ error }: { error: Error }) {
19
+ return <ReloadErrorPanel description={error.message} title="Failed to load Antigravity workspaces" />;
20
+ }
21
+
22
+ function AntigravityPage() {
23
+ const workspaces = useSuspenseQuery(antigravityWorkspacesQueryOptions()).data;
24
+ const [searchInput, setSearchInput] = useState('');
25
+ const deferredSearch = useDeferredValue(searchInput);
26
+
27
+ const visibleWorkspaces = workspaces.filter((workspace) =>
28
+ matchesTextQuery(deferredSearch, [workspace.label, workspace.uri, workspace.key]),
29
+ );
30
+
31
+ return (
32
+ <div className="space-y-6">
33
+ <PageHeader
34
+ actions={
35
+ <ListSearchInput
36
+ placeholder="Search workspace name or path"
37
+ value={searchInput}
38
+ onValueChange={setSearchInput}
39
+ />
40
+ }
41
+ eyebrow="Inventory"
42
+ subtitle="Workspace groups are derived from Antigravity summary indexes, raw conversation files, local logs, and brain artifacts."
43
+ title="Antigravity"
44
+ />
45
+
46
+ <AntigravityKeychainPanel />
47
+
48
+ <AntigravityWorkspacesTable workspaces={visibleWorkspaces} />
49
+ </div>
50
+ );
51
+ }
@@ -0,0 +1,12 @@
1
+ import { createFileRoute } from '@tanstack/react-router';
2
+
3
+ export const Route = createFileRoute('/api/v1/conversation-query')({
4
+ server: {
5
+ handlers: {
6
+ POST: async ({ request }) => {
7
+ const { handleConversationApiRequest } = await import('@spiracha/lib/conversation-api');
8
+ return handleConversationApiRequest(request);
9
+ },
10
+ },
11
+ },
12
+ });
@@ -0,0 +1,12 @@
1
+ import { createFileRoute } from '@tanstack/react-router';
2
+
3
+ export const Route = createFileRoute('/api/v1/conversations/$source/$id/export')({
4
+ server: {
5
+ handlers: {
6
+ GET: async ({ request }) => {
7
+ const { handleConversationApiRequest } = await import('@spiracha/lib/conversation-api');
8
+ return handleConversationApiRequest(request);
9
+ },
10
+ },
11
+ },
12
+ });
@@ -0,0 +1,12 @@
1
+ import { createFileRoute } from '@tanstack/react-router';
2
+
3
+ export const Route = createFileRoute('/api/v1/conversations/$source/$id')({
4
+ server: {
5
+ handlers: {
6
+ GET: async ({ request }) => {
7
+ const { handleConversationApiRequest } = await import('@spiracha/lib/conversation-api');
8
+ return handleConversationApiRequest(request);
9
+ },
10
+ },
11
+ },
12
+ });
@@ -0,0 +1,12 @@
1
+ import { createFileRoute } from '@tanstack/react-router';
2
+
3
+ export const Route = createFileRoute('/api/v1/conversations')({
4
+ server: {
5
+ handlers: {
6
+ GET: async ({ request }) => {
7
+ const { handleConversationApiRequest } = await import('@spiracha/lib/conversation-api');
8
+ return handleConversationApiRequest(request);
9
+ },
10
+ },
11
+ },
12
+ });