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,386 @@
1
+ import { mapWithConcurrency } from '../concurrency';
2
+ import { antigravityConversationAdapter } from './antigravity-adapter';
3
+ import { claudeCodeConversationAdapter } from './claude-code-adapter';
4
+ import { codexConversationAdapter } from './codex-adapter';
5
+ import { cursorConversationAdapter } from './cursor-adapter';
6
+ import { grokConversationAdapter } from './grok-adapter';
7
+ import { kiroConversationAdapter } from './kiro-adapter';
8
+ import { selectConversationMessages } from './message-selector';
9
+ import { opencodeConversationAdapter } from './opencode-adapter';
10
+ import { qoderConversationAdapter } from './qoder-adapter';
11
+ import {
12
+ CONVERSATION_SOURCES,
13
+ type ConversationAdapter,
14
+ type ConversationMessage,
15
+ type ConversationMessageSelector,
16
+ type ConversationPage,
17
+ type ConversationSource,
18
+ type ConversationSourceInfo,
19
+ type DeleteConversationItemResult,
20
+ type DeleteConversationOptions,
21
+ type DeleteConversationResult,
22
+ type DeleteConversationsOptions,
23
+ type DeleteConversationsResult,
24
+ type GetConversationOptions,
25
+ type ListConversationsForPathOptions,
26
+ type ResolvedConversationRef,
27
+ } from './types';
28
+
29
+ export { selectConversationMessages } from './message-selector';
30
+ export { getConversationPathMatch, normalizeConversationPath } from './path-match';
31
+ export {
32
+ CONVERSATION_SOURCES,
33
+ type ConversationAdapter,
34
+ type ConversationDataLocations,
35
+ type ConversationDeepLinks,
36
+ type ConversationDetail,
37
+ type ConversationIdSetOptions,
38
+ type ConversationMessage,
39
+ type ConversationMessagePhase,
40
+ type ConversationMessageRole,
41
+ type ConversationMessageSelector,
42
+ type ConversationPage,
43
+ type ConversationPathMatch,
44
+ type ConversationSource,
45
+ type ConversationSourceInfo,
46
+ type ConversationZipDownload,
47
+ type DeleteConversationItemResult,
48
+ type DeleteConversationOptions,
49
+ type DeleteConversationResult,
50
+ type DeleteConversationsOptions,
51
+ type DeleteConversationsResult,
52
+ type ExportConversationsZipOptions,
53
+ type GetConversationOptions,
54
+ type ListConversationsForPathOptions,
55
+ type ResolvedConversationRef,
56
+ } from './types';
57
+
58
+ const SOURCE_LABELS: Record<ConversationSource, string> = {
59
+ antigravity: 'Antigravity',
60
+ 'claude-code': 'Claude Code',
61
+ codex: 'Codex',
62
+ cursor: 'Cursor',
63
+ grok: 'Grok',
64
+ kiro: 'Kiro',
65
+ opencode: 'OpenCode',
66
+ qoder: 'Qoder',
67
+ };
68
+
69
+ const SOURCE_INFOS: ConversationSourceInfo[] = CONVERSATION_SOURCES.map((source) => ({
70
+ label: SOURCE_LABELS[source],
71
+ source,
72
+ }));
73
+
74
+ export const isConversationSource = (value: unknown): value is ConversationSource => {
75
+ return typeof value === 'string' && (CONVERSATION_SOURCES as readonly string[]).includes(value);
76
+ };
77
+
78
+ const ADAPTERS: Partial<Record<ConversationSource, ConversationAdapter>> = {
79
+ antigravity: antigravityConversationAdapter,
80
+ 'claude-code': claudeCodeConversationAdapter,
81
+ codex: codexConversationAdapter,
82
+ cursor: cursorConversationAdapter,
83
+ grok: grokConversationAdapter,
84
+ kiro: kiroConversationAdapter,
85
+ opencode: opencodeConversationAdapter,
86
+ qoder: qoderConversationAdapter,
87
+ };
88
+
89
+ const MAX_LIMIT = 200;
90
+ const DEFAULT_LIMIT = 100;
91
+ const DELETE_CONCURRENCY_BY_SOURCE: Record<ConversationSource, number> = {
92
+ antigravity: 1,
93
+ 'claude-code': 4,
94
+ codex: 1,
95
+ cursor: 1,
96
+ grok: 1,
97
+ kiro: 1,
98
+ opencode: 2,
99
+ qoder: 1,
100
+ };
101
+
102
+ const getEnabledSources = (sources: ListConversationsForPathOptions['sources']): ConversationSource[] => {
103
+ if (!sources || sources === 'all') {
104
+ return SOURCE_INFOS.map((sourceInfo) => sourceInfo.source);
105
+ }
106
+
107
+ return sources;
108
+ };
109
+
110
+ const isAllSourcesRequest = (sources: ListConversationsForPathOptions['sources']) => !sources || sources === 'all';
111
+
112
+ const getAdapter = (source: ConversationSource): ConversationAdapter | null => {
113
+ return ADAPTERS[source] ?? null;
114
+ };
115
+
116
+ const decodeCursor = (cursor: string | null | undefined) => {
117
+ if (!cursor) {
118
+ return 0;
119
+ }
120
+
121
+ const parsed = Number.parseInt(Buffer.from(cursor, 'base64url').toString('utf8'), 10);
122
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 0;
123
+ };
124
+
125
+ const encodeCursor = (offset: number) => Buffer.from(String(offset), 'utf8').toString('base64url');
126
+
127
+ const getLimit = (limit: number | undefined) => {
128
+ if (!limit || limit <= 0) {
129
+ return DEFAULT_LIMIT;
130
+ }
131
+
132
+ return Math.min(limit, MAX_LIMIT);
133
+ };
134
+
135
+ const filterByUpdatedAt = (
136
+ conversations: Awaited<ReturnType<ConversationAdapter['listConversationsForPath']>>,
137
+ options: Pick<ListConversationsForPathOptions, 'updatedAfterMs' | 'updatedBeforeMs'>,
138
+ ) => {
139
+ return conversations.filter((conversation) => {
140
+ const updatedAtMs = conversation.updatedAtMs ?? 0;
141
+ if (options.updatedAfterMs !== undefined && updatedAtMs < options.updatedAfterMs) {
142
+ return false;
143
+ }
144
+ if (options.updatedBeforeMs !== undefined && updatedAtMs > options.updatedBeforeMs) {
145
+ return false;
146
+ }
147
+ return true;
148
+ });
149
+ };
150
+
151
+ const sortConversations = (conversations: Awaited<ReturnType<ConversationAdapter['listConversationsForPath']>>) => {
152
+ return [...conversations].sort(
153
+ (left, right) =>
154
+ (right.updatedAtMs ?? 0) - (left.updatedAtMs ?? 0) ||
155
+ left.source.localeCompare(right.source) ||
156
+ left.id.localeCompare(right.id),
157
+ );
158
+ };
159
+
160
+ export const listConversationSources = async (): Promise<ConversationSourceInfo[]> => SOURCE_INFOS;
161
+
162
+ const listSourceConversationsForPath = async (
163
+ source: ConversationSource,
164
+ options: ListConversationsForPathOptions,
165
+ ignoreSourceFailures: boolean,
166
+ ) => {
167
+ const adapter = getAdapter(source);
168
+ if (!adapter) {
169
+ return [];
170
+ }
171
+
172
+ try {
173
+ return await adapter.listConversationsForPath(options);
174
+ } catch (error) {
175
+ if (!ignoreSourceFailures) {
176
+ throw error;
177
+ }
178
+ return [];
179
+ }
180
+ };
181
+
182
+ export const listConversationsForPath = async (options: ListConversationsForPathOptions): Promise<ConversationPage> => {
183
+ const ignoreSourceFailures = isAllSourcesRequest(options.sources);
184
+ const conversations = (
185
+ await Promise.all(
186
+ getEnabledSources(options.sources).map((source) =>
187
+ listSourceConversationsForPath(source, options, ignoreSourceFailures),
188
+ ),
189
+ )
190
+ ).flat();
191
+
192
+ const sorted = sortConversations(filterByUpdatedAt(conversations, options));
193
+ const offset = decodeCursor(options.cursor);
194
+ const limit = getLimit(options.limit);
195
+ const data = sorted.slice(offset, offset + limit);
196
+ const nextOffset = offset + data.length;
197
+
198
+ return {
199
+ data,
200
+ meta: {
201
+ hasNext: nextOffset < sorted.length,
202
+ nextCursor: nextOffset < sorted.length ? encodeCursor(nextOffset) : null,
203
+ },
204
+ };
205
+ };
206
+
207
+ export const getConversation = async (options: GetConversationOptions) => {
208
+ return getAdapter(options.source)?.getConversation(options) ?? null;
209
+ };
210
+
211
+ export const deleteConversation = async (
212
+ options: DeleteConversationOptions,
213
+ ): Promise<DeleteConversationResult | null> => {
214
+ return (await getAdapter(options.source)?.deleteConversation?.(options)) ?? null;
215
+ };
216
+
217
+ export const deleteConversations = async (
218
+ options: DeleteConversationsOptions,
219
+ ): Promise<DeleteConversationsResult | null> => {
220
+ const adapter = getAdapter(options.source);
221
+ if (!adapter?.deleteConversation) {
222
+ return null;
223
+ }
224
+ const deleteAdapterConversation = adapter.deleteConversation;
225
+
226
+ const rawResults = await mapWithConcurrency(
227
+ options.ids,
228
+ DELETE_CONCURRENCY_BY_SOURCE[options.source],
229
+ async (id) => ({
230
+ id,
231
+ result: await deleteAdapterConversation({
232
+ id,
233
+ locations: options.locations,
234
+ source: options.source,
235
+ }),
236
+ }),
237
+ );
238
+ const deletedIdSet = new Set(rawResults.flatMap(({ result }) => result.deletedIds));
239
+ const results: DeleteConversationItemResult[] = rawResults.map(({ id, result }) => ({
240
+ deleted: result.deletedIds.length > 0 || deletedIdSet.has(id),
241
+ deletedFiles: result.deletedFiles,
242
+ deletedIds: result.deletedIds,
243
+ id,
244
+ }));
245
+
246
+ return {
247
+ deletedFiles: [...new Set(results.flatMap((result) => result.deletedFiles))],
248
+ deletedIds: [...deletedIdSet],
249
+ missingIds: results.filter((result) => !result.deleted).map((result) => result.id),
250
+ results,
251
+ };
252
+ };
253
+
254
+ const sourceFromSessionRoute = (segment: string): ConversationSource | null => {
255
+ if (segment === 'claude-code-sessions') {
256
+ return 'claude-code';
257
+ }
258
+ if (segment === 'grok-sessions') {
259
+ return 'grok';
260
+ }
261
+ if (segment === 'kiro-sessions') {
262
+ return 'kiro';
263
+ }
264
+ if (segment === 'qoder-sessions') {
265
+ return 'qoder';
266
+ }
267
+ if (segment === 'cursor-threads') {
268
+ return 'cursor';
269
+ }
270
+ if (segment === 'antigravity-conversations') {
271
+ return 'antigravity';
272
+ }
273
+ if (segment === 'opencode-sessions') {
274
+ return 'opencode';
275
+ }
276
+ return null;
277
+ };
278
+
279
+ const decodeRefId = (value: string | undefined): string | null => {
280
+ if (!value) {
281
+ return null;
282
+ }
283
+
284
+ try {
285
+ const decoded = decodeURIComponent(value);
286
+ return decoded.trim() ? decoded : null;
287
+ } catch {
288
+ return null;
289
+ }
290
+ };
291
+
292
+ const refFromPathSegmentAt = (segments: string[], index: number): ResolvedConversationRef | null => {
293
+ const segment = segments[index];
294
+ const next = segments[index + 1];
295
+ const nextNext = segments[index + 2];
296
+
297
+ if (segment === 'threads') {
298
+ const id = decodeRefId(next);
299
+ return id ? { id, source: 'codex' } : null;
300
+ }
301
+
302
+ if (segment === 'conversations' && isConversationSource(next)) {
303
+ const id = decodeRefId(nextNext);
304
+ return id ? { id, source: next } : null;
305
+ }
306
+
307
+ const source = segment ? sourceFromSessionRoute(segment) : null;
308
+ if (!source) {
309
+ return null;
310
+ }
311
+
312
+ const id = decodeRefId(next);
313
+ return id ? { id, source } : null;
314
+ };
315
+
316
+ const refFromPathSegments = (segments: string[]): ResolvedConversationRef | null => {
317
+ for (let index = 0; index < segments.length - 1; index += 1) {
318
+ const ref = refFromPathSegmentAt(segments, index);
319
+ if (ref) {
320
+ return ref;
321
+ }
322
+ }
323
+
324
+ return null;
325
+ };
326
+
327
+ const parseUrlRef = (ref: string): ResolvedConversationRef | null => {
328
+ let url: URL;
329
+ try {
330
+ url = new URL(ref);
331
+ } catch {
332
+ return null;
333
+ }
334
+
335
+ if (url.protocol === 'codex:' && url.hostname === 'threads') {
336
+ const id = decodeRefId(url.pathname.replace(/^\/+/u, ''));
337
+ return id ? { id, source: 'codex' } : null;
338
+ }
339
+
340
+ if (url.protocol === 'spiracha:' && url.hostname === 'conversation') {
341
+ const [source, id, extra] = url.pathname.split('/').filter(Boolean);
342
+ const decodedId = decodeRefId(id);
343
+ return isConversationSource(source) && decodedId && !extra ? { id: decodedId, source } : null;
344
+ }
345
+
346
+ return refFromPathSegments(url.pathname.split('/').filter(Boolean));
347
+ };
348
+
349
+ export const resolveConversationRef = async (ref: string): Promise<ResolvedConversationRef | null> => {
350
+ const trimmed = ref.trim();
351
+ if (!trimmed) {
352
+ return null;
353
+ }
354
+
355
+ return parseUrlRef(trimmed);
356
+ };
357
+
358
+ export const renderConversationMarkdown = (
359
+ conversation: {
360
+ messages: ConversationMessage[];
361
+ title: string | null;
362
+ },
363
+ options: {
364
+ messageSelector?: ConversationMessageSelector;
365
+ } = {},
366
+ ) => {
367
+ const selectedMessages = options.messageSelector
368
+ ? selectConversationMessages(conversation.messages, options.messageSelector)
369
+ : conversation.messages;
370
+ const title = conversation.title?.trim() || 'Conversation';
371
+ const roleLabels: Record<ConversationMessage['role'], string> = {
372
+ assistant: 'Assistant',
373
+ system: 'System',
374
+ tool: 'Tool',
375
+ unknown: 'Unknown',
376
+ user: 'User',
377
+ };
378
+ const sections = selectedMessages.map((message) => {
379
+ const text = message.text.trim() || '_No message content._';
380
+ return `## ${roleLabels[message.role]}\n\n${text}`;
381
+ });
382
+ if (sections.length === 0) {
383
+ sections.push('_No messages selected._');
384
+ }
385
+ return [`# ${title}`, ...sections].join('\n\n').trimEnd() + '\n';
386
+ };
@@ -0,0 +1,174 @@
1
+ import {
2
+ deleteKiroSession,
3
+ listKiroSessionsForGroup,
4
+ listKiroWorkspaceGroups,
5
+ readKiroSessionTranscript,
6
+ } from '../kiro-db';
7
+ import type {
8
+ KiroSessionSummary,
9
+ KiroSessionTranscript,
10
+ KiroTranscriptEntry,
11
+ KiroTranscriptPart,
12
+ } from '../kiro-exporter-types';
13
+ import { resolveKiroWorkspaceSessionsDir } from '../kiro-exporter-types';
14
+ import { getFinalKiroAssistantMessageEntryIds, getKiroMessagePhase } from '../kiro-transcript-phase';
15
+ import { cleanInlineTitle } from '../shared';
16
+ import { runWithTranscriptLoadLimit } from '../transcript-load-limiter';
17
+ import {
18
+ createDeepLinks,
19
+ createTextMessage,
20
+ finalizeMessages,
21
+ normalizeAssistantPhase,
22
+ normalizeRole,
23
+ toDateMs,
24
+ } from './adapter-helpers';
25
+ import { selectConversationMessages } from './message-selector';
26
+ import { getConversationPathMatch } from './path-match';
27
+ import type {
28
+ ConversationAdapter,
29
+ ConversationDetail,
30
+ ConversationMessage,
31
+ ConversationPathMatch,
32
+ DeleteConversationOptions,
33
+ GetConversationOptions,
34
+ ListConversationsForPathOptions,
35
+ } from './types';
36
+
37
+ const getSessionsDir = (options: { locations?: { kiroWorkspaceSessionsDir?: string } }) =>
38
+ options.locations?.kiroWorkspaceSessionsDir ?? resolveKiroWorkspaceSessionsDir();
39
+
40
+ const partToMessages = (
41
+ entry: KiroTranscriptEntry,
42
+ part: KiroTranscriptPart,
43
+ partIndex: number,
44
+ finalEntryIds: Set<string>,
45
+ ): ConversationMessage[] => {
46
+ const createdAtMs = toDateMs(entry.timestamp);
47
+ if (entry.entryType === 'tool_call') {
48
+ return createTextMessage({
49
+ createdAtMs,
50
+ id: `${entry.entryId}:${partIndex}`,
51
+ metadata: { executionId: entry.executionId },
52
+ order: partIndex,
53
+ phase: 'tool_call',
54
+ role: 'tool',
55
+ text: part.text,
56
+ });
57
+ }
58
+
59
+ return createTextMessage({
60
+ createdAtMs,
61
+ id: `${entry.entryId}:${partIndex}`,
62
+ metadata: part.imageUrl ? { imageUrl: part.imageUrl } : {},
63
+ order: partIndex,
64
+ phase: normalizeAssistantPhase(getKiroMessagePhase(entry, finalEntryIds), 'unknown'),
65
+ role: normalizeRole(entry.role),
66
+ text: part.text ?? part.imageUrl,
67
+ });
68
+ };
69
+
70
+ const transcriptToMessages = (transcript: KiroSessionTranscript) => {
71
+ const finalEntryIds = getFinalKiroAssistantMessageEntryIds(transcript.entries);
72
+ return finalizeMessages(
73
+ transcript.entries.flatMap((entry) =>
74
+ entry.parts.flatMap((part, partIndex) => partToMessages(entry, part, partIndex, finalEntryIds)),
75
+ ),
76
+ );
77
+ };
78
+
79
+ const buildConversation = async (
80
+ session: KiroSessionSummary,
81
+ sessionsDir: string,
82
+ matches: ConversationPathMatch[],
83
+ options: Pick<ListConversationsForPathOptions, 'includeMessages' | 'messageSelector'>,
84
+ loadedTranscript: KiroSessionTranscript | null = null,
85
+ ): Promise<ConversationDetail> => {
86
+ const transcript = options.includeMessages
87
+ ? (loadedTranscript ??
88
+ (await runWithTranscriptLoadLimit(() => readKiroSessionTranscript(sessionsDir, session.sessionId), {
89
+ id: session.sessionId,
90
+ path: session.filePath,
91
+ source: 'kiro-api',
92
+ })))
93
+ : null;
94
+ const allMessages = transcript ? transcriptToMessages(transcript) : [];
95
+ const messages = options.includeMessages
96
+ ? selectConversationMessages(allMessages, options.messageSelector ?? 'last_final_answer')
97
+ : [];
98
+
99
+ return {
100
+ createdAtMs: session.createdAtMs,
101
+ deepLinks: createDeepLinks('kiro', session.sessionId, `/kiro-sessions/${session.sessionId}`),
102
+ id: session.sessionId,
103
+ matches,
104
+ messageCount: options.includeMessages ? allMessages.length : session.messageCount,
105
+ messages,
106
+ metadata: {
107
+ defaultModelTitle: session.defaultModelTitle,
108
+ filePath: session.filePath,
109
+ model: session.selectedModel ?? session.defaultModelTitle,
110
+ selectedModel: session.selectedModel,
111
+ sessionType: session.sessionType,
112
+ },
113
+ source: 'kiro',
114
+ title: cleanInlineTitle(session.title),
115
+ updatedAtMs: session.lastActiveAtMs,
116
+ workspaceKey: session.workspaceKey,
117
+ workspacePath: session.worktree,
118
+ };
119
+ };
120
+
121
+ const listKiroConversationsForPath = async (options: ListConversationsForPathOptions) => {
122
+ const sessionsDir = getSessionsDir(options);
123
+ const groups = await listKiroWorkspaceGroups(sessionsDir);
124
+ const conversations: ConversationDetail[] = [];
125
+
126
+ for (const group of groups) {
127
+ const match = await getConversationPathMatch(options.cwd, group.worktree);
128
+ if (!match) {
129
+ continue;
130
+ }
131
+ const sessions = await listKiroSessionsForGroup(group.key, sessionsDir);
132
+ for (const session of sessions) {
133
+ conversations.push(await buildConversation(session, sessionsDir, [match], options));
134
+ }
135
+ }
136
+
137
+ return conversations;
138
+ };
139
+
140
+ const getKiroConversation = async (options: GetConversationOptions): Promise<ConversationDetail | null> => {
141
+ const sessionsDir = getSessionsDir(options);
142
+ const transcript = await runWithTranscriptLoadLimit(() => readKiroSessionTranscript(sessionsDir, options.id), {
143
+ id: options.id,
144
+ path: sessionsDir,
145
+ source: 'kiro-api',
146
+ });
147
+ return transcript
148
+ ? buildConversation(
149
+ transcript.session,
150
+ sessionsDir,
151
+ [],
152
+ {
153
+ includeMessages: true,
154
+ messageSelector: options.messageSelector ?? 'all',
155
+ },
156
+ transcript,
157
+ )
158
+ : null;
159
+ };
160
+
161
+ const deleteKiroConversation = async (options: DeleteConversationOptions) => {
162
+ const result = await deleteKiroSession(getSessionsDir(options), options.id);
163
+ return {
164
+ deletedFiles: result.deletedFiles,
165
+ deletedIds: result.deletedSessionIds,
166
+ };
167
+ };
168
+
169
+ export const kiroConversationAdapter: ConversationAdapter = {
170
+ deleteConversation: deleteKiroConversation,
171
+ getConversation: getKiroConversation,
172
+ listConversationsForPath: listKiroConversationsForPath,
173
+ source: 'kiro',
174
+ };
@@ -0,0 +1,37 @@
1
+ import type { ConversationMessage, ConversationMessageSelector } from './types';
2
+
3
+ const latestByOrder = (messages: ConversationMessage[]) => {
4
+ let latest: ConversationMessage | null = null;
5
+ for (const message of messages) {
6
+ if (!latest || message.order > latest.order) {
7
+ latest = message;
8
+ }
9
+ }
10
+ return latest;
11
+ };
12
+
13
+ const selectLastAssistantMessage = (messages: ConversationMessage[]) => {
14
+ return latestByOrder(messages.filter((message) => message.role === 'assistant'));
15
+ };
16
+
17
+ // Not every integration can identify final answers. In that case, API list/export defaults still
18
+ // return the latest assistant message instead of silently omitting the conversation.
19
+ const selectLastFinalAnswer = (messages: ConversationMessage[]) => {
20
+ return (
21
+ latestByOrder(messages.filter((message) => message.role === 'assistant' && message.phase === 'final_answer')) ??
22
+ selectLastAssistantMessage(messages)
23
+ );
24
+ };
25
+
26
+ export const selectConversationMessages = (
27
+ messages: ConversationMessage[],
28
+ selector: ConversationMessageSelector,
29
+ ): ConversationMessage[] => {
30
+ if (selector === 'all') {
31
+ return messages;
32
+ }
33
+
34
+ const selected =
35
+ selector === 'last_assistant' ? selectLastAssistantMessage(messages) : selectLastFinalAnswer(messages);
36
+ return selected ? [selected] : [];
37
+ };