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
@@ -1,4 +1,4 @@
1
- import { readdir, stat } from 'node:fs/promises';
1
+ import { readdir, rm, stat } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
3
  import {
4
4
  type AntigravityArtifact,
@@ -11,6 +11,7 @@ import {
11
11
  resolveAntigravityRoots,
12
12
  } from './antigravity-exporter-types';
13
13
  import { decryptAntigravitySafeStoragePayload } from './antigravity-keychain';
14
+ import { resolveAntigravityProjectNames } from './antigravity-projects';
14
15
  import { mapWithConcurrency } from './concurrency';
15
16
 
16
17
  type ProtoField = {
@@ -25,6 +26,7 @@ type SummaryEntry = {
25
26
  createdAtMs: number | null;
26
27
  indexedItemCount: number | null;
27
28
  lastUpdatedAtMs: number | null;
29
+ projectId: string | null;
28
30
  summaryPath: string;
29
31
  title: string;
30
32
  workspaceFolder: string | null;
@@ -33,6 +35,11 @@ type SummaryEntry = {
33
35
  workspaceUri: string | null;
34
36
  };
35
37
 
38
+ export type DeleteAntigravityConversationResult = {
39
+ deletedConversationIds: string[];
40
+ deletedPaths: string[];
41
+ };
42
+
36
43
  type ConversationFile = {
37
44
  bytes: number;
38
45
  mtimeMs: number;
@@ -49,11 +56,21 @@ type TranscriptFile = {
49
56
  bytes: number;
50
57
  entryCount: number;
51
58
  mtimeMs: number;
59
+ model: string | null;
52
60
  path: string;
53
61
  root: string;
54
62
  source: Exclude<AntigravityTranscriptSource, 'safe-storage'>;
55
63
  };
56
64
 
65
+ export type AntigravityConversationMessage = {
66
+ createdAtMs: number | null;
67
+ metadata: Record<string, unknown>;
68
+ order: number;
69
+ phase: 'final_answer' | 'reasoning' | 'tool_call' | 'tool_output' | 'unknown';
70
+ role: 'assistant' | 'system' | 'tool' | 'unknown' | 'user';
71
+ text: string;
72
+ };
73
+
57
74
  type WorkspaceInfo = Pick<SummaryEntry, 'workspaceFolder' | 'workspaceKey' | 'workspaceLabel' | 'workspaceUri'>;
58
75
 
59
76
  const UNKNOWN_WORKSPACE: WorkspaceInfo = {
@@ -260,8 +277,8 @@ const parseContextWorkspaceInfo = (field: ProtoField | null): WorkspaceInfo | nu
260
277
  // Antigravity summary parsing is reverse-engineered from agyhub_summaries_proto.pb:
261
278
  // entry field 1 = conversation id, entry field 2 = summary message. Inside that summary,
262
279
  // field 1 = title, 2 = indexed item count, 3 = last-updated timestamp, 7 = created timestamp,
263
- // 9 = workspace info, and 17 = context workspace info. parseWorkspaceInfo uses nested fields
264
- // 1/2 for URI variants; parseContextWorkspaceInfo uses field 7 or nested workspace field 1.
280
+ // 9 = workspace info, and 17 = context metadata. Context field 18 is the Antigravity
281
+ // project id; workspace parsing uses context field 7 or nested workspace field 1.
265
282
  const parseSummaryEntry = (entryField: ProtoField, summaryPath: string): SummaryEntry | null => {
266
283
  try {
267
284
  const entryFields = nestedFields(entryField);
@@ -272,6 +289,7 @@ const parseSummaryEntry = (entryField: ProtoField, summaryPath: string): Summary
272
289
  }
273
290
 
274
291
  const summaryFields = nestedFields(summaryBytes);
292
+ const contextFields = nestedFields(firstField(summaryFields, 17));
275
293
  const workspace =
276
294
  parseWorkspaceInfo(firstField(summaryFields, 9)) ??
277
295
  parseContextWorkspaceInfo(firstField(summaryFields, 17)) ??
@@ -283,6 +301,7 @@ const parseSummaryEntry = (entryField: ProtoField, summaryPath: string): Summary
283
301
  createdAtMs: parseTimestampMs(firstField(summaryFields, 7)),
284
302
  indexedItemCount: fieldNumberValue(summaryFields, 2),
285
303
  lastUpdatedAtMs: parseTimestampMs(firstField(summaryFields, 3)),
304
+ projectId: fieldString(contextFields, 18),
286
305
  summaryPath,
287
306
  title: cleanTitle(fieldString(summaryFields, 1), conversationId),
288
307
  };
@@ -307,6 +326,84 @@ export const readAntigravitySummaryIndex = async (summaryPath: string): Promise<
307
326
  }
308
327
  };
309
328
 
329
+ const getFieldBounds = (
330
+ buffer: Uint8Array,
331
+ start: number,
332
+ ): {
333
+ end: number;
334
+ fieldNumber: number;
335
+ payloadEnd: number;
336
+ payloadStart: number;
337
+ wireType: number;
338
+ } => {
339
+ const key = readVarint(buffer, start, buffer.length);
340
+ const fieldNumber = key.value >> 3;
341
+ const wireType = key.value & 7;
342
+ let index = key.next;
343
+
344
+ if (wireType === 0) {
345
+ const value = readVarint(buffer, index, buffer.length);
346
+ return { end: value.next, fieldNumber, payloadEnd: value.next, payloadStart: index, wireType };
347
+ }
348
+
349
+ if (wireType === 1) {
350
+ return { end: index + 8, fieldNumber, payloadEnd: index + 8, payloadStart: index, wireType };
351
+ }
352
+
353
+ if (wireType === 2) {
354
+ const length = readVarint(buffer, index, buffer.length);
355
+ index = length.next;
356
+ return {
357
+ end: index + length.value,
358
+ fieldNumber,
359
+ payloadEnd: index + length.value,
360
+ payloadStart: index,
361
+ wireType,
362
+ };
363
+ }
364
+
365
+ if (wireType === 5) {
366
+ return { end: index + 4, fieldNumber, payloadEnd: index + 4, payloadStart: index, wireType };
367
+ }
368
+
369
+ throw new Error(`Unsupported protobuf wire type: ${wireType}`);
370
+ };
371
+
372
+ const removeConversationFromSummaryIndex = async (summaryPath: string, conversationId: string): Promise<boolean> => {
373
+ if (!(await pathExists(summaryPath))) {
374
+ return false;
375
+ }
376
+
377
+ const buffer = new Uint8Array(await Bun.file(summaryPath).arrayBuffer());
378
+ const retained: Uint8Array[] = [];
379
+ let removed = false;
380
+ let index = 0;
381
+
382
+ while (index < buffer.length) {
383
+ const bounds = getFieldBounds(buffer, index);
384
+ const fieldBytes = buffer.slice(index, bounds.end);
385
+ const shouldRemove =
386
+ bounds.fieldNumber === 1 &&
387
+ bounds.wireType === 2 &&
388
+ fieldString(parseProtoFields(buffer, bounds.payloadStart, bounds.payloadEnd), 1) === conversationId;
389
+
390
+ if (shouldRemove) {
391
+ removed = true;
392
+ } else {
393
+ retained.push(fieldBytes);
394
+ }
395
+
396
+ index = bounds.end;
397
+ }
398
+
399
+ if (!removed) {
400
+ return false;
401
+ }
402
+
403
+ await Bun.write(summaryPath, Buffer.concat(retained));
404
+ return true;
405
+ };
406
+
310
407
  const preferConversationFile = (
311
408
  current: ConversationFile | undefined,
312
409
  candidate: ConversationFile,
@@ -489,20 +586,91 @@ const countJsonlEntries = async (filePath: string): Promise<number> => {
489
586
  }
490
587
  };
491
588
 
589
+ const stripModelQualifier = (value: string): string => value.replace(/\s*\([^)]*\)\s*$/u, '').trim();
590
+
591
+ const extractModelSelection = (content: string): string | null => {
592
+ const marker = '`Model Selection`';
593
+ const markerIndex = content.indexOf(marker);
594
+ if (markerIndex < 0) {
595
+ return null;
596
+ }
597
+
598
+ const toIndex = content.indexOf(' to ', markerIndex + marker.length);
599
+ if (toIndex < 0) {
600
+ return null;
601
+ }
602
+
603
+ const candidate = content.slice(toIndex + ' to '.length);
604
+ const endMarkers = ['. No need', '. If reporting', '</USER_SETTINGS_CHANGE>', '\n'];
605
+ const endIndex = endMarkers.reduce<number | null>((earliest, endMarker) => {
606
+ const index = candidate.indexOf(endMarker);
607
+ return index < 0 || (earliest !== null && index >= earliest) ? earliest : index;
608
+ }, null);
609
+ const rawModel = (endIndex === null ? candidate : candidate.slice(0, endIndex)).trim();
610
+ return rawModel ? stripModelQualifier(rawModel) : null;
611
+ };
612
+
613
+ const extractTranscriptModel = async (filePath: string): Promise<string | null> => {
614
+ const text = await Bun.file(filePath)
615
+ .text()
616
+ .catch(() => '');
617
+ for (const entry of parseLogEntries(text)) {
618
+ const model = extractModelSelection(getString(entry.content) ?? '');
619
+ if (model) {
620
+ return model;
621
+ }
622
+ }
623
+
624
+ return null;
625
+ };
626
+
492
627
  const preferTranscriptFile = (current: TranscriptFile | undefined, candidate: TranscriptFile): TranscriptFile => {
493
628
  if (!current) {
494
629
  return candidate;
495
630
  }
496
631
 
632
+ const sourceRank = (source: TranscriptFile['source']) => (source === 'transcript' ? 2 : 1);
633
+ const candidateRank = sourceRank(candidate.source);
634
+ const currentRank = sourceRank(current.source);
635
+ if (candidateRank !== currentRank) {
636
+ return candidateRank > currentRank ? candidate : current;
637
+ }
638
+
497
639
  if (candidate.mtimeMs !== current.mtimeMs) {
498
640
  return candidate.mtimeMs > current.mtimeMs ? candidate : current;
499
641
  }
500
642
 
501
- if (candidate.source !== current.source) {
502
- return candidate.source === 'overview' ? candidate : current;
643
+ if (candidate.entryCount !== current.entryCount) {
644
+ return candidate.entryCount > current.entryCount ? candidate : current;
503
645
  }
504
646
 
505
- return candidate.entryCount > current.entryCount ? candidate : current;
647
+ return candidate.bytes > current.bytes ? candidate : current;
648
+ };
649
+
650
+ const readTranscriptFileCandidate = async (
651
+ root: string,
652
+ logsDir: string,
653
+ candidate: { name: string; source: TranscriptFile['source'] },
654
+ ): Promise<TranscriptFile | null> => {
655
+ const transcriptPath = path.join(logsDir, candidate.name);
656
+ try {
657
+ const info = await stat(transcriptPath);
658
+ if (!info.isFile()) {
659
+ return null;
660
+ }
661
+
662
+ return {
663
+ bytes: info.size,
664
+ entryCount: await countJsonlEntries(transcriptPath),
665
+ model: await extractTranscriptModel(transcriptPath),
666
+ mtimeMs: info.mtimeMs,
667
+ path: transcriptPath,
668
+ root,
669
+ source: candidate.source,
670
+ };
671
+ } catch {
672
+ return null;
673
+ }
506
674
  };
507
675
 
508
676
  const readTranscriptFilesForRoot = async (root: string): Promise<Map<string, TranscriptFile>> => {
@@ -522,28 +690,14 @@ const readTranscriptFilesForRoot = async (root: string): Promise<Map<string, Tra
522
690
 
523
691
  const logsDir = path.join(brainDir, entry.name, '.system_generated', 'logs');
524
692
  for (const candidate of [
525
- { name: 'overview.txt', source: 'overview' as const },
693
+ { name: 'transcript_full.jsonl', source: 'transcript' as const },
526
694
  { name: 'transcript.jsonl', source: 'transcript' as const },
695
+ { name: 'overview.txt', source: 'overview' as const },
527
696
  ]) {
528
- const transcriptPath = path.join(logsDir, candidate.name);
529
- try {
530
- const info = await stat(transcriptPath);
531
- if (!info.isFile()) {
532
- continue;
533
- }
534
-
535
- transcripts.set(
536
- entry.name,
537
- preferTranscriptFile(transcripts.get(entry.name), {
538
- bytes: info.size,
539
- entryCount: await countJsonlEntries(transcriptPath),
540
- mtimeMs: info.mtimeMs,
541
- path: transcriptPath,
542
- root,
543
- source: candidate.source,
544
- }),
545
- );
546
- } catch {}
697
+ const transcript = await readTranscriptFileCandidate(root, logsDir, candidate);
698
+ if (transcript) {
699
+ transcripts.set(entry.name, preferTranscriptFile(transcripts.get(entry.name), transcript));
700
+ }
547
701
  }
548
702
  }
549
703
 
@@ -625,6 +779,8 @@ const toConversation = (
625
779
  ): AntigravityConversation => {
626
780
  const fallbackTitle = artifacts[0]?.summary ?? conversationId;
627
781
  const artifactBytes = artifacts.reduce((total, artifact) => total + artifact.bytes, 0);
782
+ const conversationBytes = file?.bytes ?? 0;
783
+ const transcriptBytes = transcript?.bytes ?? 0;
628
784
  const workspace = resolveConversationWorkspace(summary, file, transcript, artifacts);
629
785
  const lastUpdatedAtMs = resolveConversationLastUpdatedAt(artifacts, file, summary, transcript);
630
786
  const sourceRoot = resolveConversationSourceRoot(file, transcript, artifacts);
@@ -633,17 +789,20 @@ const toConversation = (
633
789
  artifactBytes,
634
790
  artifactCount: artifacts.length,
635
791
  artifacts,
636
- conversationBytes: file?.bytes ?? 0,
792
+ conversationBytes,
637
793
  conversationId,
638
794
  conversationMtimeMs: file?.mtimeMs ?? null,
639
795
  conversationPath: file?.path ?? null,
640
796
  createdAtMs: summary?.createdAtMs ?? null,
641
797
  indexedItemCount: summary?.indexedItemCount ?? null,
642
798
  lastUpdatedAtMs,
799
+ model: transcript?.model ?? null,
800
+ projectId: summary?.projectId ?? null,
643
801
  sourceRoot,
644
802
  summaryPath: summary?.summaryPath ?? null,
645
803
  title: summary?.title ?? cleanTitle(fallbackTitle, conversationId),
646
- transcriptBytes: transcript?.bytes ?? 0,
804
+ totalBytes: conversationBytes + transcriptBytes + artifactBytes,
805
+ transcriptBytes,
647
806
  transcriptEntryCount: transcript?.entryCount ?? 0,
648
807
  transcriptPath: transcript?.path ?? null,
649
808
  transcriptSource: resolveConversationTranscriptSource(file, transcript),
@@ -685,25 +844,30 @@ export const listAntigravityConversations = async (
685
844
 
686
845
  export const groupAntigravityConversations = (
687
846
  conversations: AntigravityConversation[],
847
+ projectNames: ReadonlyMap<string, string> = new Map(),
688
848
  ): AntigravityWorkspaceGroup[] => {
689
849
  const groups = new Map<string, AntigravityWorkspaceGroup>();
690
850
  for (const conversation of conversations) {
691
- const current = groups.get(conversation.workspaceKey) ?? {
851
+ const projectName = conversation.projectId ? projectNames.get(conversation.projectId) : null;
852
+ const groupKey = conversation.projectId ? `project:${conversation.projectId}` : conversation.workspaceKey;
853
+ const current = groups.get(groupKey) ?? {
692
854
  artifactCount: 0,
693
855
  conversationBytes: 0,
694
856
  conversationCount: 0,
695
- key: conversation.workspaceKey,
696
- label: conversation.workspaceLabel,
857
+ key: groupKey,
858
+ label: projectName ?? conversation.workspaceLabel,
697
859
  lastActiveMs: 0,
860
+ totalBytes: 0,
698
861
  transcriptCount: 0,
699
- uri: conversation.workspaceUri,
862
+ uri: conversation.projectId ? null : conversation.workspaceUri,
700
863
  };
701
864
  current.artifactCount += conversation.artifactCount;
702
865
  current.conversationBytes += conversation.conversationBytes;
703
866
  current.conversationCount += 1;
704
867
  current.lastActiveMs = Math.max(current.lastActiveMs, conversation.lastUpdatedAtMs ?? 0);
705
868
  current.transcriptCount += conversation.transcriptEntryCount > 0 ? 1 : 0;
706
- groups.set(conversation.workspaceKey, current);
869
+ current.totalBytes += conversation.totalBytes;
870
+ groups.set(groupKey, current);
707
871
  }
708
872
 
709
873
  return [...groups.values()].sort((a, b) => b.lastActiveMs - a.lastActiveMs || a.label.localeCompare(b.label));
@@ -712,16 +876,67 @@ export const groupAntigravityConversations = (
712
876
  export const listAntigravityWorkspaceGroups = async (
713
877
  roots = resolveAntigravityRoots(),
714
878
  ): Promise<AntigravityWorkspaceGroup[]> => {
715
- return groupAntigravityConversations(await listAntigravityConversations(roots));
879
+ const conversations = await listAntigravityConversations(roots);
880
+ const projectNames = await resolveAntigravityProjectNames(
881
+ conversations.flatMap((conversation) => (conversation.projectId ? [conversation.projectId] : [])),
882
+ );
883
+ return groupAntigravityConversations(conversations, projectNames);
716
884
  };
717
885
 
718
886
  export const listAntigravityConversationsForGroup = async (
719
887
  workspaceKey: string,
720
888
  roots = resolveAntigravityRoots(),
721
889
  ): Promise<AntigravityConversation[]> => {
722
- return (await listAntigravityConversations(roots)).filter(
723
- (conversation) => conversation.workspaceKey === workspaceKey,
724
- );
890
+ return (await listAntigravityConversations(roots)).filter((conversation) => {
891
+ const conversationGroupKey = conversation.projectId
892
+ ? `project:${conversation.projectId}`
893
+ : conversation.workspaceKey;
894
+ return conversationGroupKey === workspaceKey;
895
+ });
896
+ };
897
+
898
+ const existingAntigravityDeletePaths = async (root: string, conversationId: string): Promise<string[]> => {
899
+ const conversationPath = path.join(getAntigravityConversationDir(root), `${conversationId}.pb`);
900
+ const artifactDir = path.join(getAntigravityBrainDir(root), conversationId);
901
+ const logsDir = path.join(artifactDir, '.system_generated', 'logs');
902
+ const candidates = [
903
+ conversationPath,
904
+ path.join(logsDir, 'overview.txt'),
905
+ path.join(logsDir, 'transcript.jsonl'),
906
+ path.join(logsDir, 'transcript_full.jsonl'),
907
+ artifactDir,
908
+ ];
909
+ const exists = await Promise.all(candidates.map(pathExists));
910
+ return candidates.filter((_, index) => exists[index]);
911
+ };
912
+
913
+ export const deleteAntigravityConversation = async (
914
+ roots: string[],
915
+ conversationId: string,
916
+ ): Promise<DeleteAntigravityConversationResult> => {
917
+ if (!isSafeConversationId(conversationId)) {
918
+ return { deletedConversationIds: [], deletedPaths: [] };
919
+ }
920
+
921
+ const deletedPaths: string[] = [];
922
+ let deletedSummary = false;
923
+
924
+ for (const root of roots) {
925
+ deletedSummary =
926
+ (await removeConversationFromSummaryIndex(getAntigravitySummaryIndexPath(root), conversationId)) ||
927
+ deletedSummary;
928
+
929
+ const rootPaths = await existingAntigravityDeletePaths(root, conversationId);
930
+ deletedPaths.push(...rootPaths);
931
+
932
+ await rm(path.join(getAntigravityConversationDir(root), `${conversationId}.pb`), { force: true });
933
+ await rm(path.join(getAntigravityBrainDir(root), conversationId), { force: true, recursive: true });
934
+ }
935
+
936
+ return {
937
+ deletedConversationIds: deletedSummary || deletedPaths.length > 0 ? [conversationId] : [],
938
+ deletedPaths: [...new Set(deletedPaths)],
939
+ };
725
940
  };
726
941
 
727
942
  export const renderAntigravityArtifactsMarkdown = async (
@@ -853,7 +1068,7 @@ const renderLogEntry = (entry: AntigravityLogEntry): string[] => {
853
1068
  const heading = logEntryHeading(entry);
854
1069
  const timestamp = getString(entry.created_at);
855
1070
  const content = cleanLogContent(entry);
856
- const thinking = getString(entry.thinking);
1071
+ const thinking = getString(entry.thinking) ?? '';
857
1072
  const parts = [`## ${heading}`, ''];
858
1073
 
859
1074
  if (timestamp) {
@@ -872,6 +1087,135 @@ const renderLogEntry = (entry: AntigravityLogEntry): string[] => {
872
1087
  return parts;
873
1088
  };
874
1089
 
1090
+ const logEntryCreatedAtMs = (entry: AntigravityLogEntry): number | null => {
1091
+ const timestamp = getString(entry.created_at);
1092
+ if (!timestamp) {
1093
+ return null;
1094
+ }
1095
+
1096
+ const parsed = Date.parse(timestamp);
1097
+ return Number.isFinite(parsed) ? parsed : null;
1098
+ };
1099
+
1100
+ const logEntryOrder = (entry: AntigravityLogEntry, fallback: number): number => {
1101
+ return typeof entry.step_index === 'number' && Number.isFinite(entry.step_index) ? entry.step_index : fallback;
1102
+ };
1103
+
1104
+ const isAssistantLogEntry = (entry: AntigravityLogEntry): boolean => {
1105
+ return getString(entry.source) === 'MODEL' && getString(entry.type) === 'PLANNER_RESPONSE';
1106
+ };
1107
+
1108
+ const logEntryRole = (entry: AntigravityLogEntry): AntigravityConversationMessage['role'] => {
1109
+ const source = getString(entry.source);
1110
+ if (source?.startsWith('USER')) {
1111
+ return 'user';
1112
+ }
1113
+ if (isAssistantLogEntry(entry)) {
1114
+ return 'assistant';
1115
+ }
1116
+ if (source === 'SYSTEM') {
1117
+ return 'system';
1118
+ }
1119
+ if (source === 'MODEL') {
1120
+ return 'tool';
1121
+ }
1122
+ return 'unknown';
1123
+ };
1124
+
1125
+ const logEntryPhase = (entry: AntigravityLogEntry): AntigravityConversationMessage['phase'] => {
1126
+ const role = logEntryRole(entry);
1127
+ if (role === 'assistant') {
1128
+ return 'final_answer';
1129
+ }
1130
+ if (role === 'tool') {
1131
+ return 'tool_output';
1132
+ }
1133
+ return 'unknown';
1134
+ };
1135
+
1136
+ const logEntryMetadata = (entry: AntigravityLogEntry): Record<string, unknown> => ({
1137
+ source: getString(entry.source),
1138
+ status: getString(entry.status),
1139
+ type: getString(entry.type),
1140
+ });
1141
+
1142
+ const toolCallsText = (toolCalls: unknown): string => {
1143
+ if (!Array.isArray(toolCalls)) {
1144
+ return '';
1145
+ }
1146
+
1147
+ return toolCalls
1148
+ .flatMap((call) => {
1149
+ if (!call || typeof call !== 'object') {
1150
+ return [];
1151
+ }
1152
+ const { args, name } = call as { args?: unknown; name?: unknown };
1153
+ return [JSON.stringify({ args, name: typeof name === 'string' ? name : 'unknown' })];
1154
+ })
1155
+ .join('\n');
1156
+ };
1157
+
1158
+ const logEntryToMessages = (entry: AntigravityLogEntry, index: number): AntigravityConversationMessage[] => {
1159
+ const order = logEntryOrder(entry, index);
1160
+ const createdAtMs = logEntryCreatedAtMs(entry);
1161
+ const role = logEntryRole(entry);
1162
+ const phase = logEntryPhase(entry);
1163
+ const metadata = logEntryMetadata(entry);
1164
+ const messages: AntigravityConversationMessage[] = [];
1165
+ const thinking = getString(entry.thinking)?.trim();
1166
+ if (thinking && role === 'assistant') {
1167
+ messages.push({
1168
+ createdAtMs,
1169
+ metadata,
1170
+ order,
1171
+ phase: 'reasoning',
1172
+ role: 'assistant',
1173
+ text: thinking,
1174
+ });
1175
+ }
1176
+
1177
+ const content = cleanLogContent(entry);
1178
+ if (content) {
1179
+ messages.push({
1180
+ createdAtMs,
1181
+ metadata,
1182
+ order,
1183
+ phase,
1184
+ role,
1185
+ text: content,
1186
+ });
1187
+ }
1188
+
1189
+ const calls = toolCallsText(entry.tool_calls);
1190
+ if (calls) {
1191
+ messages.push({
1192
+ createdAtMs,
1193
+ metadata,
1194
+ order,
1195
+ phase: 'tool_call',
1196
+ role: 'tool',
1197
+ text: calls,
1198
+ });
1199
+ }
1200
+
1201
+ return messages;
1202
+ };
1203
+
1204
+ export const readAntigravityConversationMessages = async (
1205
+ conversation: AntigravityConversation,
1206
+ ): Promise<AntigravityConversationMessage[]> => {
1207
+ if (!conversation.transcriptPath || !conversation.transcriptSource) {
1208
+ return [];
1209
+ }
1210
+
1211
+ try {
1212
+ const entries = parseLogEntries(await Bun.file(conversation.transcriptPath).text());
1213
+ return entries.flatMap(logEntryToMessages);
1214
+ } catch {
1215
+ return [];
1216
+ }
1217
+ };
1218
+
875
1219
  const renderAntigravityTranscriptMarkdown = async (conversation: AntigravityConversation): Promise<string | null> => {
876
1220
  if (!conversation.transcriptPath || !conversation.transcriptSource) {
877
1221
  return null;
@@ -886,6 +1230,7 @@ const renderAntigravityTranscriptMarkdown = async (conversation: AntigravityConv
886
1230
  conversation.transcriptSource === 'overview'
887
1231
  ? 'antigravity_overview_transcript'
888
1232
  : 'antigravity_jsonl_transcript';
1233
+ const sections = entries.flatMap((entry) => renderLogEntry(entry));
889
1234
  const parts = [
890
1235
  `# ${conversation.title}`,
891
1236
  '',
@@ -893,12 +1238,9 @@ const renderAntigravityTranscriptMarkdown = async (conversation: AntigravityConv
893
1238
  `- conversation_id: \`${conversation.conversationId}\``,
894
1239
  conversation.workspaceUri ? `- workspace: \`${conversation.workspaceUri}\`` : '',
895
1240
  '',
1241
+ ...sections,
896
1242
  ].filter(Boolean);
897
1243
 
898
- for (const entry of entries) {
899
- parts.push(...renderLogEntry(entry));
900
- }
901
-
902
1244
  return `${parts.join('\n').trimEnd()}\n`;
903
1245
  };
904
1246
 
@@ -922,9 +1264,37 @@ const renderDecryptedSafeStorageMarkdown = (conversation: AntigravityConversatio
922
1264
  .join('\n');
923
1265
  };
924
1266
 
1267
+ const renderAntigravitySummaryMarkdown = (conversation: AntigravityConversation): string | null => {
1268
+ if (conversation.artifactCount > 0) {
1269
+ return null;
1270
+ }
1271
+
1272
+ if (!conversation.summaryPath && conversation.indexedItemCount === null) {
1273
+ return null;
1274
+ }
1275
+
1276
+ return [
1277
+ `# ${conversation.title}`,
1278
+ '',
1279
+ '- exported_from: `antigravity_summary_index`',
1280
+ `- conversation_id: \`${conversation.conversationId}\``,
1281
+ conversation.workspaceUri ? `- workspace: \`${conversation.workspaceUri}\`` : '',
1282
+ conversation.indexedItemCount !== null ? `- indexed_items: \`${conversation.indexedItemCount}\`` : '',
1283
+ conversation.createdAtMs ? `- created_at: \`${new Date(conversation.createdAtMs).toISOString()}\`` : '',
1284
+ conversation.lastUpdatedAtMs ? `- updated_at: \`${new Date(conversation.lastUpdatedAtMs).toISOString()}\`` : '',
1285
+ '',
1286
+ 'No local transcript log was found for this Antigravity conversation. The export contains the summary index metadata that Antigravity retained.',
1287
+ '',
1288
+ ]
1289
+ .filter(Boolean)
1290
+ .join('\n');
1291
+ };
1292
+
925
1293
  export const renderAntigravityConversationMarkdown = async (
926
1294
  conversation: AntigravityConversation,
927
- options: { keychainSecret?: string | null } = {},
1295
+ options: {
1296
+ keychainSecret?: string | null;
1297
+ } = {},
928
1298
  ): Promise<string | null> => {
929
1299
  const transcript = await renderAntigravityTranscriptMarkdown(conversation);
930
1300
  if (transcript) {
@@ -939,5 +1309,5 @@ export const renderAntigravityConversationMarkdown = async (
939
1309
  }
940
1310
  }
941
1311
 
942
- return null;
1312
+ return renderAntigravitySummaryMarkdown(conversation);
943
1313
  };
@@ -45,9 +45,12 @@ export type AntigravityConversation = {
45
45
  createdAtMs: number | null;
46
46
  indexedItemCount: number | null;
47
47
  lastUpdatedAtMs: number | null;
48
+ model: string | null;
49
+ projectId: string | null;
48
50
  sourceRoot: string | null;
49
51
  summaryPath: string | null;
50
52
  title: string;
53
+ totalBytes: number;
51
54
  transcriptBytes: number;
52
55
  transcriptEntryCount: number;
53
56
  transcriptPath: string | null;
@@ -66,5 +69,6 @@ export type AntigravityWorkspaceGroup = {
66
69
  label: string;
67
70
  lastActiveMs: number;
68
71
  transcriptCount: number;
72
+ totalBytes: number;
69
73
  uri: string | null;
70
74
  };