spiracha 1.5.0 → 2.1.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 (401) hide show
  1. package/AGENTS.md +114 -205
  2. package/README.md +94 -269
  3. package/apps/ui/AGENTS.md +17 -7
  4. package/apps/ui/README.md +52 -8
  5. package/apps/ui/components.json +21 -0
  6. package/apps/ui/package.json +65 -0
  7. package/apps/ui/src/components/antigravity-conversations-table.tsx +245 -0
  8. package/apps/ui/src/components/antigravity-keychain-panel.tsx +76 -0
  9. package/apps/ui/src/components/antigravity-workspaces-table.tsx +63 -0
  10. package/apps/ui/src/components/app-shell.tsx +125 -0
  11. package/apps/ui/src/components/breadcrumbs.tsx +71 -0
  12. package/apps/ui/src/components/claude-code-sessions-table.tsx +150 -0
  13. package/apps/ui/src/components/claude-code-workspaces-table.tsx +57 -0
  14. package/apps/ui/src/components/cursor-threads-table.tsx +152 -0
  15. package/apps/ui/src/components/cursor-workspaces-table.tsx +140 -0
  16. package/apps/ui/src/components/data-table.tsx +243 -0
  17. package/apps/ui/src/components/delete-confirm-dialog.tsx +88 -0
  18. package/apps/ui/src/components/export-dialog.tsx +174 -0
  19. package/apps/ui/src/components/grok-sessions-table.tsx +146 -0
  20. package/apps/ui/src/components/grok-workspaces-table.tsx +53 -0
  21. package/apps/ui/src/components/json-panel.tsx +17 -0
  22. package/apps/ui/src/components/kiro-sessions-table.tsx +148 -0
  23. package/apps/ui/src/components/kiro-workspaces-table.tsx +53 -0
  24. package/apps/ui/src/components/list-search-input.tsx +18 -0
  25. package/apps/ui/src/components/loading-panel.tsx +23 -0
  26. package/apps/ui/src/components/metadata-section.tsx +31 -0
  27. package/apps/ui/src/components/metric-card.tsx +19 -0
  28. package/apps/ui/src/components/opencode-sessions-table.tsx +164 -0
  29. package/apps/ui/src/components/opencode-workspaces-table.tsx +57 -0
  30. package/apps/ui/src/components/page-header.tsx +39 -0
  31. package/apps/ui/src/components/projects-loading-state.tsx +74 -0
  32. package/apps/ui/src/components/projects-table.tsx +108 -0
  33. package/apps/ui/src/components/qoder-sessions-table.tsx +133 -0
  34. package/apps/ui/src/components/qoder-workspaces-table.tsx +57 -0
  35. package/apps/ui/src/components/recent-threads-list.tsx +52 -0
  36. package/apps/ui/src/components/reload-error-panel.tsx +20 -0
  37. package/apps/ui/src/components/selection-actions-toolbar.tsx +80 -0
  38. package/apps/ui/src/components/text-document-panel.tsx +19 -0
  39. package/apps/ui/src/components/theme-toggle.tsx +48 -0
  40. package/apps/ui/src/components/threads-table.tsx +165 -0
  41. package/apps/ui/src/components/transcript-view.tsx +648 -0
  42. package/apps/ui/src/components/ui/alert-dialog.tsx +160 -0
  43. package/apps/ui/src/components/ui/badge.tsx +45 -0
  44. package/apps/ui/src/components/ui/button.tsx +62 -0
  45. package/apps/ui/src/components/ui/checkbox.tsx +29 -0
  46. package/apps/ui/src/components/ui/dialog.tsx +137 -0
  47. package/apps/ui/src/components/ui/dropdown-menu.tsx +217 -0
  48. package/apps/ui/src/components/ui/input.tsx +21 -0
  49. package/apps/ui/src/components/ui/scroll-area.tsx +46 -0
  50. package/apps/ui/src/components/ui/select.tsx +163 -0
  51. package/apps/ui/src/components/ui/separator.tsx +28 -0
  52. package/apps/ui/src/components/ui/sheet.tsx +107 -0
  53. package/apps/ui/src/components/ui/skeleton.tsx +7 -0
  54. package/apps/ui/src/components/ui/table.tsx +76 -0
  55. package/apps/ui/src/components/ui/tabs.tsx +71 -0
  56. package/apps/ui/src/components/ui/tooltip.tsx +44 -0
  57. package/apps/ui/src/integrations/tanstack-query/devtools.tsx +6 -0
  58. package/apps/ui/src/integrations/tanstack-query/root-provider.tsx +10 -0
  59. package/apps/ui/src/lib/antigravity-conversation-state.ts +41 -0
  60. package/apps/ui/src/lib/antigravity-queries.ts +33 -0
  61. package/apps/ui/src/lib/antigravity-server.ts +273 -0
  62. package/apps/ui/src/lib/antigravity-transcript-events.ts +343 -0
  63. package/apps/ui/src/lib/claude-code-queries.ts +34 -0
  64. package/apps/ui/src/lib/claude-code-server.ts +243 -0
  65. package/apps/ui/src/lib/claude-code-transcript-events.ts +161 -0
  66. package/apps/ui/src/lib/codex-queries.ts +82 -0
  67. package/apps/ui/src/lib/codex-server.ts +291 -0
  68. package/apps/ui/src/lib/cursor-queries.ts +37 -0
  69. package/apps/ui/src/lib/cursor-server.ts +315 -0
  70. package/apps/ui/src/lib/cursor-transcript-events.ts +229 -0
  71. package/apps/ui/src/lib/download.ts +166 -0
  72. package/apps/ui/src/lib/formatters.ts +147 -0
  73. package/apps/ui/src/lib/grok-queries.ts +22 -0
  74. package/apps/ui/src/lib/grok-server.ts +169 -0
  75. package/apps/ui/src/lib/grok-transcript-events.ts +149 -0
  76. package/apps/ui/src/lib/kiro-queries.ts +22 -0
  77. package/apps/ui/src/lib/kiro-server.ts +151 -0
  78. package/apps/ui/src/lib/kiro-transcript-events.ts +113 -0
  79. package/apps/ui/src/lib/opencode-queries.ts +37 -0
  80. package/apps/ui/src/lib/opencode-server.ts +151 -0
  81. package/apps/ui/src/lib/opencode-transcript-events.ts +221 -0
  82. package/apps/ui/src/lib/package-metadata.ts +16 -0
  83. package/apps/ui/src/lib/path-utils.ts +13 -0
  84. package/apps/ui/src/lib/qoder-queries.ts +22 -0
  85. package/apps/ui/src/lib/qoder-server.ts +135 -0
  86. package/apps/ui/src/lib/qoder-transcript-events.ts +139 -0
  87. package/apps/ui/src/lib/route-search.ts +182 -0
  88. package/apps/ui/src/lib/settings-store.tsx +59 -0
  89. package/apps/ui/src/lib/source-session-export-server.ts +139 -0
  90. package/apps/ui/src/lib/text-filter.ts +22 -0
  91. package/apps/ui/src/lib/thread-id.ts +3 -0
  92. package/apps/ui/src/lib/thread-transcript-load.ts +15 -0
  93. package/apps/ui/src/lib/thread-transcript-stats.ts +57 -0
  94. package/apps/ui/src/lib/utils.ts +7 -0
  95. package/apps/ui/src/lib/workspace-delete-navigation.ts +12 -0
  96. package/apps/ui/src/routeTree.gen.ts +837 -0
  97. package/apps/ui/src/router.tsx +20 -0
  98. package/apps/ui/src/routes/$threadId.tsx +22 -0
  99. package/apps/ui/src/routes/__root.tsx +127 -0
  100. package/apps/ui/src/routes/analytics.tsx +143 -0
  101. package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +504 -0
  102. package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +365 -0
  103. package/apps/ui/src/routes/antigravity.index.tsx +51 -0
  104. package/apps/ui/src/routes/api.v1.conversation-query.ts +12 -0
  105. package/apps/ui/src/routes/api.v1.conversations.$source.$id.export.ts +12 -0
  106. package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +16 -0
  107. package/apps/ui/src/routes/api.v1.conversations.delete.ts +12 -0
  108. package/apps/ui/src/routes/api.v1.conversations.export.ts +12 -0
  109. package/apps/ui/src/routes/api.v1.conversations.ts +12 -0
  110. package/apps/ui/src/routes/api.v1.resolve.ts +12 -0
  111. package/apps/ui/src/routes/api.v1.sources.ts +12 -0
  112. package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +468 -0
  113. package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +274 -0
  114. package/apps/ui/src/routes/claude-code.index.tsx +48 -0
  115. package/apps/ui/src/routes/codex.$project.tsx +390 -0
  116. package/apps/ui/src/routes/codex.index.tsx +116 -0
  117. package/apps/ui/src/routes/cursor-threads.$composerId.tsx +435 -0
  118. package/apps/ui/src/routes/cursor.$workspaceKey.tsx +426 -0
  119. package/apps/ui/src/routes/cursor.index.tsx +120 -0
  120. package/apps/ui/src/routes/grok-sessions.$sessionId.tsx +388 -0
  121. package/apps/ui/src/routes/grok.$workspaceKey.tsx +301 -0
  122. package/apps/ui/src/routes/grok.index.tsx +48 -0
  123. package/apps/ui/src/routes/index.tsx +124 -0
  124. package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +396 -0
  125. package/apps/ui/src/routes/kiro.$workspaceKey.tsx +303 -0
  126. package/apps/ui/src/routes/kiro.index.tsx +48 -0
  127. package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +420 -0
  128. package/apps/ui/src/routes/opencode.$workspaceKey.tsx +327 -0
  129. package/apps/ui/src/routes/opencode.index.tsx +61 -0
  130. package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +344 -0
  131. package/apps/ui/src/routes/qoder.$workspaceKey.tsx +186 -0
  132. package/apps/ui/src/routes/qoder.index.tsx +48 -0
  133. package/apps/ui/src/routes/settings.tsx +91 -0
  134. package/apps/ui/src/routes/threads.$threadId.tsx +1103 -0
  135. package/apps/ui/src/styles.css +122 -0
  136. package/apps/ui/tsconfig.json +29 -0
  137. package/apps/ui/vite.config.ts +84 -0
  138. package/bin/spiracha.ts +32 -0
  139. package/package.json +54 -80
  140. package/src/client.ts +423 -0
  141. package/src/lib/antigravity-db.ts +414 -44
  142. package/src/lib/antigravity-exporter-types.ts +4 -0
  143. package/src/lib/antigravity-projects.ts +201 -0
  144. package/src/lib/claude-code-db.ts +498 -32
  145. package/src/lib/claude-code-exporter-types.ts +5 -0
  146. package/src/lib/claude-code-transcript-phase.ts +60 -1
  147. package/src/lib/claude-code-transcript.ts +8 -5
  148. package/src/lib/codex-analytics.ts +1 -1
  149. package/src/lib/codex-browser-db.ts +410 -74
  150. package/src/lib/codex-browser-export.ts +29 -41
  151. package/src/lib/codex-browser-types.ts +1 -1
  152. package/src/lib/codex-thread-cache.ts +41 -13
  153. package/src/lib/codex-thread-parser.ts +86 -35
  154. package/src/lib/{codex-exporter-types.ts → codex-thread-types.ts} +2 -30
  155. package/src/lib/codex-transcript-filter.ts +31 -0
  156. package/src/lib/{codex-exporter-transcript.ts → codex-transcript-renderer.ts} +104 -48
  157. package/src/lib/concurrency.ts +41 -0
  158. package/src/lib/conversation-api.ts +1172 -0
  159. package/src/lib/conversation-data/adapter-helpers.ts +110 -0
  160. package/src/lib/conversation-data/antigravity-adapter.ts +167 -0
  161. package/src/lib/conversation-data/claude-code-adapter.ts +206 -0
  162. package/src/lib/conversation-data/codex-adapter.ts +269 -0
  163. package/src/lib/conversation-data/cursor-adapter.ts +205 -0
  164. package/src/lib/conversation-data/grok-adapter.ts +210 -0
  165. package/src/lib/conversation-data/index.ts +386 -0
  166. package/src/lib/conversation-data/kiro-adapter.ts +174 -0
  167. package/src/lib/conversation-data/message-selector.ts +37 -0
  168. package/src/lib/conversation-data/opencode-adapter.ts +202 -0
  169. package/src/lib/conversation-data/path-match.ts +79 -0
  170. package/src/lib/conversation-data/qoder-adapter.ts +255 -0
  171. package/src/lib/conversation-data/types.ts +159 -0
  172. package/src/lib/conversation-zip-export.ts +57 -0
  173. package/src/lib/cursor-db.ts +100 -25
  174. package/src/lib/cursor-exporter-types.ts +0 -19
  175. package/src/lib/grok-db.ts +1026 -0
  176. package/src/lib/grok-exporter-types.ts +110 -0
  177. package/src/lib/grok-transcript-phase.ts +52 -0
  178. package/src/lib/grok-transcript.ts +154 -0
  179. package/src/lib/kiro-db.ts +52 -1
  180. package/src/lib/model-label.ts +11 -3
  181. package/src/lib/opencode-db.ts +598 -55
  182. package/src/lib/opencode-transcript.ts +8 -5
  183. package/src/lib/qoder-acp-client.ts +268 -0
  184. package/src/lib/qoder-db.ts +1601 -0
  185. package/src/lib/qoder-exporter-types.ts +114 -0
  186. package/src/lib/qoder-transcript-phase.ts +41 -0
  187. package/src/lib/qoder-transcript.ts +112 -0
  188. package/src/lib/shared.ts +12 -0
  189. package/src/lib/transcript-load-limiter.ts +82 -0
  190. package/src/lib/ui-cache.ts +43 -17
  191. package/src/lib/ui-export-archive.ts +60 -0
  192. package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +0 -1
  193. package/apps/ui/dist/client/assets/analytics-DOy1b6Sh.js +0 -1
  194. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-DqySVO2K.js +0 -7
  195. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-KAcXtNxI.js +0 -1
  196. package/apps/ui/dist/client/assets/antigravity-keychain-panel-B77qJz6f.js +0 -1
  197. package/apps/ui/dist/client/assets/antigravity._workspaceKey-B3NM6gRH.js +0 -1
  198. package/apps/ui/dist/client/assets/antigravity._workspaceKey-ByitGWki.js +0 -1
  199. package/apps/ui/dist/client/assets/antigravity.index-DP9JC2P9.js +0 -1
  200. package/apps/ui/dist/client/assets/antigravity.index-DgW25FEV.js +0 -1
  201. package/apps/ui/dist/client/assets/badge-C3i4OKs8.js +0 -1
  202. package/apps/ui/dist/client/assets/checkbox-CdHitXWQ.js +0 -1
  203. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-8pQ55ci2.js +0 -1
  204. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-DVz5UmtU.js +0 -1
  205. package/apps/ui/dist/client/assets/claude-code._workspaceKey-BBKskSum.js +0 -1
  206. package/apps/ui/dist/client/assets/claude-code._workspaceKey-OkikMUFs.js +0 -1
  207. package/apps/ui/dist/client/assets/claude-code.index-Cwu76dbb.js +0 -1
  208. package/apps/ui/dist/client/assets/claude-code.index-D6eMd08t.js +0 -1
  209. package/apps/ui/dist/client/assets/createServerFn-B-KkwmHU.js +0 -3
  210. package/apps/ui/dist/client/assets/cursor-threads._composerId-CmBFclK8.js +0 -1
  211. package/apps/ui/dist/client/assets/cursor-threads._composerId-hBWlP1D-.js +0 -1
  212. package/apps/ui/dist/client/assets/cursor._workspaceKey-BFPkIRi-.js +0 -1
  213. package/apps/ui/dist/client/assets/cursor._workspaceKey-CaAZjGmm.js +0 -1
  214. package/apps/ui/dist/client/assets/cursor.index-8y4o20kb.js +0 -2
  215. package/apps/ui/dist/client/assets/cursor.index-CrnMwDCi.js +0 -1
  216. package/apps/ui/dist/client/assets/data-table-Br78_dk3.js +0 -4
  217. package/apps/ui/dist/client/assets/delete-confirm-dialog-Bxs07u-j.js +0 -7
  218. package/apps/ui/dist/client/assets/dist-B9pyYCVU.js +0 -1
  219. package/apps/ui/dist/client/assets/dist-BrJhN2A0.js +0 -5
  220. package/apps/ui/dist/client/assets/dist-Cmd3AIfD.js +0 -1
  221. package/apps/ui/dist/client/assets/dist-DvMS2965.js +0 -1
  222. package/apps/ui/dist/client/assets/download-Bf0QJKD3.js +0 -1
  223. package/apps/ui/dist/client/assets/dropdown-menu-D5cvPaZt.js +0 -1
  224. package/apps/ui/dist/client/assets/es2015-ad6040dw.js +0 -41
  225. package/apps/ui/dist/client/assets/export-dialog-Dr8d2MqD.js +0 -1
  226. package/apps/ui/dist/client/assets/formatters-BtqyrX_c.js +0 -1
  227. package/apps/ui/dist/client/assets/index-C-STgIH4.js +0 -166
  228. package/apps/ui/dist/client/assets/jsx-runtime-DGeXAQPT.js +0 -1
  229. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-CKgfJ7GR.js +0 -1
  230. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-zvIJHtQF.js +0 -1
  231. package/apps/ui/dist/client/assets/kiro._workspaceKey-DhVuJuZB.js +0 -1
  232. package/apps/ui/dist/client/assets/kiro._workspaceKey-QArsjkTY.js +0 -1
  233. package/apps/ui/dist/client/assets/kiro.index-C-fr4m7i.js +0 -1
  234. package/apps/ui/dist/client/assets/kiro.index-OYgAdtZd.js +0 -1
  235. package/apps/ui/dist/client/assets/metric-card-Dplm0ZiM.js +0 -1
  236. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-DLjiTst-.js +0 -1
  237. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-biBwrRbt.js +0 -8
  238. package/apps/ui/dist/client/assets/opencode._workspaceKey-C7OIzMOJ.js +0 -1
  239. package/apps/ui/dist/client/assets/opencode._workspaceKey-sBakX0oI.js +0 -1
  240. package/apps/ui/dist/client/assets/opencode.index-Bl_kNs9N.js +0 -1
  241. package/apps/ui/dist/client/assets/opencode.index-CN53bVmb.js +0 -1
  242. package/apps/ui/dist/client/assets/page-header-Cwa3p6Tl.js +0 -1
  243. package/apps/ui/dist/client/assets/preload-helper-B8fFrdxC.js +0 -1
  244. package/apps/ui/dist/client/assets/projects._project-D8WloxQN.js +0 -1
  245. package/apps/ui/dist/client/assets/projects._project-DSDwH4NF.js +0 -1
  246. package/apps/ui/dist/client/assets/projects.index-5xRtuJdX.js +0 -3
  247. package/apps/ui/dist/client/assets/projects.index-DEfhWqa8.js +0 -1
  248. package/apps/ui/dist/client/assets/react-dom-DL96Jor4.js +0 -1
  249. package/apps/ui/dist/client/assets/refresh-ccw-BgKjOiA6.js +0 -1
  250. package/apps/ui/dist/client/assets/reload-error-panel-AHqu0akK.js +0 -1
  251. package/apps/ui/dist/client/assets/routes-DnzF_9CX.js +0 -1
  252. package/apps/ui/dist/client/assets/scroll-text-fM0sMOB3.js +0 -1
  253. package/apps/ui/dist/client/assets/select-CYF6pF37.js +0 -1
  254. package/apps/ui/dist/client/assets/settings-Dx70jgP_.js +0 -1
  255. package/apps/ui/dist/client/assets/sqlite-error-B6uZjUe8.js +0 -1
  256. package/apps/ui/dist/client/assets/styles-B7Zi9EFA.css +0 -1
  257. package/apps/ui/dist/client/assets/tabs-CmuhkT-c.js +0 -7
  258. package/apps/ui/dist/client/assets/text-filter-DVAZySUS.js +0 -2
  259. package/apps/ui/dist/client/assets/thread-transcript-stats-BUNz6u7F.js +0 -1
  260. package/apps/ui/dist/client/assets/threads._threadId-BB9tTsV4.js +0 -1
  261. package/apps/ui/dist/client/assets/threads._threadId-BMRSFow3.js +0 -1
  262. package/apps/ui/dist/client/assets/useMutation-BSFult2i.js +0 -1
  263. package/apps/ui/dist/client/assets/useQuery-CjINKZf1.js +0 -1
  264. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CQ8Jjs3B.js +0 -387
  265. package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +0 -6
  266. package/apps/ui/dist/server/assets/analytics-CYP_LT5Y.js +0 -16
  267. package/apps/ui/dist/server/assets/analytics-CtpOMVMO.js +0 -146
  268. package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +0 -16
  269. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BKOyL2T6.js +0 -613
  270. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +0 -11
  271. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-eS87Dx7g.js +0 -20
  272. package/apps/ui/dist/server/assets/antigravity-db-Bh8_U9uw.js +0 -580
  273. package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +0 -126
  274. package/apps/ui/dist/server/assets/antigravity-keychain-panel-CC7FLmAK.js +0 -55
  275. package/apps/ui/dist/server/assets/antigravity-queries-CGrJO9Vr.js +0 -37
  276. package/apps/ui/dist/server/assets/antigravity-server-CHRjVFqN.js +0 -114
  277. package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +0 -11
  278. package/apps/ui/dist/server/assets/antigravity._workspaceKey-B0QeYUOh.js +0 -28
  279. package/apps/ui/dist/server/assets/antigravity._workspaceKey-C3kP-qyN.js +0 -210
  280. package/apps/ui/dist/server/assets/antigravity.index-CPCYkqCi.js +0 -104
  281. package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +0 -11
  282. package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +0 -26
  283. package/apps/ui/dist/server/assets/button-CmTDnzOn.js +0 -46
  284. package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +0 -19
  285. package/apps/ui/dist/server/assets/claude-code-db-Ik3VStKZ.js +0 -361
  286. package/apps/ui/dist/server/assets/claude-code-queries-Cgzi4K-e.js +0 -37
  287. package/apps/ui/dist/server/assets/claude-code-server-PfraClXS.js +0 -72
  288. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-C55oe6zj.js +0 -18
  289. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-D1RYYi3j.js +0 -473
  290. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-DSvPLEUL.js +0 -11
  291. package/apps/ui/dist/server/assets/claude-code-transcript-C-bxh3cS.js +0 -139
  292. package/apps/ui/dist/server/assets/claude-code-transcript-phase-DmUMc8VU.js +0 -10
  293. package/apps/ui/dist/server/assets/claude-code._workspaceKey-B5Xg_-tE.js +0 -28
  294. package/apps/ui/dist/server/assets/claude-code._workspaceKey-BPlzyXPa.js +0 -11
  295. package/apps/ui/dist/server/assets/claude-code._workspaceKey-DqDve2wl.js +0 -191
  296. package/apps/ui/dist/server/assets/claude-code.index-B7yYR7dD.js +0 -92
  297. package/apps/ui/dist/server/assets/claude-code.index-BUHThG1W.js +0 -11
  298. package/apps/ui/dist/server/assets/codex-queries-CtgeZ7VL.js +0 -99
  299. package/apps/ui/dist/server/assets/codex-server-CGXU4H8-.js +0 -2294
  300. package/apps/ui/dist/server/assets/concurrency-VXtYvlGh.js +0 -18
  301. package/apps/ui/dist/server/assets/createServerRpc-CF_DEwnm.js +0 -12
  302. package/apps/ui/dist/server/assets/createSsrRpc-C754NPki.js +0 -16
  303. package/apps/ui/dist/server/assets/cursor-db-CZnYy7aT.js +0 -830
  304. package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +0 -34
  305. package/apps/ui/dist/server/assets/cursor-queries-NCIM0Nat.js +0 -67
  306. package/apps/ui/dist/server/assets/cursor-recovery-CXpO8KcD.js +0 -361
  307. package/apps/ui/dist/server/assets/cursor-server-DNu52A3K.js +0 -213
  308. package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +0 -11
  309. package/apps/ui/dist/server/assets/cursor-threads._composerId-Ckn6ItHI.js +0 -582
  310. package/apps/ui/dist/server/assets/cursor-threads._composerId-p9-ARAzc.js +0 -18
  311. package/apps/ui/dist/server/assets/cursor-transcript-B7tGnqtn.js +0 -125
  312. package/apps/ui/dist/server/assets/cursor._workspaceKey-CZuohIUL.js +0 -28
  313. package/apps/ui/dist/server/assets/cursor._workspaceKey-DPp5JSjy.js +0 -401
  314. package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +0 -11
  315. package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +0 -11
  316. package/apps/ui/dist/server/assets/cursor.index-DkWT-mxw.js +0 -189
  317. package/apps/ui/dist/server/assets/data-table-Cdct823O.js +0 -189
  318. package/apps/ui/dist/server/assets/delete-confirm-dialog-BcBNCxWB.js +0 -144
  319. package/apps/ui/dist/server/assets/download-DMmiy1xf.js +0 -92
  320. package/apps/ui/dist/server/assets/dropdown-menu-Dy_9t6TN.js +0 -36
  321. package/apps/ui/dist/server/assets/empty-plugin-adapters-B3lHh1La.js +0 -5
  322. package/apps/ui/dist/server/assets/export-dialog-D88ze9Gy.js +0 -240
  323. package/apps/ui/dist/server/assets/formatters-FJaGZgJk.js +0 -91
  324. package/apps/ui/dist/server/assets/kiro-db--fXrED_-.js +0 -552
  325. package/apps/ui/dist/server/assets/kiro-queries-CzNlM2ok.js +0 -37
  326. package/apps/ui/dist/server/assets/kiro-server-9WRxg2Au.js +0 -72
  327. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-CRY2c7YO.js +0 -11
  328. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-F1UlwxmR.js +0 -449
  329. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-bvTulT7C.js +0 -18
  330. package/apps/ui/dist/server/assets/kiro-transcript-DoekQBaH.js +0 -112
  331. package/apps/ui/dist/server/assets/kiro-transcript-phase-CJG40nQg.js +0 -27
  332. package/apps/ui/dist/server/assets/kiro._workspaceKey-BDe9sQwo.js +0 -11
  333. package/apps/ui/dist/server/assets/kiro._workspaceKey-CJsjgNwO.js +0 -28
  334. package/apps/ui/dist/server/assets/kiro._workspaceKey-D_-4Qb7y.js +0 -193
  335. package/apps/ui/dist/server/assets/kiro.index-C__-UROk.js +0 -11
  336. package/apps/ui/dist/server/assets/kiro.index-CmTbqeYj.js +0 -93
  337. package/apps/ui/dist/server/assets/loading-panel-BGFnWseS.js +0 -27
  338. package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +0 -23
  339. package/apps/ui/dist/server/assets/model-label-B1NWGc65.js +0 -13
  340. package/apps/ui/dist/server/assets/opencode-db-BM7KjOzc.js +0 -397
  341. package/apps/ui/dist/server/assets/opencode-queries-BeNYXnQv.js +0 -50
  342. package/apps/ui/dist/server/assets/opencode-server-BpQ_kRze.js +0 -72
  343. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-CGQ-t0vD.js +0 -518
  344. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-D8Q7in_Z.js +0 -18
  345. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-DKOvi0lV.js +0 -11
  346. package/apps/ui/dist/server/assets/opencode-think-tags-CAoD-EcZ.js +0 -87
  347. package/apps/ui/dist/server/assets/opencode-transcript-BNTcGNym.js +0 -141
  348. package/apps/ui/dist/server/assets/opencode-transcript-phase-OqLkiQD0.js +0 -32
  349. package/apps/ui/dist/server/assets/opencode._workspaceKey-BdqcWHw1.js +0 -11
  350. package/apps/ui/dist/server/assets/opencode._workspaceKey-CfH96HTT.js +0 -28
  351. package/apps/ui/dist/server/assets/opencode._workspaceKey-DdbHPDrO.js +0 -207
  352. package/apps/ui/dist/server/assets/opencode.index-BbVzkJXP.js +0 -11
  353. package/apps/ui/dist/server/assets/opencode.index-Vh_Gq_1L.js +0 -93
  354. package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +0 -29
  355. package/apps/ui/dist/server/assets/path-transforms-DL2IwtYd.js +0 -31
  356. package/apps/ui/dist/server/assets/projects._project-4io5LO0E.js +0 -20
  357. package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +0 -12
  358. package/apps/ui/dist/server/assets/projects._project-D6ZoGhJ8.js +0 -395
  359. package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +0 -12
  360. package/apps/ui/dist/server/assets/projects.index-BkLiF2FF.js +0 -182
  361. package/apps/ui/dist/server/assets/projects.index-DesYXwfi.js +0 -14
  362. package/apps/ui/dist/server/assets/reload-error-panel-BJMxY3U1.js +0 -25
  363. package/apps/ui/dist/server/assets/route-search-ts4W9MJ9.js +0 -38
  364. package/apps/ui/dist/server/assets/router-Sac2DGk6.js +0 -518
  365. package/apps/ui/dist/server/assets/routes-Bsact1uB.js +0 -184
  366. package/apps/ui/dist/server/assets/routes-BzkJgq4W.js +0 -34
  367. package/apps/ui/dist/server/assets/select-GW76p-ld.js +0 -76
  368. package/apps/ui/dist/server/assets/settings-OayxIYQQ.js +0 -100
  369. package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +0 -52
  370. package/apps/ui/dist/server/assets/shared-DyhChtHf.js +0 -137
  371. package/apps/ui/dist/server/assets/source-session-export-server-DNutCawb.js +0 -38
  372. package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +0 -13
  373. package/apps/ui/dist/server/assets/start-B_HFwkkk.js +0 -4
  374. package/apps/ui/dist/server/assets/tabs-DkaChNVg.js +0 -501
  375. package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +0 -36
  376. package/apps/ui/dist/server/assets/thread-transcript-stats-Dh34mt2u.js +0 -45
  377. package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +0 -26
  378. package/apps/ui/dist/server/assets/threads._threadId-BeXEc4Lo.js +0 -648
  379. package/apps/ui/dist/server/assets/threads._threadId-Ci0S4mKU.js +0 -18
  380. package/apps/ui/dist/server/assets/ui-export-files-BHLX9bhN.js +0 -83
  381. package/apps/ui/dist/server/assets/utils-C_uf36nf.js +0 -8
  382. package/apps/ui/dist/server/server.js +0 -5895
  383. package/bin/codex-chats-claude.js +0 -5
  384. package/bin/codex-chats.js +0 -5
  385. package/bin/spiracha.js +0 -5
  386. package/src/export-chats.ts +0 -120
  387. package/src/export-claude.ts +0 -36
  388. package/src/export-cursor.ts +0 -244
  389. package/src/lib/claude-exporter.ts +0 -864
  390. package/src/lib/codex-exporter-cli.ts +0 -277
  391. package/src/lib/codex-exporter-db.ts +0 -319
  392. package/src/lib/codex-exporter.ts +0 -115
  393. package/src/lib/cursor-exporter.ts +0 -266
  394. package/src/lib/interactive-cli.ts +0 -433
  395. package/src/lib/native-open.ts +0 -54
  396. package/src/mcp-server.ts +0 -137
  397. package/src/spiracha.ts +0 -116
  398. package/src/ui-cli.ts +0 -310
  399. /package/apps/ui/{dist/client → public}/icon.svg +0 -0
  400. /package/apps/ui/{dist/client → public}/manifest.json +0 -0
  401. /package/apps/ui/{dist/client → public}/robots.txt +0 -0
@@ -0,0 +1,273 @@
1
+ import { buildConversationExportBaseName } from '@spiracha/lib/ui-export-archive';
2
+ import { createServerFn } from '@tanstack/react-start';
3
+ import { z } from 'zod';
4
+ import { canExportAntigravityConversation, isAntigravityConversationLocked } from './antigravity-conversation-state';
5
+
6
+ const workspaceSchema = z.object({
7
+ workspaceKey: z.string().min(1),
8
+ });
9
+
10
+ const conversationSchema = z.object({
11
+ conversationId: z.string().min(1),
12
+ });
13
+
14
+ const exportSchema = z.object({
15
+ conversationId: z.string().min(1),
16
+ });
17
+
18
+ const exportConversationsSchema = z.object({
19
+ conversationIds: z.array(z.string().min(1)).min(1),
20
+ outputFormat: z.enum(['md', 'txt']).default('md'),
21
+ zipArchive: z.boolean().default(true),
22
+ });
23
+
24
+ const deleteConversationsSchema = z.object({
25
+ conversationIds: z.array(z.string().min(1)).min(1),
26
+ });
27
+
28
+ export const listAntigravityWorkspacesFn = createServerFn({ method: 'GET' }).handler(async () => {
29
+ const { listAntigravityWorkspaceGroups } = await import('@spiracha/lib/antigravity-db');
30
+ return listAntigravityWorkspaceGroups();
31
+ });
32
+
33
+ export const getAntigravityDecryptionStateFn = createServerFn({ method: 'GET' }).handler(async () => {
34
+ const { getAntigravityDecryptionState } = await import('@spiracha/lib/antigravity-keychain');
35
+ return getAntigravityDecryptionState();
36
+ });
37
+
38
+ export const unlockAntigravityDecryptionFn = createServerFn({ method: 'POST' }).handler(async () => {
39
+ const { unlockAntigravityDecryption } = await import('@spiracha/lib/antigravity-keychain');
40
+ return unlockAntigravityDecryption();
41
+ });
42
+
43
+ export const listAntigravityConversationsFn = createServerFn({ method: 'GET' })
44
+ .validator(workspaceSchema)
45
+ .handler(async ({ data }) => {
46
+ const { listAntigravityConversationsForGroup } = await import('@spiracha/lib/antigravity-db');
47
+ return listAntigravityConversationsForGroup(data.workspaceKey);
48
+ });
49
+
50
+ const findAntigravityConversationById = async (conversationId: string) => {
51
+ const { listAntigravityConversations } = await import('@spiracha/lib/antigravity-db');
52
+ const conversation = (await listAntigravityConversations()).find(
53
+ (candidate) => candidate.conversationId === conversationId,
54
+ );
55
+ if (!conversation) {
56
+ throw new Error(`Antigravity conversation not found: ${conversationId}`);
57
+ }
58
+
59
+ return conversation;
60
+ };
61
+
62
+ const resolveAntigravityConversationGroup = async (
63
+ conversation: Awaited<ReturnType<typeof findAntigravityConversationById>>,
64
+ ) => {
65
+ const fallback = {
66
+ key: conversation.projectId ? `project:${conversation.projectId}` : conversation.workspaceKey,
67
+ label: conversation.workspaceLabel,
68
+ };
69
+ if (!conversation.projectId) {
70
+ return fallback;
71
+ }
72
+
73
+ const { listAntigravityWorkspaceGroups } = await import('@spiracha/lib/antigravity-db');
74
+ const group = (await listAntigravityWorkspaceGroups()).find((candidate) => candidate.key === fallback.key);
75
+ return group ? { key: group.key, label: group.label } : fallback;
76
+ };
77
+
78
+ export const loadAntigravityConversationDetail = async (conversationId: string) => {
79
+ const { runWithTranscriptLoadLimit } = await import('@spiracha/lib/transcript-load-limiter');
80
+ const { renderAntigravityArtifactsMarkdown, renderAntigravityConversationMarkdown } = await import(
81
+ '@spiracha/lib/antigravity-db'
82
+ );
83
+ const { getCachedAntigravityKeychainSecret } = await import('@spiracha/lib/antigravity-keychain');
84
+ const conversation = await findAntigravityConversationById(conversationId);
85
+ const keychainSecret = getCachedAntigravityKeychainSecret();
86
+ const hasKeychainSecret = Boolean(keychainSecret);
87
+ const transcriptLocked = isAntigravityConversationLocked(conversation, hasKeychainSecret);
88
+ const [[conversationMarkdown, artifactsMarkdown], conversationGroup] = await Promise.all([
89
+ runWithTranscriptLoadLimit(
90
+ async () =>
91
+ Promise.all([
92
+ transcriptLocked ? null : renderAntigravityConversationMarkdown(conversation, { keychainSecret }),
93
+ conversation.artifactCount > 0 ? renderAntigravityArtifactsMarkdown(conversation) : null,
94
+ ]),
95
+ {
96
+ id: conversation.conversationId,
97
+ path: conversation.transcriptPath ?? conversation.conversationPath ?? undefined,
98
+ source: 'antigravity-ui-detail',
99
+ },
100
+ ),
101
+ resolveAntigravityConversationGroup(conversation),
102
+ ]);
103
+
104
+ return {
105
+ artifactsMarkdown,
106
+ conversation,
107
+ conversationGroup,
108
+ // Suppress the duplicate panel when artifactsMarkdown and conversationMarkdown are identical.
109
+ conversationMarkdown: conversationMarkdown === artifactsMarkdown ? null : conversationMarkdown,
110
+ transcriptLocked,
111
+ };
112
+ };
113
+
114
+ export const loadAntigravityConversationExport = async (conversationId: string) => {
115
+ const { runWithTranscriptLoadLimit } = await import('@spiracha/lib/transcript-load-limiter');
116
+ const { renderAntigravityConversationMarkdown } = await import('@spiracha/lib/antigravity-db');
117
+ const { getCachedAntigravityKeychainSecret } = await import('@spiracha/lib/antigravity-keychain');
118
+ const conversation = await findAntigravityConversationById(conversationId);
119
+ const keychainSecret = getCachedAntigravityKeychainSecret();
120
+ const hasKeychainSecret = Boolean(keychainSecret);
121
+
122
+ if (!canExportAntigravityConversation(conversation, hasKeychainSecret)) {
123
+ if (isAntigravityConversationLocked(conversation, hasKeychainSecret)) {
124
+ throw new Error('Unlock Antigravity Keychain access before exporting transcript logs.');
125
+ }
126
+
127
+ throw new Error(`No exportable Antigravity transcript found for conversation: ${conversationId}`);
128
+ }
129
+
130
+ const content = await runWithTranscriptLoadLimit(
131
+ () =>
132
+ renderAntigravityConversationMarkdown(conversation, {
133
+ keychainSecret,
134
+ }),
135
+ {
136
+ id: conversation.conversationId,
137
+ path: conversation.transcriptPath ?? conversation.conversationPath ?? undefined,
138
+ source: 'antigravity-ui-export',
139
+ },
140
+ );
141
+ if (!content) {
142
+ throw new Error(`No exportable Antigravity transcript found for conversation: ${conversationId}`);
143
+ }
144
+
145
+ return {
146
+ content,
147
+ conversation,
148
+ filename: `${buildConversationExportBaseName(
149
+ {
150
+ cwd: conversation.workspaceFolder,
151
+ id: conversation.conversationId,
152
+ updatedAtMs: conversation.lastUpdatedAtMs ?? conversation.conversationMtimeMs,
153
+ },
154
+ 'antigravity-conversation',
155
+ )}.md`,
156
+ };
157
+ };
158
+
159
+ export const deleteAntigravityConversationById = async (conversationId: string) => {
160
+ const { deleteAntigravityConversation } = await import('@spiracha/lib/antigravity-db');
161
+ const { resolveAntigravityRoots } = await import('@spiracha/lib/antigravity-exporter-types');
162
+ const result = await deleteAntigravityConversation(resolveAntigravityRoots(), conversationId);
163
+ if (result.deletedConversationIds.length === 0) {
164
+ throw new Error(`Antigravity conversation not found: ${conversationId}`);
165
+ }
166
+
167
+ return result;
168
+ };
169
+
170
+ export const deleteAntigravityConversationsById = async (conversationIds: string[]) => {
171
+ const { deleteAntigravityConversation } = await import('@spiracha/lib/antigravity-db');
172
+ const { resolveAntigravityRoots } = await import('@spiracha/lib/antigravity-exporter-types');
173
+ const roots = resolveAntigravityRoots();
174
+ const results = await Promise.all(
175
+ conversationIds.map((conversationId) => deleteAntigravityConversation(roots, conversationId)),
176
+ );
177
+ const deletedConversationIds = results.flatMap((result) => result.deletedConversationIds);
178
+ if (deletedConversationIds.length === 0) {
179
+ throw new Error('No Antigravity conversations were deleted');
180
+ }
181
+
182
+ return {
183
+ deletedConversationIds,
184
+ deletedPaths: results.flatMap((result) => result.deletedPaths),
185
+ };
186
+ };
187
+
188
+ export const getAntigravityConversationDetailFn = createServerFn({ method: 'GET' })
189
+ .validator(conversationSchema)
190
+ .handler(async ({ data }) => {
191
+ return loadAntigravityConversationDetail(data.conversationId);
192
+ });
193
+
194
+ export const exportAntigravityArtifactsFn = createServerFn({ method: 'POST' })
195
+ .validator(exportSchema)
196
+ .handler(async ({ data }) => {
197
+ const { renderAntigravityArtifactsMarkdown } = await import('@spiracha/lib/antigravity-db');
198
+ const conversation = await findAntigravityConversationById(data.conversationId);
199
+
200
+ const content = await renderAntigravityArtifactsMarkdown(conversation);
201
+ if (!content) {
202
+ throw new Error(`No Markdown artifacts found for conversation: ${data.conversationId}`);
203
+ }
204
+
205
+ return {
206
+ content,
207
+ filename: `${data.conversationId}-artifacts.md`,
208
+ };
209
+ });
210
+
211
+ export const exportAntigravityConversationFn = createServerFn({ method: 'POST' })
212
+ .validator(exportSchema)
213
+ .handler(async ({ data }) => {
214
+ return loadAntigravityConversationExport(data.conversationId);
215
+ });
216
+
217
+ export const exportAntigravityConversations = async (data: z.infer<typeof exportConversationsSchema>) => {
218
+ const { renderSourceSessionsDownload } = await import('./source-session-export-server');
219
+ const { listAntigravityWorkspaceGroups } = await import('@spiracha/lib/antigravity-db');
220
+ const groups = await listAntigravityWorkspaceGroups();
221
+ const groupsByKey = new Map(groups.map((group) => [group.key, group]));
222
+ const entries = await Promise.all(
223
+ data.conversationIds.map(async (conversationId) => {
224
+ const result = await loadAntigravityConversationExport(conversationId);
225
+ const conversation = result.conversation;
226
+ const projectGroup = conversation.projectId
227
+ ? groupsByKey.get(`project:${conversation.projectId}`)
228
+ : undefined;
229
+ const exportCwd = projectGroup?.label ?? conversation.workspaceFolder;
230
+ const updatedAtMs = conversation.lastUpdatedAtMs ?? conversation.conversationMtimeMs;
231
+ return {
232
+ content: result.content,
233
+ cwd: exportCwd,
234
+ fallbackBaseName: 'antigravity-conversation',
235
+ fileBaseName: buildConversationExportBaseName(
236
+ {
237
+ cwd: exportCwd,
238
+ id: conversation.conversationId,
239
+ updatedAtMs,
240
+ },
241
+ 'antigravity-conversation',
242
+ ),
243
+ sessionId: conversation.conversationId,
244
+ updatedAtMs,
245
+ };
246
+ }),
247
+ );
248
+
249
+ return renderSourceSessionsDownload({
250
+ entries,
251
+ fallbackBaseName: 'antigravity-conversations',
252
+ outputFormat: data.outputFormat,
253
+ zipArchive: data.zipArchive,
254
+ });
255
+ };
256
+
257
+ export const exportAntigravityConversationsFn = createServerFn({ method: 'POST' })
258
+ .validator(exportConversationsSchema)
259
+ .handler(async ({ data }) => {
260
+ return exportAntigravityConversations(data);
261
+ });
262
+
263
+ export const deleteAntigravityConversationFn = createServerFn({ method: 'POST' })
264
+ .validator(conversationSchema)
265
+ .handler(async ({ data }) => {
266
+ return deleteAntigravityConversationById(data.conversationId);
267
+ });
268
+
269
+ export const deleteAntigravityConversationsFn = createServerFn({ method: 'POST' })
270
+ .validator(deleteConversationsSchema)
271
+ .handler(async ({ data }) => {
272
+ return deleteAntigravityConversationsById(data.conversationIds);
273
+ });
@@ -0,0 +1,343 @@
1
+ import type { ThreadEvent, ThreadTranscriptStats } from '@spiracha/lib/codex-browser-types';
2
+ import type { JsonValue } from '@spiracha/lib/shared';
3
+
4
+ type MarkdownSection = {
5
+ body: string;
6
+ heading: string;
7
+ sequence: number;
8
+ };
9
+
10
+ type ParsedAssistantSection = {
11
+ content: string;
12
+ thinking: string;
13
+ toolCalls: ParsedToolCall[];
14
+ };
15
+
16
+ type ParsedToolCall = {
17
+ argumentsText: string | null;
18
+ name: string;
19
+ };
20
+
21
+ const HEADING_PATTERN = /^##\s+((?:User|Assistant|System|Event)|Tool:\s*.+)$/iu;
22
+ const TIMESTAMP_PATTERN = /^_Timestamp:\s*(.+?)_$/u;
23
+ const TOOL_HEADING_PATTERN = /^tool:\s*(.+)$/iu;
24
+ const CONTROL_SUBHEADING_PATTERN = /^###\s+(Thinking|Tool Calls)\s*$/iu;
25
+
26
+ const splitMarkdownSections = (markdown: string | null): MarkdownSection[] => {
27
+ if (!markdown?.trim()) {
28
+ return [];
29
+ }
30
+
31
+ const sections: MarkdownSection[] = [];
32
+ const lines = markdown.split(/\r?\n/u);
33
+ let currentHeading: string | null = null;
34
+ let currentLines: string[] = [];
35
+
36
+ const flush = () => {
37
+ if (!currentHeading) {
38
+ return;
39
+ }
40
+
41
+ sections.push({
42
+ body: currentLines.join('\n').trim(),
43
+ heading: currentHeading,
44
+ sequence: sections.length * 10,
45
+ });
46
+ };
47
+
48
+ for (const line of lines) {
49
+ const heading = HEADING_PATTERN.exec(line);
50
+ if (heading) {
51
+ flush();
52
+ currentHeading = heading[1]!.trim();
53
+ currentLines = [];
54
+ continue;
55
+ }
56
+
57
+ if (currentHeading) {
58
+ currentLines.push(line);
59
+ }
60
+ }
61
+
62
+ flush();
63
+ return sections;
64
+ };
65
+
66
+ const extractTimestamp = (body: string): { body: string; timestamp: string | null } => {
67
+ const lines = body.split(/\r?\n/u);
68
+ const timestamp = TIMESTAMP_PATTERN.exec(lines[0]?.trim() ?? '')?.[1]?.trim() ?? null;
69
+ return {
70
+ body: timestamp ? lines.slice(1).join('\n').trim() : body.trim(),
71
+ timestamp,
72
+ };
73
+ };
74
+
75
+ const sectionBodyBeforeSubheading = (body: string): string => {
76
+ const lines = body.split(/\r?\n/u);
77
+ const controlIndex = lines.findIndex((line) => CONTROL_SUBHEADING_PATTERN.test(line.trim()));
78
+ return lines
79
+ .slice(0, controlIndex === -1 ? undefined : controlIndex)
80
+ .join('\n')
81
+ .trim();
82
+ };
83
+
84
+ const extractSubheadingBlock = (body: string, title: string): string => {
85
+ const lines = body.split(/\r?\n/u);
86
+ const startIndex = lines.findIndex((line) => line.trim().toLowerCase() === `### ${title.toLowerCase()}`);
87
+ if (startIndex === -1) {
88
+ return '';
89
+ }
90
+
91
+ const nextSubheadingIndex = lines.findIndex(
92
+ (line, index) => index > startIndex && CONTROL_SUBHEADING_PATTERN.test(line.trim()),
93
+ );
94
+ return lines
95
+ .slice(startIndex + 1, nextSubheadingIndex === -1 ? undefined : nextSubheadingIndex)
96
+ .join('\n')
97
+ .trim();
98
+ };
99
+
100
+ const parseToolCalls = (body: string): ParsedToolCall[] => {
101
+ const toolCallsBlock = extractSubheadingBlock(body, 'Tool Calls');
102
+ if (!toolCallsBlock) {
103
+ return [];
104
+ }
105
+
106
+ const calls: ParsedToolCall[] = [];
107
+ const callPattern = /-\s+`([^`]+)`(?:\s*\n+```json\s*\n([\s\S]*?)\n```)?/gu;
108
+ for (const match of toolCallsBlock.matchAll(callPattern)) {
109
+ calls.push({
110
+ argumentsText: match[2]?.trim() ?? null,
111
+ name: match[1]?.trim() || 'unknown',
112
+ });
113
+ }
114
+
115
+ return calls;
116
+ };
117
+
118
+ const parseAssistantSection = (body: string): ParsedAssistantSection => {
119
+ const content = sectionBodyBeforeSubheading(body);
120
+ const thinkingBlock = extractSubheadingBlock(body, 'Thinking');
121
+ const [thinking, ...remainingThinkingBlock] = thinkingBlock.split(/\n{2,}/u).map((entry) => entry.trim());
122
+
123
+ return {
124
+ content: content || remainingThinkingBlock.join('\n\n').trim(),
125
+ thinking: thinking ?? '',
126
+ toolCalls: parseToolCalls(body),
127
+ };
128
+ };
129
+
130
+ const buildRaw = (section: MarkdownSection, extra: Record<string, JsonValue> = {}): Record<string, JsonValue> => ({
131
+ heading: section.heading,
132
+ source: 'antigravity_markdown',
133
+ ...extra,
134
+ });
135
+
136
+ const buildMessageEvent = (
137
+ section: MarkdownSection,
138
+ role: string,
139
+ text: string,
140
+ timestamp: string | null,
141
+ phase: string | null,
142
+ sequenceOffset = 0,
143
+ ): ThreadEvent => ({
144
+ isHiddenByDefault: role !== 'assistant' && role !== 'user',
145
+ kind: 'message',
146
+ memoryCitation: null,
147
+ model: null,
148
+ phase,
149
+ raw: buildRaw(section, { role }),
150
+ role,
151
+ sequence: section.sequence + sequenceOffset,
152
+ text,
153
+ timestamp,
154
+ variant: role === 'user' ? 'user_message' : role === 'assistant' ? 'agent_message' : 'message',
155
+ });
156
+
157
+ const buildToolCallEvent = (
158
+ section: MarkdownSection,
159
+ toolCall: ParsedToolCall,
160
+ timestamp: string | null,
161
+ sequenceOffset: number,
162
+ ): ThreadEvent => ({
163
+ argumentsParseFailed: false,
164
+ argumentsText: toolCall.argumentsText,
165
+ callId: null,
166
+ command: [toolCall.name, toolCall.argumentsText].filter(Boolean).join('\n'),
167
+ kind: 'tool_call',
168
+ name: toolCall.name,
169
+ raw: buildRaw(section, {
170
+ argumentsText: toolCall.argumentsText,
171
+ name: toolCall.name,
172
+ }),
173
+ sequence: section.sequence + sequenceOffset,
174
+ timestamp,
175
+ workdir: null,
176
+ });
177
+
178
+ const buildToolOutputEvent = (
179
+ section: MarkdownSection,
180
+ toolName: string,
181
+ outputText: string,
182
+ timestamp: string | null,
183
+ ): ThreadEvent => ({
184
+ callId: null,
185
+ exitCode: null,
186
+ kind: 'tool_output',
187
+ outputText,
188
+ raw: buildRaw(section, {
189
+ name: toolName,
190
+ }),
191
+ sequence: section.sequence,
192
+ summary: outputText,
193
+ timestamp,
194
+ wallTime: null,
195
+ });
196
+
197
+ const getFinalAssistantSectionSequences = (sections: MarkdownSection[]): Set<number> => {
198
+ const finalAssistantSectionSequences = new Set<number>();
199
+ let currentAssistantContentSequence: number | null = null;
200
+
201
+ const flushAssistantRun = () => {
202
+ if (currentAssistantContentSequence !== null) {
203
+ finalAssistantSectionSequences.add(currentAssistantContentSequence);
204
+ }
205
+ currentAssistantContentSequence = null;
206
+ };
207
+
208
+ for (const section of sections) {
209
+ const heading = section.heading.toLowerCase();
210
+ if (heading === 'user') {
211
+ flushAssistantRun();
212
+ continue;
213
+ }
214
+
215
+ if (heading !== 'assistant') {
216
+ continue;
217
+ }
218
+
219
+ const { body } = extractTimestamp(section.body);
220
+ const parsed = parseAssistantSection(body);
221
+ if (parsed.toolCalls.length > 0) {
222
+ currentAssistantContentSequence = null;
223
+ } else if (parsed.content) {
224
+ currentAssistantContentSequence = section.sequence;
225
+ }
226
+ }
227
+
228
+ flushAssistantRun();
229
+ return finalAssistantSectionSequences;
230
+ };
231
+
232
+ const textSectionToEvents = (
233
+ section: MarkdownSection,
234
+ role: string,
235
+ body: string,
236
+ timestamp: string | null,
237
+ ): ThreadEvent[] => {
238
+ return body ? [buildMessageEvent(section, role, body, timestamp, null)] : [];
239
+ };
240
+
241
+ const toolOutputSectionToEvents = (
242
+ section: MarkdownSection,
243
+ toolName: string,
244
+ body: string,
245
+ timestamp: string | null,
246
+ ): ThreadEvent[] => {
247
+ return body ? [buildToolOutputEvent(section, toolName, body, timestamp)] : [];
248
+ };
249
+
250
+ const assistantSectionToEvents = (
251
+ section: MarkdownSection,
252
+ body: string,
253
+ timestamp: string | null,
254
+ finalAssistantSectionSequences: Set<number>,
255
+ ): ThreadEvent[] => {
256
+ const parsed = parseAssistantSection(body);
257
+ const events: ThreadEvent[] = [];
258
+ if (parsed.thinking) {
259
+ events.push(buildMessageEvent(section, 'assistant', parsed.thinking, timestamp, 'commentary'));
260
+ }
261
+ if (parsed.content) {
262
+ const phase = finalAssistantSectionSequences.has(section.sequence) ? 'final_answer' : 'commentary';
263
+ events.push(buildMessageEvent(section, 'assistant', parsed.content, timestamp, phase, 1));
264
+ }
265
+ parsed.toolCalls.forEach((toolCall, index) => {
266
+ events.push(buildToolCallEvent(section, toolCall, timestamp, 2 + index));
267
+ });
268
+ return events;
269
+ };
270
+
271
+ const sectionToEvents = (section: MarkdownSection, finalAssistantSectionSequences: Set<number>): ThreadEvent[] => {
272
+ const { body, timestamp } = extractTimestamp(section.body);
273
+ const heading = section.heading.toLowerCase();
274
+ const toolHeading = TOOL_HEADING_PATTERN.exec(section.heading);
275
+
276
+ if (heading === 'user') {
277
+ return textSectionToEvents(section, 'user', body, timestamp);
278
+ }
279
+
280
+ if (toolHeading) {
281
+ return toolOutputSectionToEvents(section, toolHeading[1]?.trim() || 'unknown', body, timestamp);
282
+ }
283
+
284
+ if (heading === 'assistant') {
285
+ return assistantSectionToEvents(section, body, timestamp, finalAssistantSectionSequences);
286
+ }
287
+
288
+ if (heading === 'system') {
289
+ return textSectionToEvents(section, 'system', body, timestamp);
290
+ }
291
+
292
+ return textSectionToEvents(section, 'event', body, timestamp);
293
+ };
294
+
295
+ export const antigravityMarkdownToThreadEvents = (markdown: string | null): ThreadEvent[] => {
296
+ const sections = splitMarkdownSections(markdown);
297
+ const finalAssistantSectionSequences = getFinalAssistantSectionSequences(sections);
298
+ return sections.flatMap((section) => sectionToEvents(section, finalAssistantSectionSequences));
299
+ };
300
+
301
+ const updateMessageStats = (stats: ThreadTranscriptStats, event: Extract<ThreadEvent, { kind: 'message' }>) => {
302
+ stats.messageCount += 1;
303
+ if (event.role === 'assistant') {
304
+ stats.assistantMessageCount += 1;
305
+ }
306
+ if (event.role === 'user') {
307
+ stats.userMessageCount += 1;
308
+ }
309
+ if (event.phase === 'commentary') {
310
+ stats.commentaryCount += 1;
311
+ }
312
+ if (event.phase === 'final_answer') {
313
+ stats.finalAnswerCount += 1;
314
+ }
315
+ };
316
+
317
+ export const getAntigravityThreadTranscriptStats = (events: ThreadEvent[]): ThreadTranscriptStats => {
318
+ const stats: ThreadTranscriptStats = {
319
+ assistantMessageCount: 0,
320
+ commentaryCount: 0,
321
+ execCommandCount: 0,
322
+ finalAnswerCount: 0,
323
+ messageCount: 0,
324
+ toolCallCount: 0,
325
+ toolOutputCount: 0,
326
+ userMessageCount: 0,
327
+ webSearchEventCount: 0,
328
+ };
329
+
330
+ for (const event of events) {
331
+ if (event.kind === 'message') {
332
+ updateMessageStats(stats, event);
333
+ }
334
+ if (event.kind === 'tool_call') {
335
+ stats.toolCallCount += 1;
336
+ }
337
+ if (event.kind === 'tool_output') {
338
+ stats.toolOutputCount += 1;
339
+ }
340
+ }
341
+
342
+ return stats;
343
+ };
@@ -0,0 +1,34 @@
1
+ import { queryOptions } from '@tanstack/react-query';
2
+ import {
3
+ getClaudeCodeSessionDetailFn,
4
+ getClaudeCodeSessionTranscriptFn,
5
+ listClaudeCodeSessionsFn,
6
+ listClaudeCodeWorkspacesFn,
7
+ } from './claude-code-server';
8
+
9
+ export const claudeCodeWorkspacesQueryOptions = () =>
10
+ queryOptions({
11
+ queryFn: () => listClaudeCodeWorkspacesFn(),
12
+ queryKey: ['claude-code-workspaces'],
13
+ });
14
+
15
+ export const claudeCodeSessionsQueryOptions = (workspaceKey: string | null) =>
16
+ queryOptions({
17
+ enabled: workspaceKey !== null,
18
+ queryFn: () => listClaudeCodeSessionsFn({ data: { workspaceKey: workspaceKey ?? '' } }),
19
+ queryKey: ['claude-code-sessions', workspaceKey ?? 'none'],
20
+ });
21
+
22
+ export const claudeCodeSessionDetailQueryOptions = (sessionId: string | null) =>
23
+ queryOptions({
24
+ enabled: sessionId !== null,
25
+ queryFn: () => getClaudeCodeSessionDetailFn({ data: { sessionId: sessionId ?? '' } }),
26
+ queryKey: ['claude-code-session', sessionId ?? 'none'],
27
+ });
28
+
29
+ export const claudeCodeSessionTranscriptQueryOptions = (sessionId: string | null) =>
30
+ queryOptions({
31
+ enabled: sessionId !== null,
32
+ queryFn: () => getClaudeCodeSessionTranscriptFn({ data: { sessionId: sessionId ?? '' } }),
33
+ queryKey: ['claude-code-session-transcript', sessionId ?? 'none'],
34
+ });