spiracha 1.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/AGENTS.md +114 -205
  2. package/README.md +89 -269
  3. package/apps/ui/AGENTS.md +17 -7
  4. package/apps/ui/README.md +34 -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 +206 -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 +124 -0
  11. package/apps/ui/src/components/breadcrumbs.tsx +53 -0
  12. package/apps/ui/src/components/claude-code-sessions-table.tsx +114 -0
  13. package/apps/ui/src/components/claude-code-workspaces-table.tsx +55 -0
  14. package/apps/ui/src/components/cursor-threads-table.tsx +189 -0
  15. package/apps/ui/src/components/cursor-workspaces-table.tsx +140 -0
  16. package/apps/ui/src/components/data-table.tsx +241 -0
  17. package/apps/ui/src/components/delete-confirm-dialog.tsx +88 -0
  18. package/apps/ui/src/components/export-dialog.tsx +184 -0
  19. package/apps/ui/src/components/json-panel.tsx +17 -0
  20. package/apps/ui/src/components/kiro-sessions-table.tsx +112 -0
  21. package/apps/ui/src/components/kiro-workspaces-table.tsx +53 -0
  22. package/apps/ui/src/components/list-search-input.tsx +18 -0
  23. package/apps/ui/src/components/loading-panel.tsx +23 -0
  24. package/apps/ui/src/components/metadata-section.tsx +31 -0
  25. package/apps/ui/src/components/metric-card.tsx +19 -0
  26. package/apps/ui/src/components/opencode-sessions-table.tsx +128 -0
  27. package/apps/ui/src/components/opencode-workspaces-table.tsx +57 -0
  28. package/apps/ui/src/components/page-header.tsx +33 -0
  29. package/apps/ui/src/components/projects-loading-state.tsx +74 -0
  30. package/apps/ui/src/components/projects-table.tsx +108 -0
  31. package/apps/ui/src/components/qoder-sessions-table.tsx +112 -0
  32. package/apps/ui/src/components/qoder-workspaces-table.tsx +53 -0
  33. package/apps/ui/src/components/recent-threads-list.tsx +52 -0
  34. package/apps/ui/src/components/reload-error-panel.tsx +20 -0
  35. package/apps/ui/src/components/text-document-panel.tsx +19 -0
  36. package/apps/ui/src/components/theme-toggle.tsx +48 -0
  37. package/apps/ui/src/components/threads-table.tsx +202 -0
  38. package/apps/ui/src/components/transcript-view.tsx +552 -0
  39. package/apps/ui/src/components/ui/alert-dialog.tsx +160 -0
  40. package/apps/ui/src/components/ui/badge.tsx +45 -0
  41. package/apps/ui/src/components/ui/button.tsx +62 -0
  42. package/apps/ui/src/components/ui/checkbox.tsx +29 -0
  43. package/apps/ui/src/components/ui/dialog.tsx +137 -0
  44. package/apps/ui/src/components/ui/dropdown-menu.tsx +217 -0
  45. package/apps/ui/src/components/ui/input.tsx +21 -0
  46. package/apps/ui/src/components/ui/scroll-area.tsx +46 -0
  47. package/apps/ui/src/components/ui/select.tsx +163 -0
  48. package/apps/ui/src/components/ui/separator.tsx +28 -0
  49. package/apps/ui/src/components/ui/sheet.tsx +107 -0
  50. package/apps/ui/src/components/ui/skeleton.tsx +7 -0
  51. package/apps/ui/src/components/ui/table.tsx +76 -0
  52. package/apps/ui/src/components/ui/tabs.tsx +71 -0
  53. package/apps/ui/src/components/ui/tooltip.tsx +44 -0
  54. package/apps/ui/src/integrations/tanstack-query/devtools.tsx +6 -0
  55. package/apps/ui/src/integrations/tanstack-query/root-provider.tsx +10 -0
  56. package/apps/ui/src/lib/antigravity-conversation-state.ts +28 -0
  57. package/apps/ui/src/lib/antigravity-queries.ts +33 -0
  58. package/apps/ui/src/lib/antigravity-server.ts +128 -0
  59. package/apps/ui/src/lib/antigravity-transcript-events.ts +335 -0
  60. package/apps/ui/src/lib/claude-code-queries.ts +26 -0
  61. package/apps/ui/src/lib/claude-code-server.ts +75 -0
  62. package/apps/ui/src/lib/claude-code-transcript-events.ts +154 -0
  63. package/apps/ui/src/lib/codex-queries.ts +66 -0
  64. package/apps/ui/src/lib/codex-server.ts +209 -0
  65. package/apps/ui/src/lib/cursor-queries.ts +37 -0
  66. package/apps/ui/src/lib/cursor-server.ts +272 -0
  67. package/apps/ui/src/lib/cursor-transcript-events.ts +229 -0
  68. package/apps/ui/src/lib/download.ts +166 -0
  69. package/apps/ui/src/lib/formatters.ts +149 -0
  70. package/apps/ui/src/lib/kiro-queries.ts +22 -0
  71. package/apps/ui/src/lib/kiro-server.ts +73 -0
  72. package/apps/ui/src/lib/kiro-transcript-events.ts +113 -0
  73. package/apps/ui/src/lib/opencode-queries.ts +37 -0
  74. package/apps/ui/src/lib/opencode-server.ts +73 -0
  75. package/apps/ui/src/lib/opencode-transcript-events.ts +221 -0
  76. package/apps/ui/src/lib/package-metadata.ts +16 -0
  77. package/apps/ui/src/lib/path-utils.ts +13 -0
  78. package/apps/ui/src/lib/qoder-queries.ts +22 -0
  79. package/apps/ui/src/lib/qoder-server.ts +79 -0
  80. package/apps/ui/src/lib/qoder-transcript-events.ts +139 -0
  81. package/apps/ui/src/lib/route-search.ts +68 -0
  82. package/apps/ui/src/lib/settings-store.tsx +59 -0
  83. package/apps/ui/src/lib/source-session-export-server.ts +56 -0
  84. package/apps/ui/src/lib/text-filter.ts +22 -0
  85. package/apps/ui/src/lib/thread-id.ts +3 -0
  86. package/apps/ui/src/lib/thread-transcript-stats.ts +57 -0
  87. package/apps/ui/src/lib/utils.ts +7 -0
  88. package/apps/ui/src/routeTree.gen.ts +730 -0
  89. package/apps/ui/src/router.tsx +20 -0
  90. package/apps/ui/src/routes/$threadId.tsx +22 -0
  91. package/apps/ui/src/routes/__root.tsx +127 -0
  92. package/apps/ui/src/routes/analytics.tsx +143 -0
  93. package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +438 -0
  94. package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +127 -0
  95. package/apps/ui/src/routes/antigravity.index.tsx +51 -0
  96. package/apps/ui/src/routes/api.v1.conversation-query.ts +12 -0
  97. package/apps/ui/src/routes/api.v1.conversations.$source.$id.export.ts +12 -0
  98. package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +12 -0
  99. package/apps/ui/src/routes/api.v1.conversations.ts +12 -0
  100. package/apps/ui/src/routes/api.v1.resolve.ts +12 -0
  101. package/apps/ui/src/routes/api.v1.sources.ts +12 -0
  102. package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +342 -0
  103. package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +135 -0
  104. package/apps/ui/src/routes/claude-code.index.tsx +48 -0
  105. package/apps/ui/src/routes/codex.$project.tsx +390 -0
  106. package/apps/ui/src/routes/codex.index.tsx +116 -0
  107. package/apps/ui/src/routes/cursor-threads.$composerId.tsx +435 -0
  108. package/apps/ui/src/routes/cursor.$workspaceKey.tsx +416 -0
  109. package/apps/ui/src/routes/cursor.index.tsx +120 -0
  110. package/apps/ui/src/routes/index.tsx +124 -0
  111. package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +345 -0
  112. package/apps/ui/src/routes/kiro.$workspaceKey.tsx +136 -0
  113. package/apps/ui/src/routes/kiro.index.tsx +48 -0
  114. package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +334 -0
  115. package/apps/ui/src/routes/opencode.$workspaceKey.tsx +135 -0
  116. package/apps/ui/src/routes/opencode.index.tsx +48 -0
  117. package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +341 -0
  118. package/apps/ui/src/routes/qoder.$workspaceKey.tsx +139 -0
  119. package/apps/ui/src/routes/qoder.index.tsx +48 -0
  120. package/apps/ui/src/routes/settings.tsx +91 -0
  121. package/apps/ui/src/routes/threads.$threadId.tsx +619 -0
  122. package/apps/ui/src/styles.css +122 -0
  123. package/apps/ui/tsconfig.json +29 -0
  124. package/apps/ui/vite.config.ts +84 -0
  125. package/bin/spiracha.ts +32 -0
  126. package/package.json +46 -73
  127. package/src/client.ts +290 -0
  128. package/src/lib/antigravity-db.ts +213 -19
  129. package/src/lib/antigravity-exporter-types.ts +1 -0
  130. package/src/lib/codex-analytics.ts +1 -1
  131. package/src/lib/codex-browser-db.ts +410 -74
  132. package/src/lib/codex-browser-export.ts +6 -14
  133. package/src/lib/codex-browser-types.ts +1 -1
  134. package/src/lib/{codex-exporter-types.ts → codex-thread-types.ts} +2 -30
  135. package/src/lib/{codex-exporter-transcript.ts → codex-transcript-renderer.ts} +64 -28
  136. package/src/lib/conversation-api.ts +792 -0
  137. package/src/lib/conversation-data/adapter-helpers.ts +110 -0
  138. package/src/lib/conversation-data/antigravity-adapter.ts +148 -0
  139. package/src/lib/conversation-data/claude-code-adapter.ts +175 -0
  140. package/src/lib/conversation-data/codex-adapter.ts +245 -0
  141. package/src/lib/conversation-data/cursor-adapter.ts +171 -0
  142. package/src/lib/conversation-data/index.ts +311 -0
  143. package/src/lib/conversation-data/kiro-adapter.ts +140 -0
  144. package/src/lib/conversation-data/message-selector.ts +37 -0
  145. package/src/lib/conversation-data/opencode-adapter.ts +180 -0
  146. package/src/lib/conversation-data/path-match.ts +79 -0
  147. package/src/lib/conversation-data/qoder-adapter.ts +230 -0
  148. package/src/lib/conversation-data/types.ts +116 -0
  149. package/src/lib/cursor-db.ts +67 -21
  150. package/src/lib/cursor-exporter-types.ts +0 -19
  151. package/src/lib/qoder-acp-client.ts +268 -0
  152. package/src/lib/qoder-db.ts +1601 -0
  153. package/src/lib/qoder-exporter-types.ts +114 -0
  154. package/src/lib/qoder-transcript-phase.ts +41 -0
  155. package/src/lib/qoder-transcript.ts +112 -0
  156. package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +0 -1
  157. package/apps/ui/dist/client/assets/analytics-DOy1b6Sh.js +0 -1
  158. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-DqySVO2K.js +0 -7
  159. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-KAcXtNxI.js +0 -1
  160. package/apps/ui/dist/client/assets/antigravity-keychain-panel-B77qJz6f.js +0 -1
  161. package/apps/ui/dist/client/assets/antigravity._workspaceKey-B3NM6gRH.js +0 -1
  162. package/apps/ui/dist/client/assets/antigravity._workspaceKey-ByitGWki.js +0 -1
  163. package/apps/ui/dist/client/assets/antigravity.index-DP9JC2P9.js +0 -1
  164. package/apps/ui/dist/client/assets/antigravity.index-DgW25FEV.js +0 -1
  165. package/apps/ui/dist/client/assets/badge-C3i4OKs8.js +0 -1
  166. package/apps/ui/dist/client/assets/checkbox-CdHitXWQ.js +0 -1
  167. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-8pQ55ci2.js +0 -1
  168. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-DVz5UmtU.js +0 -1
  169. package/apps/ui/dist/client/assets/claude-code._workspaceKey-BBKskSum.js +0 -1
  170. package/apps/ui/dist/client/assets/claude-code._workspaceKey-OkikMUFs.js +0 -1
  171. package/apps/ui/dist/client/assets/claude-code.index-Cwu76dbb.js +0 -1
  172. package/apps/ui/dist/client/assets/claude-code.index-D6eMd08t.js +0 -1
  173. package/apps/ui/dist/client/assets/createServerFn-B-KkwmHU.js +0 -3
  174. package/apps/ui/dist/client/assets/cursor-threads._composerId-CmBFclK8.js +0 -1
  175. package/apps/ui/dist/client/assets/cursor-threads._composerId-hBWlP1D-.js +0 -1
  176. package/apps/ui/dist/client/assets/cursor._workspaceKey-BFPkIRi-.js +0 -1
  177. package/apps/ui/dist/client/assets/cursor._workspaceKey-CaAZjGmm.js +0 -1
  178. package/apps/ui/dist/client/assets/cursor.index-8y4o20kb.js +0 -2
  179. package/apps/ui/dist/client/assets/cursor.index-CrnMwDCi.js +0 -1
  180. package/apps/ui/dist/client/assets/data-table-Br78_dk3.js +0 -4
  181. package/apps/ui/dist/client/assets/delete-confirm-dialog-Bxs07u-j.js +0 -7
  182. package/apps/ui/dist/client/assets/dist-B9pyYCVU.js +0 -1
  183. package/apps/ui/dist/client/assets/dist-BrJhN2A0.js +0 -5
  184. package/apps/ui/dist/client/assets/dist-Cmd3AIfD.js +0 -1
  185. package/apps/ui/dist/client/assets/dist-DvMS2965.js +0 -1
  186. package/apps/ui/dist/client/assets/download-Bf0QJKD3.js +0 -1
  187. package/apps/ui/dist/client/assets/dropdown-menu-D5cvPaZt.js +0 -1
  188. package/apps/ui/dist/client/assets/es2015-ad6040dw.js +0 -41
  189. package/apps/ui/dist/client/assets/export-dialog-Dr8d2MqD.js +0 -1
  190. package/apps/ui/dist/client/assets/formatters-BtqyrX_c.js +0 -1
  191. package/apps/ui/dist/client/assets/index-C-STgIH4.js +0 -166
  192. package/apps/ui/dist/client/assets/jsx-runtime-DGeXAQPT.js +0 -1
  193. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-CKgfJ7GR.js +0 -1
  194. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-zvIJHtQF.js +0 -1
  195. package/apps/ui/dist/client/assets/kiro._workspaceKey-DhVuJuZB.js +0 -1
  196. package/apps/ui/dist/client/assets/kiro._workspaceKey-QArsjkTY.js +0 -1
  197. package/apps/ui/dist/client/assets/kiro.index-C-fr4m7i.js +0 -1
  198. package/apps/ui/dist/client/assets/kiro.index-OYgAdtZd.js +0 -1
  199. package/apps/ui/dist/client/assets/metric-card-Dplm0ZiM.js +0 -1
  200. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-DLjiTst-.js +0 -1
  201. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-biBwrRbt.js +0 -8
  202. package/apps/ui/dist/client/assets/opencode._workspaceKey-C7OIzMOJ.js +0 -1
  203. package/apps/ui/dist/client/assets/opencode._workspaceKey-sBakX0oI.js +0 -1
  204. package/apps/ui/dist/client/assets/opencode.index-Bl_kNs9N.js +0 -1
  205. package/apps/ui/dist/client/assets/opencode.index-CN53bVmb.js +0 -1
  206. package/apps/ui/dist/client/assets/page-header-Cwa3p6Tl.js +0 -1
  207. package/apps/ui/dist/client/assets/preload-helper-B8fFrdxC.js +0 -1
  208. package/apps/ui/dist/client/assets/projects._project-D8WloxQN.js +0 -1
  209. package/apps/ui/dist/client/assets/projects._project-DSDwH4NF.js +0 -1
  210. package/apps/ui/dist/client/assets/projects.index-5xRtuJdX.js +0 -3
  211. package/apps/ui/dist/client/assets/projects.index-DEfhWqa8.js +0 -1
  212. package/apps/ui/dist/client/assets/react-dom-DL96Jor4.js +0 -1
  213. package/apps/ui/dist/client/assets/refresh-ccw-BgKjOiA6.js +0 -1
  214. package/apps/ui/dist/client/assets/reload-error-panel-AHqu0akK.js +0 -1
  215. package/apps/ui/dist/client/assets/routes-DnzF_9CX.js +0 -1
  216. package/apps/ui/dist/client/assets/scroll-text-fM0sMOB3.js +0 -1
  217. package/apps/ui/dist/client/assets/select-CYF6pF37.js +0 -1
  218. package/apps/ui/dist/client/assets/settings-Dx70jgP_.js +0 -1
  219. package/apps/ui/dist/client/assets/sqlite-error-B6uZjUe8.js +0 -1
  220. package/apps/ui/dist/client/assets/styles-B7Zi9EFA.css +0 -1
  221. package/apps/ui/dist/client/assets/tabs-CmuhkT-c.js +0 -7
  222. package/apps/ui/dist/client/assets/text-filter-DVAZySUS.js +0 -2
  223. package/apps/ui/dist/client/assets/thread-transcript-stats-BUNz6u7F.js +0 -1
  224. package/apps/ui/dist/client/assets/threads._threadId-BB9tTsV4.js +0 -1
  225. package/apps/ui/dist/client/assets/threads._threadId-BMRSFow3.js +0 -1
  226. package/apps/ui/dist/client/assets/useMutation-BSFult2i.js +0 -1
  227. package/apps/ui/dist/client/assets/useQuery-CjINKZf1.js +0 -1
  228. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CQ8Jjs3B.js +0 -387
  229. package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +0 -6
  230. package/apps/ui/dist/server/assets/analytics-CYP_LT5Y.js +0 -16
  231. package/apps/ui/dist/server/assets/analytics-CtpOMVMO.js +0 -146
  232. package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +0 -16
  233. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BKOyL2T6.js +0 -613
  234. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +0 -11
  235. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-eS87Dx7g.js +0 -20
  236. package/apps/ui/dist/server/assets/antigravity-db-Bh8_U9uw.js +0 -580
  237. package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +0 -126
  238. package/apps/ui/dist/server/assets/antigravity-keychain-panel-CC7FLmAK.js +0 -55
  239. package/apps/ui/dist/server/assets/antigravity-queries-CGrJO9Vr.js +0 -37
  240. package/apps/ui/dist/server/assets/antigravity-server-CHRjVFqN.js +0 -114
  241. package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +0 -11
  242. package/apps/ui/dist/server/assets/antigravity._workspaceKey-B0QeYUOh.js +0 -28
  243. package/apps/ui/dist/server/assets/antigravity._workspaceKey-C3kP-qyN.js +0 -210
  244. package/apps/ui/dist/server/assets/antigravity.index-CPCYkqCi.js +0 -104
  245. package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +0 -11
  246. package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +0 -26
  247. package/apps/ui/dist/server/assets/button-CmTDnzOn.js +0 -46
  248. package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +0 -19
  249. package/apps/ui/dist/server/assets/claude-code-db-Ik3VStKZ.js +0 -361
  250. package/apps/ui/dist/server/assets/claude-code-queries-Cgzi4K-e.js +0 -37
  251. package/apps/ui/dist/server/assets/claude-code-server-PfraClXS.js +0 -72
  252. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-C55oe6zj.js +0 -18
  253. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-D1RYYi3j.js +0 -473
  254. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-DSvPLEUL.js +0 -11
  255. package/apps/ui/dist/server/assets/claude-code-transcript-C-bxh3cS.js +0 -139
  256. package/apps/ui/dist/server/assets/claude-code-transcript-phase-DmUMc8VU.js +0 -10
  257. package/apps/ui/dist/server/assets/claude-code._workspaceKey-B5Xg_-tE.js +0 -28
  258. package/apps/ui/dist/server/assets/claude-code._workspaceKey-BPlzyXPa.js +0 -11
  259. package/apps/ui/dist/server/assets/claude-code._workspaceKey-DqDve2wl.js +0 -191
  260. package/apps/ui/dist/server/assets/claude-code.index-B7yYR7dD.js +0 -92
  261. package/apps/ui/dist/server/assets/claude-code.index-BUHThG1W.js +0 -11
  262. package/apps/ui/dist/server/assets/codex-queries-CtgeZ7VL.js +0 -99
  263. package/apps/ui/dist/server/assets/codex-server-CGXU4H8-.js +0 -2294
  264. package/apps/ui/dist/server/assets/concurrency-VXtYvlGh.js +0 -18
  265. package/apps/ui/dist/server/assets/createServerRpc-CF_DEwnm.js +0 -12
  266. package/apps/ui/dist/server/assets/createSsrRpc-C754NPki.js +0 -16
  267. package/apps/ui/dist/server/assets/cursor-db-CZnYy7aT.js +0 -830
  268. package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +0 -34
  269. package/apps/ui/dist/server/assets/cursor-queries-NCIM0Nat.js +0 -67
  270. package/apps/ui/dist/server/assets/cursor-recovery-CXpO8KcD.js +0 -361
  271. package/apps/ui/dist/server/assets/cursor-server-DNu52A3K.js +0 -213
  272. package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +0 -11
  273. package/apps/ui/dist/server/assets/cursor-threads._composerId-Ckn6ItHI.js +0 -582
  274. package/apps/ui/dist/server/assets/cursor-threads._composerId-p9-ARAzc.js +0 -18
  275. package/apps/ui/dist/server/assets/cursor-transcript-B7tGnqtn.js +0 -125
  276. package/apps/ui/dist/server/assets/cursor._workspaceKey-CZuohIUL.js +0 -28
  277. package/apps/ui/dist/server/assets/cursor._workspaceKey-DPp5JSjy.js +0 -401
  278. package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +0 -11
  279. package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +0 -11
  280. package/apps/ui/dist/server/assets/cursor.index-DkWT-mxw.js +0 -189
  281. package/apps/ui/dist/server/assets/data-table-Cdct823O.js +0 -189
  282. package/apps/ui/dist/server/assets/delete-confirm-dialog-BcBNCxWB.js +0 -144
  283. package/apps/ui/dist/server/assets/download-DMmiy1xf.js +0 -92
  284. package/apps/ui/dist/server/assets/dropdown-menu-Dy_9t6TN.js +0 -36
  285. package/apps/ui/dist/server/assets/empty-plugin-adapters-B3lHh1La.js +0 -5
  286. package/apps/ui/dist/server/assets/export-dialog-D88ze9Gy.js +0 -240
  287. package/apps/ui/dist/server/assets/formatters-FJaGZgJk.js +0 -91
  288. package/apps/ui/dist/server/assets/kiro-db--fXrED_-.js +0 -552
  289. package/apps/ui/dist/server/assets/kiro-queries-CzNlM2ok.js +0 -37
  290. package/apps/ui/dist/server/assets/kiro-server-9WRxg2Au.js +0 -72
  291. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-CRY2c7YO.js +0 -11
  292. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-F1UlwxmR.js +0 -449
  293. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-bvTulT7C.js +0 -18
  294. package/apps/ui/dist/server/assets/kiro-transcript-DoekQBaH.js +0 -112
  295. package/apps/ui/dist/server/assets/kiro-transcript-phase-CJG40nQg.js +0 -27
  296. package/apps/ui/dist/server/assets/kiro._workspaceKey-BDe9sQwo.js +0 -11
  297. package/apps/ui/dist/server/assets/kiro._workspaceKey-CJsjgNwO.js +0 -28
  298. package/apps/ui/dist/server/assets/kiro._workspaceKey-D_-4Qb7y.js +0 -193
  299. package/apps/ui/dist/server/assets/kiro.index-C__-UROk.js +0 -11
  300. package/apps/ui/dist/server/assets/kiro.index-CmTbqeYj.js +0 -93
  301. package/apps/ui/dist/server/assets/loading-panel-BGFnWseS.js +0 -27
  302. package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +0 -23
  303. package/apps/ui/dist/server/assets/model-label-B1NWGc65.js +0 -13
  304. package/apps/ui/dist/server/assets/opencode-db-BM7KjOzc.js +0 -397
  305. package/apps/ui/dist/server/assets/opencode-queries-BeNYXnQv.js +0 -50
  306. package/apps/ui/dist/server/assets/opencode-server-BpQ_kRze.js +0 -72
  307. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-CGQ-t0vD.js +0 -518
  308. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-D8Q7in_Z.js +0 -18
  309. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-DKOvi0lV.js +0 -11
  310. package/apps/ui/dist/server/assets/opencode-think-tags-CAoD-EcZ.js +0 -87
  311. package/apps/ui/dist/server/assets/opencode-transcript-BNTcGNym.js +0 -141
  312. package/apps/ui/dist/server/assets/opencode-transcript-phase-OqLkiQD0.js +0 -32
  313. package/apps/ui/dist/server/assets/opencode._workspaceKey-BdqcWHw1.js +0 -11
  314. package/apps/ui/dist/server/assets/opencode._workspaceKey-CfH96HTT.js +0 -28
  315. package/apps/ui/dist/server/assets/opencode._workspaceKey-DdbHPDrO.js +0 -207
  316. package/apps/ui/dist/server/assets/opencode.index-BbVzkJXP.js +0 -11
  317. package/apps/ui/dist/server/assets/opencode.index-Vh_Gq_1L.js +0 -93
  318. package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +0 -29
  319. package/apps/ui/dist/server/assets/path-transforms-DL2IwtYd.js +0 -31
  320. package/apps/ui/dist/server/assets/projects._project-4io5LO0E.js +0 -20
  321. package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +0 -12
  322. package/apps/ui/dist/server/assets/projects._project-D6ZoGhJ8.js +0 -395
  323. package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +0 -12
  324. package/apps/ui/dist/server/assets/projects.index-BkLiF2FF.js +0 -182
  325. package/apps/ui/dist/server/assets/projects.index-DesYXwfi.js +0 -14
  326. package/apps/ui/dist/server/assets/reload-error-panel-BJMxY3U1.js +0 -25
  327. package/apps/ui/dist/server/assets/route-search-ts4W9MJ9.js +0 -38
  328. package/apps/ui/dist/server/assets/router-Sac2DGk6.js +0 -518
  329. package/apps/ui/dist/server/assets/routes-Bsact1uB.js +0 -184
  330. package/apps/ui/dist/server/assets/routes-BzkJgq4W.js +0 -34
  331. package/apps/ui/dist/server/assets/select-GW76p-ld.js +0 -76
  332. package/apps/ui/dist/server/assets/settings-OayxIYQQ.js +0 -100
  333. package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +0 -52
  334. package/apps/ui/dist/server/assets/shared-DyhChtHf.js +0 -137
  335. package/apps/ui/dist/server/assets/source-session-export-server-DNutCawb.js +0 -38
  336. package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +0 -13
  337. package/apps/ui/dist/server/assets/start-B_HFwkkk.js +0 -4
  338. package/apps/ui/dist/server/assets/tabs-DkaChNVg.js +0 -501
  339. package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +0 -36
  340. package/apps/ui/dist/server/assets/thread-transcript-stats-Dh34mt2u.js +0 -45
  341. package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +0 -26
  342. package/apps/ui/dist/server/assets/threads._threadId-BeXEc4Lo.js +0 -648
  343. package/apps/ui/dist/server/assets/threads._threadId-Ci0S4mKU.js +0 -18
  344. package/apps/ui/dist/server/assets/ui-export-files-BHLX9bhN.js +0 -83
  345. package/apps/ui/dist/server/assets/utils-C_uf36nf.js +0 -8
  346. package/apps/ui/dist/server/server.js +0 -5895
  347. package/bin/codex-chats-claude.js +0 -5
  348. package/bin/codex-chats.js +0 -5
  349. package/bin/spiracha.js +0 -5
  350. package/src/export-chats.ts +0 -120
  351. package/src/export-claude.ts +0 -36
  352. package/src/export-cursor.ts +0 -244
  353. package/src/lib/claude-exporter.ts +0 -864
  354. package/src/lib/codex-exporter-cli.ts +0 -277
  355. package/src/lib/codex-exporter-db.ts +0 -319
  356. package/src/lib/codex-exporter.ts +0 -115
  357. package/src/lib/cursor-exporter.ts +0 -266
  358. package/src/lib/interactive-cli.ts +0 -433
  359. package/src/lib/native-open.ts +0 -54
  360. package/src/mcp-server.ts +0 -137
  361. package/src/spiracha.ts +0 -116
  362. package/src/ui-cli.ts +0 -310
  363. /package/apps/ui/{dist/client → public}/icon.svg +0 -0
  364. /package/apps/ui/{dist/client → public}/manifest.json +0 -0
  365. /package/apps/ui/{dist/client → public}/robots.txt +0 -0
@@ -1,830 +0,0 @@
1
- import { i as asString, n as asNumber, r as asObject } from "./shared-DyhChtHf.js";
2
- import { getCursorGlobalDbPath, getCursorProjectsDir, getCursorWorkspaceStorageDir, resolveCursorUserDir } from "./cursor-exporter-types-CI3goo-c.js";
3
- import { createHash } from "node:crypto";
4
- import { readdir, stat } from "node:fs/promises";
5
- import path from "node:path";
6
- import { Database, constants } from "bun:sqlite";
7
- //#region ../../src/lib/cursor-db.ts
8
- var CURSOR_READONLY_DB_OPEN_FLAGS = constants.SQLITE_OPEN_READONLY | constants.SQLITE_OPEN_URI;
9
- var getCursorReadonlyDbUri = (dbPath) => {
10
- const normalizedPath = dbPath.replace(/\\/gu, "/");
11
- return `file://${(normalizedPath.startsWith("/") ? normalizedPath : `/${normalizedPath}`).split("/").map((segment) => /^[A-Za-z]:$/u.test(segment) ? segment : encodeURIComponent(segment)).join("/")}?immutable=1`;
12
- };
13
- var openCursorReadonlyDb = (dbPath) => {
14
- return new Database(getCursorReadonlyDbUri(dbPath), CURSOR_READONLY_DB_OPEN_FLAGS);
15
- };
16
- var pathExists = async (target) => {
17
- try {
18
- await stat(target);
19
- return true;
20
- } catch {
21
- return false;
22
- }
23
- };
24
- var isMissingOrUnreadableCursorStoreError = (error) => {
25
- const code = error.code;
26
- return code === "ENOENT" || code === "ENOTDIR" || code === "SQLITE_CANTOPEN";
27
- };
28
- var readItemValue = (db, key) => {
29
- const row = db.query("SELECT value FROM ItemTable WHERE key = ?").get(key);
30
- if (!row?.value) return null;
31
- try {
32
- return JSON.parse(row.value);
33
- } catch {
34
- return null;
35
- }
36
- };
37
- var readKvValue = (db, key) => {
38
- const row = db.query("SELECT value FROM cursorDiskKV WHERE key = ?").get(key);
39
- if (!row?.value) return null;
40
- try {
41
- return JSON.parse(row.value);
42
- } catch {
43
- return null;
44
- }
45
- };
46
- var decodeCursorUri = (uri) => {
47
- if (!uri) return "";
48
- if (uri.startsWith("file://")) return decodeURIComponent(uri.slice(7));
49
- return uri;
50
- };
51
- var normalizeCursorPath = (value) => {
52
- const decoded = decodeCursorUri(value.trim());
53
- if (!decoded) return "";
54
- return decoded.replace(/\/+$/u, "") || decoded;
55
- };
56
- var warnCursorDataIssue = (event, details) => {
57
- console.warn(`[spiracha:cursor] ${event}`, details);
58
- };
59
- var stripJsonComments = (value) => {
60
- return value.replace(/\/\*[\s\S]*?\*\//gu, "").replace(/(^|\s)\/\/.*$/gmu, "$1");
61
- };
62
- var parseCodeWorkspaceJson = (text) => {
63
- try {
64
- return JSON.parse(text);
65
- } catch {
66
- return JSON.parse(stripJsonComments(text));
67
- }
68
- };
69
- var parseCodeWorkspaceFolders = async (workspaceFilePath) => {
70
- if (!workspaceFilePath.endsWith(".code-workspace")) return [];
71
- try {
72
- const data = parseCodeWorkspaceJson(await Bun.file(workspaceFilePath).text());
73
- const folders = [];
74
- for (const entry of data.folders ?? []) {
75
- const folderPath = entry.path;
76
- if (!folderPath) continue;
77
- folders.push(folderPath.startsWith("/") ? normalizeCursorPath(folderPath) : normalizeCursorPath(path.join(path.dirname(workspaceFilePath), folderPath)));
78
- }
79
- return folders;
80
- } catch (error) {
81
- warnCursorDataIssue("invalid_code_workspace_json", {
82
- error: error instanceof Error ? error.message : String(error),
83
- workspaceFilePath
84
- });
85
- return [];
86
- }
87
- };
88
- var loadGlobalComposerHeaders = (globalDbPath) => {
89
- try {
90
- const db = openCursorReadonlyDb(globalDbPath);
91
- try {
92
- return readItemValue(db, "composer.composerHeaders")?.allComposers ?? [];
93
- } finally {
94
- db.close();
95
- }
96
- } catch (error) {
97
- warnCursorDataIssue("global_composer_headers_unavailable", {
98
- error: error instanceof Error ? error.message : String(error),
99
- globalDbPath
100
- });
101
- return [];
102
- }
103
- };
104
- var readBucketWorkspaceJson = async (workspaceJsonPath) => {
105
- try {
106
- return await Bun.file(workspaceJsonPath).json();
107
- } catch {
108
- return null;
109
- }
110
- };
111
- var resolveBucketIdentity = async (wsData, bucketId) => {
112
- if (wsData.folder) {
113
- const folder = normalizeCursorPath(wsData.folder);
114
- return {
115
- folders: folder ? [folder] : [],
116
- kind: "folder",
117
- label: folder ? path.basename(folder) : bucketId,
118
- uri: wsData.folder
119
- };
120
- }
121
- if (wsData.workspace) {
122
- const workspacePath = normalizeCursorPath(wsData.workspace);
123
- return {
124
- folders: workspacePath ? await parseCodeWorkspaceFolders(workspacePath) : [],
125
- kind: "workspace",
126
- label: workspacePath ? path.basename(workspacePath) : bucketId,
127
- uri: wsData.workspace
128
- };
129
- }
130
- return {
131
- folders: [],
132
- kind: "unknown",
133
- label: bucketId,
134
- uri: ""
135
- };
136
- };
137
- var readBucketComposerIds = (dbPath) => {
138
- try {
139
- const db = openCursorReadonlyDb(dbPath);
140
- try {
141
- return (readItemValue(db, "composer.composerData")?.allComposers ?? []).map((entry) => entry.composerId).filter((value) => Boolean(value));
142
- } finally {
143
- db.close();
144
- }
145
- } catch {
146
- return [];
147
- }
148
- };
149
- var loadCursorBuckets = async (userDir = resolveCursorUserDir()) => {
150
- const workspaceStorageDir = getCursorWorkspaceStorageDir(userDir);
151
- let bucketIds = [];
152
- try {
153
- bucketIds = await readdir(workspaceStorageDir);
154
- } catch {
155
- return [];
156
- }
157
- const globalDbPath = getCursorGlobalDbPath(userDir);
158
- const headerIdsByBucket = /* @__PURE__ */ new Map();
159
- if (await pathExists(globalDbPath)) for (const header of loadGlobalComposerHeaders(globalDbPath)) {
160
- const id = header.workspaceIdentifier?.id;
161
- if (id && header.composerId) {
162
- const set = headerIdsByBucket.get(id) ?? /* @__PURE__ */ new Set();
163
- set.add(header.composerId);
164
- headerIdsByBucket.set(id, set);
165
- }
166
- }
167
- const buckets = [];
168
- for (const bucketId of bucketIds) {
169
- const bucket = await buildBucket(workspaceStorageDir, bucketId, headerIdsByBucket);
170
- if (bucket) buckets.push(bucket);
171
- }
172
- return buckets;
173
- };
174
- var buildBucket = async (workspaceStorageDir, bucketId, headerIdsByBucket) => {
175
- const root = path.join(workspaceStorageDir, bucketId);
176
- const workspaceJsonPath = path.join(root, "workspace.json");
177
- const dbPath = path.join(root, "state.vscdb");
178
- if (!await pathExists(workspaceJsonPath) || !await pathExists(dbPath)) return null;
179
- const wsData = await readBucketWorkspaceJson(workspaceJsonPath);
180
- if (!wsData || !wsData.folder && !wsData.workspace) return null;
181
- let identity;
182
- let dbStat;
183
- let composerIds;
184
- try {
185
- identity = await resolveBucketIdentity(wsData, bucketId);
186
- dbStat = await stat(dbPath);
187
- composerIds = readBucketComposerIds(dbPath);
188
- } catch (error) {
189
- if (isMissingOrUnreadableCursorStoreError(error)) return null;
190
- throw error;
191
- }
192
- const headerIds = headerIdsByBucket.get(bucketId) ?? /* @__PURE__ */ new Set();
193
- const threadComposerIds = [...new Set([...composerIds, ...headerIds])];
194
- return {
195
- bucketId,
196
- composerCount: composerIds.length,
197
- dbPath,
198
- dbSizeBytes: dbStat.size,
199
- folders: identity.folders,
200
- globalHeaderCount: headerIds.size,
201
- kind: identity.kind,
202
- label: identity.label,
203
- mtimeMs: dbStat.mtimeMs,
204
- threadComposerIds,
205
- uri: identity.uri,
206
- workspaceJsonPath
207
- };
208
- };
209
- var getCursorWorkspaceGroupKey = (bucket) => {
210
- if (bucket.kind === "folder" && bucket.folders[0]) return `folder:${bucket.folders[0]}`;
211
- if (bucket.kind === "workspace") return `workspace:${normalizeCursorPath(bucket.uri)}`;
212
- return `unknown:${bucket.bucketId}`;
213
- };
214
- var groupCursorBuckets = (buckets) => {
215
- const grouped = /* @__PURE__ */ new Map();
216
- for (const bucket of buckets) {
217
- const key = getCursorWorkspaceGroupKey(bucket);
218
- const list = grouped.get(key) ?? [];
219
- list.push(bucket);
220
- grouped.set(key, list);
221
- }
222
- const groups = [];
223
- for (const [key, list] of grouped.entries()) {
224
- const ranked = [...list].sort((a, b) => b.mtimeMs - a.mtimeMs || b.dbSizeBytes - a.dbSizeBytes);
225
- const primary = ranked[0];
226
- const newest = ranked[0];
227
- const threadCount = new Set(ranked.flatMap((bucket) => bucket.threadComposerIds)).size;
228
- const olderWithData = ranked.slice(1).some((bucket) => bucket.composerCount > 0 || bucket.globalHeaderCount > 0);
229
- groups.push({
230
- buckets: ranked,
231
- folders: primary.folders,
232
- key,
233
- kind: primary.kind,
234
- label: primary.label,
235
- lastActiveMs: Math.max(...ranked.map((bucket) => bucket.mtimeMs)),
236
- needsRecovery: ranked.length > 1 && olderWithData && newest.composerCount === 0,
237
- threadCount,
238
- uri: primary.uri
239
- });
240
- }
241
- return groups.sort((a, b) => b.lastActiveMs - a.lastActiveMs);
242
- };
243
- var listCursorWorkspaceGroups = async (userDir = resolveCursorUserDir()) => {
244
- return (await discoverCursorWorkspaces(userDir)).groups;
245
- };
246
- var countBubbles = (db, composerId) => {
247
- const row = db.query("SELECT COUNT(*) AS count, COALESCE(SUM(length(value)), 0) AS bytes FROM cursorDiskKV WHERE key LIKE ?").get(`bubbleId:${composerId}:%`);
248
- return {
249
- bytes: row.bytes,
250
- count: row.count
251
- };
252
- };
253
- var findCursorTranscriptDirs = async (composerId, userDir = resolveCursorUserDir()) => {
254
- const projectsDir = getCursorProjectsDir(userDir);
255
- if (!await pathExists(projectsDir)) return [];
256
- const matches = [];
257
- let projectDirs = [];
258
- try {
259
- projectDirs = await readdir(projectsDir);
260
- } catch {
261
- return [];
262
- }
263
- for (const projectDir of projectDirs) {
264
- const transcriptDir = path.join(projectsDir, projectDir, "agent-transcripts", composerId);
265
- if (await pathExists(transcriptDir)) matches.push(transcriptDir);
266
- }
267
- return matches;
268
- };
269
- var listCursorThreadsForGroup = async (group, userDir = resolveCursorUserDir(), options = {}) => {
270
- const threads = (await discoverCursorWorkspaces(userDir)).threadsByKey.get(group.key) ?? [];
271
- if (options.includeTranscriptDirs === false) return threads;
272
- return Promise.all(threads.map(async (thread) => ({
273
- ...thread,
274
- transcriptDirs: await findCursorTranscriptDirs(thread.composerId, userDir)
275
- })));
276
- };
277
- var DISCOVERY_TTL_MS = 6e4;
278
- var UNKNOWN_GROUP_KEY = "unknown";
279
- var discoveryCache = null;
280
- var invalidateCursorDiscoveryCache = () => {
281
- discoveryCache = null;
282
- };
283
- var DEV_CONTAINER_DIRS = [
284
- "workspace",
285
- "projects",
286
- "dev",
287
- "code",
288
- "repos",
289
- "src",
290
- "Documents",
291
- "Downloads",
292
- "Desktop"
293
- ];
294
- var REVERSE_WORKSPACE_ROOT_RE = /^\/Users\/[^/]+\/workspace\/reverse\/[^/]+/u;
295
- var CONTAINER_ROOT_RE = new RegExp(`^(/Users/[^/]+/(?:${DEV_CONTAINER_DIRS.join("|")})/[^/]+)`);
296
- var ABS_PATH_RE = /\/Users\/[^"'\s:,)\]]+/g;
297
- var isNoisePath = (value) => /\/Library(?:\/|$)|\/\.cursor(?:\/|$)|\/node_modules\/|\/\.git\/|^\/tmp|^\/var|^\/private|\/\.Trash\//u.test(value) || /^\/Users\/[^/]+\/(?:Downloads|Desktop)$/u.test(value);
298
- var stripLikelyFileName = (value) => {
299
- return path.basename(value).includes(".") ? path.dirname(value) : value;
300
- };
301
- var containerRootFromPath = (value) => {
302
- const candidate = stripLikelyFileName(normalizeCursorPath(value));
303
- const reverseMatch = candidate.match(REVERSE_WORKSPACE_ROOT_RE);
304
- if (reverseMatch) return reverseMatch[0] ?? null;
305
- const match = candidate.match(CONTAINER_ROOT_RE);
306
- if (match) return match[1] ?? null;
307
- const parts = candidate.split("/");
308
- if (parts.length >= 4 && parts[1] === "Users") return `/${parts.slice(1, 4).join("/")}`;
309
- return null;
310
- };
311
- var inferFolderFromPaths = (paths) => {
312
- const counts = /* @__PURE__ */ new Map();
313
- for (const value of paths) {
314
- if (isNoisePath(value)) continue;
315
- const root = containerRootFromPath(value);
316
- if (root) counts.set(root, (counts.get(root) ?? 0) + 1);
317
- }
318
- let best = null;
319
- let bestCount = 0;
320
- for (const [root, count] of counts) if (count > bestCount) {
321
- best = root;
322
- bestCount = count;
323
- }
324
- return best;
325
- };
326
- var inferFolderFromBlob = (blob) => {
327
- const matches = blob.match(ABS_PATH_RE);
328
- return matches ? inferFolderFromPaths(matches) : null;
329
- };
330
- var readCursorFileHistoryProjectActivity = async (userDir) => {
331
- const historyDir = path.join(userDir, "History");
332
- let entries = [];
333
- try {
334
- entries = await readdir(historyDir, { withFileTypes: true });
335
- } catch {
336
- return /* @__PURE__ */ new Map();
337
- }
338
- const activity = /* @__PURE__ */ new Map();
339
- for (const entry of entries) {
340
- if (!entry.isDirectory()) continue;
341
- const entriesPath = path.join(historyDir, entry.name, "entries.json");
342
- let data;
343
- try {
344
- data = await Bun.file(entriesPath).json();
345
- } catch {
346
- continue;
347
- }
348
- const folder = containerRootFromPath(typeof data.resource === "string" ? data.resource : "");
349
- if (!folder || isNoisePath(folder)) continue;
350
- const lastActiveMs = Math.max(0, ...(data.entries ?? []).map((item) => item.timestamp ?? 0));
351
- activity.set(folder, Math.max(activity.get(folder) ?? 0, lastActiveMs));
352
- }
353
- return activity;
354
- };
355
- var inferFolderFromBubbles = (db, composerId) => {
356
- const rows = db.query("SELECT value FROM cursorDiskKV WHERE key LIKE ? LIMIT 80").all(`bubbleId:${composerId}:%`);
357
- const paths = [];
358
- for (const { value } of rows) {
359
- let bubble;
360
- try {
361
- bubble = JSON.parse(value);
362
- } catch {
363
- continue;
364
- }
365
- const tool = asObject(bubble.toolFormerData ?? null);
366
- if (!tool) continue;
367
- const matches = `${asString(tool.rawArgs ?? null) ?? ""} ${asString(tool.params ?? null) ?? ""}`.match(ABS_PATH_RE);
368
- if (matches) paths.push(...matches);
369
- if (paths.length > 200) break;
370
- }
371
- return inferFolderFromPaths(paths);
372
- };
373
- var readAllHeads = (db) => {
374
- const rows = db.query(`SELECT substr(key, 14) AS id, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'`).all();
375
- return new Map(rows.map((row) => [row.id, parseGlobalHead(row.value)]));
376
- };
377
- var parseGlobalHead = (value) => {
378
- let parsed = {};
379
- try {
380
- parsed = JSON.parse(value);
381
- } catch {
382
- return {
383
- createdAtMs: null,
384
- lastUpdatedAtMs: null,
385
- mode: null,
386
- name: null,
387
- pathHint: inferFolderFromBlob(value)
388
- };
389
- }
390
- return {
391
- createdAtMs: asNumber(parsed.createdAt ?? null),
392
- lastUpdatedAtMs: asNumber(parsed.lastUpdatedAt ?? null),
393
- mode: asString(parsed.unifiedMode ?? null),
394
- name: asString(parsed.name ?? null),
395
- pathHint: inferFolderFromBlob(value)
396
- };
397
- };
398
- var readBubbleStats = (db) => {
399
- const rows = db.query(`SELECT substr(key, 10, instr(substr(key, 10), ':') - 1) AS id,
400
- COUNT(*) AS count,
401
- COALESCE(SUM(length(value)), 0) AS bytes
402
- FROM cursorDiskKV WHERE key GLOB 'bubbleId:*:*' GROUP BY id`).all();
403
- return new Map(rows.map((row) => [row.id, {
404
- bytes: row.bytes,
405
- count: row.count
406
- }]));
407
- };
408
- var readHeaderInfo = (globalDbPath) => {
409
- const info = /* @__PURE__ */ new Map();
410
- for (const header of loadGlobalComposerHeaders(globalDbPath)) {
411
- if (!header.composerId) continue;
412
- const identifier = header.workspaceIdentifier;
413
- const uriPath = identifier?.uri?.path ?? identifier?.uri?.fsPath ?? null;
414
- info.set(header.composerId, {
415
- bucketId: identifier?.id ?? null,
416
- name: typeof header.name === "string" ? header.name : null,
417
- uriPath: uriPath ? normalizeCursorPath(uriPath) : null
418
- });
419
- }
420
- return info;
421
- };
422
- var collectBucketComposerIds = (buckets) => {
423
- const map = /* @__PURE__ */ new Map();
424
- for (const bucket of buckets) for (const composerId of readBucketComposerIds(bucket.dbPath)) if (!map.has(composerId)) map.set(composerId, bucket.bucketId);
425
- return map;
426
- };
427
- var findLinkedBucketId = (composerId, headerInfo, bucketIdToGroupKey, bucketComposerIds) => {
428
- if (headerInfo?.bucketId && bucketIdToGroupKey.has(headerInfo.bucketId)) return headerInfo.bucketId;
429
- return bucketComposerIds.get(composerId) ?? null;
430
- };
431
- var resolveThreadFolderHint = (composerId, head, headerInfo, stat, linkedBucketId, bucketIdToGroupKey, bucketIdToFolder, db) => {
432
- if (linkedBucketId && bucketIdToGroupKey.has(linkedBucketId)) return {
433
- folder: bucketIdToFolder.get(linkedBucketId) ?? null,
434
- groupKey: bucketIdToGroupKey.get(linkedBucketId)
435
- };
436
- if (headerInfo?.uriPath) return {
437
- folder: headerInfo.uriPath,
438
- groupKey: `folder:${headerInfo.uriPath}`
439
- };
440
- if (head?.pathHint) return {
441
- folder: head.pathHint,
442
- groupKey: `folder:${head.pathHint}`
443
- };
444
- if (stat.count > 0) {
445
- const folder = inferFolderFromBubbles(db, composerId);
446
- return {
447
- folder,
448
- groupKey: folder ? `folder:${folder}` : UNKNOWN_GROUP_KEY
449
- };
450
- }
451
- return {
452
- folder: null,
453
- groupKey: UNKNOWN_GROUP_KEY
454
- };
455
- };
456
- var resolveThreadFolder = (composerId, head, headerInfo, stat, bucketIdToGroupKey, bucketIdToFolder, bucketComposerIds, db) => {
457
- const linkedBucketId = findLinkedBucketId(composerId, headerInfo, bucketIdToGroupKey, bucketComposerIds);
458
- const { folder, groupKey } = resolveThreadFolderHint(composerId, head, headerInfo, stat, linkedBucketId, bucketIdToGroupKey, bucketIdToFolder, db);
459
- return {
460
- bucketId: linkedBucketId,
461
- composerId,
462
- createdAtMs: head?.createdAtMs ?? null,
463
- folder,
464
- groupKey,
465
- groupLabel: folder ? path.basename(folder) : "Unknown project",
466
- lastUpdatedAtMs: head?.lastUpdatedAtMs ?? null,
467
- mode: head?.mode ?? null,
468
- name: head?.name || headerInfo?.name || "(untitled)",
469
- stat
470
- };
471
- };
472
- var toThreadSummary = (resolved) => ({
473
- bubbleBytes: resolved.stat.bytes,
474
- bubbleCount: resolved.stat.count,
475
- bucketId: resolved.bucketId,
476
- composerId: resolved.composerId,
477
- createdAtMs: resolved.createdAtMs,
478
- lastUpdatedAtMs: resolved.lastUpdatedAtMs,
479
- mode: resolved.mode,
480
- name: resolved.name,
481
- transcriptDirs: [],
482
- workspaceKey: resolved.groupKey,
483
- workspaceLabel: resolved.groupLabel
484
- });
485
- var assembleDiscovery = (resolved, bucketGroups, fileHistoryActivity) => {
486
- const threadsByKey = /* @__PURE__ */ new Map();
487
- const lastActiveByKey = /* @__PURE__ */ new Map();
488
- for (const thread of resolved) {
489
- if (thread.groupKey === UNKNOWN_GROUP_KEY && thread.stat.count === 0) continue;
490
- const list = threadsByKey.get(thread.groupKey) ?? [];
491
- list.push(toThreadSummary(thread));
492
- threadsByKey.set(thread.groupKey, list);
493
- lastActiveByKey.set(thread.groupKey, Math.max(lastActiveByKey.get(thread.groupKey) ?? 0, thread.lastUpdatedAtMs ?? 0));
494
- }
495
- for (const [folder, lastActiveMs] of fileHistoryActivity) {
496
- const key = `folder:${folder}`;
497
- lastActiveByKey.set(key, Math.max(lastActiveByKey.get(key) ?? 0, lastActiveMs));
498
- }
499
- for (const list of threadsByKey.values()) list.sort((a, b) => (b.lastUpdatedAtMs ?? 0) - (a.lastUpdatedAtMs ?? 0));
500
- return {
501
- groups: buildDiscoveryGroups(threadsByKey, bucketGroups, lastActiveByKey),
502
- threadsByKey
503
- };
504
- };
505
- var mergeBucketGroup = (bucketGroup, threadsByKey, lastActiveByKey) => {
506
- const threads = threadsByKey.get(bucketGroup.key) ?? [];
507
- return {
508
- ...bucketGroup,
509
- lastActiveMs: Math.max(bucketGroup.lastActiveMs, lastActiveByKey.get(bucketGroup.key) ?? 0),
510
- threadCount: threads.length || bucketGroup.threadCount
511
- };
512
- };
513
- var buildBucketlessGroup = (key, threadCount, lastActiveMs) => {
514
- const isUnknown = key === UNKNOWN_GROUP_KEY;
515
- const folder = isUnknown ? "" : key.slice(7);
516
- return {
517
- buckets: [],
518
- folders: folder ? [folder] : [],
519
- key,
520
- kind: isUnknown ? "unknown" : "folder",
521
- label: isUnknown ? "Unknown project" : path.basename(folder),
522
- lastActiveMs,
523
- needsRecovery: false,
524
- threadCount,
525
- uri: folder ? `file://${folder}` : ""
526
- };
527
- };
528
- var buildDiscoveryGroups = (threadsByKey, bucketGroups, lastActiveByKey) => {
529
- const seen = new Set(bucketGroups.map((group) => group.key));
530
- const groups = bucketGroups.map((group) => mergeBucketGroup(group, threadsByKey, lastActiveByKey));
531
- const keys = new Set([...threadsByKey.keys(), ...lastActiveByKey.keys()]);
532
- for (const key of keys) {
533
- const threads = threadsByKey.get(key) ?? [];
534
- if (!seen.has(key) && (threads.length > 0 || key !== UNKNOWN_GROUP_KEY)) {
535
- groups.push(buildBucketlessGroup(key, threads.length, lastActiveByKey.get(key) ?? 0));
536
- seen.add(key);
537
- }
538
- }
539
- return groups.sort((a, b) => b.lastActiveMs - a.lastActiveMs);
540
- };
541
- var buildDiscovery = async (userDir) => {
542
- const buckets = await loadCursorBuckets(userDir);
543
- const bucketGroups = groupCursorBuckets(buckets);
544
- const fileHistoryActivity = await readCursorFileHistoryProjectActivity(userDir);
545
- const globalDbPath = getCursorGlobalDbPath(userDir);
546
- if (!await pathExists(globalDbPath)) return assembleDiscovery([], bucketGroups, fileHistoryActivity);
547
- const bucketIdToGroupKey = /* @__PURE__ */ new Map();
548
- const bucketIdToFolder = /* @__PURE__ */ new Map();
549
- for (const group of bucketGroups) for (const bucket of group.buckets) {
550
- bucketIdToGroupKey.set(bucket.bucketId, group.key);
551
- bucketIdToFolder.set(bucket.bucketId, group.folders[0] ?? null);
552
- }
553
- const headerInfo = readHeaderInfo(globalDbPath);
554
- const bucketComposerIds = collectBucketComposerIds(buckets);
555
- const db = openCursorReadonlyDb(globalDbPath);
556
- try {
557
- const heads = readAllHeads(db);
558
- const stats = readBubbleStats(db);
559
- const universe = new Set([
560
- ...heads.keys(),
561
- ...headerInfo.keys(),
562
- ...bucketComposerIds.keys()
563
- ]);
564
- const resolved = [];
565
- for (const composerId of universe) resolved.push(resolveThreadFolder(composerId, heads.get(composerId), headerInfo.get(composerId), stats.get(composerId) ?? {
566
- bytes: 0,
567
- count: 0
568
- }, bucketIdToGroupKey, bucketIdToFolder, bucketComposerIds, db));
569
- return assembleDiscovery(resolved, bucketGroups, fileHistoryActivity);
570
- } finally {
571
- db.close();
572
- }
573
- };
574
- var discoverCursorWorkspaces = async (userDir) => {
575
- const now = Date.now();
576
- if (discoveryCache && discoveryCache.userDir === userDir && now - discoveryCache.at < DISCOVERY_TTL_MS) return discoveryCache.value;
577
- const value = await buildDiscovery(userDir);
578
- discoveryCache = {
579
- at: now,
580
- userDir,
581
- value
582
- };
583
- return value;
584
- };
585
- var readCursorThreadHead = (globalDbPath, composerId) => {
586
- const db = openCursorReadonlyDb(globalDbPath);
587
- try {
588
- const head = readKvValue(db, `composerData:${composerId}`);
589
- if (!head) return null;
590
- const headerList = Array.isArray(head.fullConversationHeadersOnly) ? head.fullConversationHeadersOnly : [];
591
- const orderedBubbleIds = headerList.map((item) => asString(asObject(item)?.bubbleId ?? null)).filter((value) => Boolean(value));
592
- return {
593
- composerId,
594
- createdAtMs: asNumber(head.createdAt ?? null),
595
- lastUpdatedAtMs: asNumber(head.lastUpdatedAt ?? null),
596
- mode: asString(head.unifiedMode ?? null),
597
- name: asString(head.name ?? null),
598
- orderedBubbleIds,
599
- totalBubbleHeaders: headerList.length
600
- };
601
- } finally {
602
- db.close();
603
- }
604
- };
605
- var toBubbleKind = (rawType) => {
606
- if (rawType === 1) return "user";
607
- if (rawType === 2) return "assistant";
608
- return "unknown";
609
- };
610
- var parseToolCall = (raw) => {
611
- const data = asObject(raw);
612
- if (!data) return null;
613
- const name = asString(data.name ?? null);
614
- if (!name) return null;
615
- return {
616
- argumentsText: asString(data.rawArgs ?? null) ?? asString(data.params ?? null),
617
- callId: asString(data.toolCallId ?? null),
618
- name,
619
- resultText: asString(data.result ?? null),
620
- status: asString(data.status ?? null)
621
- };
622
- };
623
- var parseCursorBubble = (bubbleId, raw) => {
624
- const thinking = asObject(raw.thinking ?? null);
625
- return {
626
- bubbleId,
627
- createdAtMs: asNumber(raw.createdAt ?? null),
628
- kind: toBubbleKind(raw.type ?? null),
629
- text: asString(raw.text ?? null) ?? "",
630
- thinking: thinking ? asString(thinking.text ?? null) : null,
631
- toolCall: parseToolCall(raw.toolFormerData ?? null)
632
- };
633
- };
634
- var readBubble = (db, composerId, bubbleId) => {
635
- const raw = readKvValue(db, `bubbleId:${composerId}:${bubbleId}`);
636
- if (!raw) return null;
637
- return parseCursorBubble(bubbleId, raw);
638
- };
639
- var isRenderableBubble = (bubble) => {
640
- return Boolean(bubble.text.trim() || bubble.thinking?.trim() || bubble.toolCall);
641
- };
642
- var normalizeBubbleText = (value) => {
643
- return (value ?? "").replace(/\s+/gu, " ").trim();
644
- };
645
- var hashText = (value) => createHash("sha1").update(value).digest("hex").slice(0, 12);
646
- var stableStringifyJson = (value) => {
647
- if (Array.isArray(value)) return `[${value.map(stableStringifyJson).join(",")}]`;
648
- if (value && typeof value === "object") return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringifyJson(value[key])}`).join(",")}}`;
649
- return JSON.stringify(value);
650
- };
651
- var normalizeToolArgumentsText = (value) => {
652
- if (!value?.trim()) return "";
653
- try {
654
- return stableStringifyJson(JSON.parse(value));
655
- } catch {
656
- return normalizeBubbleText(value);
657
- }
658
- };
659
- var hasRenderableTextSuperset = (left, right) => {
660
- const normalizedLeft = normalizeBubbleText(left);
661
- const normalizedRight = normalizeBubbleText(right);
662
- if (!normalizedLeft && !normalizedRight) return true;
663
- return normalizedLeft === normalizedRight || normalizedLeft.startsWith(normalizedRight) || normalizedRight.startsWith(normalizedLeft);
664
- };
665
- var haveSameToolIdentity = (left, right) => {
666
- if (!left && !right) return true;
667
- if (!left || !right) return false;
668
- return left.name === right.name && normalizeToolArgumentsText(left.argumentsText) === normalizeToolArgumentsText(right.argumentsText);
669
- };
670
- var areEquivalentBubbles = (left, right) => {
671
- return left.kind === right.kind && hasRenderableTextSuperset(left.text, right.text) && Boolean(normalizeBubbleText(left.thinking)) === Boolean(normalizeBubbleText(right.thinking)) && haveSameToolIdentity(left.toolCall, right.toolCall);
672
- };
673
- var findAgentTailStartIndex = (existingBubbles, agentBubbles) => {
674
- const maxOverlap = Math.min(existingBubbles.length, agentBubbles.length);
675
- for (let overlapLength = maxOverlap; overlapLength > 0; overlapLength -= 1) {
676
- const existingStart = existingBubbles.length - overlapLength;
677
- if (agentBubbles.slice(0, overlapLength).every((bubble, index) => areEquivalentBubbles(existingBubbles[existingStart + index], bubble))) return overlapLength;
678
- }
679
- return 0;
680
- };
681
- var hasEquivalentBubble = (bubbles, candidate) => {
682
- return bubbles.some((bubble) => areEquivalentBubbles(bubble, candidate));
683
- };
684
- var getAgentTranscriptContentParts = (entry) => {
685
- const content = asObject(entry.message ?? null)?.content ?? entry.content ?? null;
686
- if (Array.isArray(content)) return content.map((part) => asObject(part)).filter((part) => Boolean(part));
687
- if (typeof content === "string") return [{
688
- text: content,
689
- type: "text"
690
- }];
691
- return [];
692
- };
693
- var parseAgentTranscriptToolCall = (parts) => {
694
- const toolUse = parts.find((part) => asString(part.type ?? null) === "tool_use");
695
- if (!toolUse) return null;
696
- const name = asString(toolUse.name ?? null);
697
- if (!name) return null;
698
- return {
699
- argumentsText: toolUse.input === void 0 ? null : JSON.stringify(toolUse.input),
700
- callId: asString(toolUse.id ?? null),
701
- name,
702
- resultText: null,
703
- status: null
704
- };
705
- };
706
- var parseAgentTranscriptBubble = (filePath, lineNumber, raw) => {
707
- const message = asObject(raw.message ?? null);
708
- const role = asString(raw.role ?? message?.role ?? null);
709
- const kind = role === "user" || role === "assistant" ? role : "unknown";
710
- const parts = getAgentTranscriptContentParts(raw);
711
- const text = parts.filter((part) => asString(part.type ?? null) === "text").map((part) => asString(part.text ?? null)).filter((value) => Boolean(value?.trim())).join("\n\n");
712
- const toolCall = parseAgentTranscriptToolCall(parts);
713
- const bubble = {
714
- bubbleId: `agent-transcript:${hashText(path.resolve(filePath))}:${path.basename(filePath)}:${lineNumber}`,
715
- createdAtMs: null,
716
- kind,
717
- text,
718
- thinking: null,
719
- toolCall
720
- };
721
- return isRenderableBubble(bubble) ? bubble : null;
722
- };
723
- var readCursorAgentTranscriptFile = async (filePath) => {
724
- let text = "";
725
- try {
726
- text = await Bun.file(filePath).text();
727
- } catch (error) {
728
- warnCursorDataIssue("agent_transcript_unreadable", {
729
- error: error instanceof Error ? error.message : String(error),
730
- filePath
731
- });
732
- return [];
733
- }
734
- const bubbles = [];
735
- for (const [index, line] of text.split(/\n/u).entries()) {
736
- if (!line.trim()) continue;
737
- let raw;
738
- try {
739
- raw = JSON.parse(line);
740
- } catch (error) {
741
- warnCursorDataIssue("invalid_agent_transcript_jsonl", {
742
- error: error instanceof Error ? error.message : String(error),
743
- filePath,
744
- lineNumber: index + 1
745
- });
746
- continue;
747
- }
748
- const entry = asObject(raw);
749
- if (!entry) continue;
750
- const bubble = parseAgentTranscriptBubble(filePath, index + 1, entry);
751
- if (bubble) bubbles.push(bubble);
752
- }
753
- return bubbles;
754
- };
755
- var listCursorAgentTranscriptFiles = async (transcriptDir, composerId) => {
756
- const preferred = path.join(transcriptDir, `${composerId}.jsonl`);
757
- const files = /* @__PURE__ */ new Set();
758
- if (await pathExists(preferred)) files.add(preferred);
759
- let entries = [];
760
- try {
761
- entries = await readdir(transcriptDir);
762
- } catch {
763
- return [...files];
764
- }
765
- for (const entry of entries) if (entry.endsWith(".jsonl")) files.add(path.join(transcriptDir, entry));
766
- return [...files].sort();
767
- };
768
- var readCursorAgentTranscriptBubbles = async (composerId, userDir) => {
769
- const transcriptDirs = await findCursorTranscriptDirs(composerId, userDir);
770
- const bubbles = [];
771
- for (const transcriptDir of transcriptDirs.sort()) {
772
- const files = await listCursorAgentTranscriptFiles(transcriptDir, composerId);
773
- for (const file of files) bubbles.push(...await readCursorAgentTranscriptFile(file));
774
- }
775
- return bubbles;
776
- };
777
- var mergeAgentTranscriptTail = (transcript, agentBubbles) => {
778
- const tailStartIndex = findAgentTailStartIndex(transcript.bubbles, agentBubbles);
779
- const seen = [...transcript.bubbles];
780
- const appended = [];
781
- const candidates = agentBubbles.slice(tailStartIndex);
782
- for (const bubble of candidates) {
783
- if (hasEquivalentBubble(seen, bubble)) continue;
784
- seen.push(bubble);
785
- appended.push(bubble);
786
- }
787
- if (appended.length === 0) return transcript;
788
- return {
789
- ...transcript,
790
- bubbles: [...transcript.bubbles, ...appended],
791
- renderableBubbleCount: transcript.renderableBubbleCount + appended.length
792
- };
793
- };
794
- var inferCursorUserDirFromGlobalDbPath = (globalDbPath) => {
795
- const globalStorageDir = path.dirname(globalDbPath);
796
- return path.basename(globalStorageDir) === "globalStorage" ? path.dirname(globalStorageDir) : resolveCursorUserDir();
797
- };
798
- var readCursorThreadTranscript = (globalDbPath, composerId) => {
799
- const head = readCursorThreadHead(globalDbPath, composerId);
800
- if (!head) return null;
801
- const db = openCursorReadonlyDb(globalDbPath);
802
- try {
803
- const orderedIds = head.orderedBubbleIds.length > 0 ? head.orderedBubbleIds : readAllBubbleIds(db, composerId);
804
- const bubbles = [];
805
- for (const bubbleId of orderedIds) {
806
- const bubble = readBubble(db, composerId, bubbleId);
807
- if (bubble && isRenderableBubble(bubble)) bubbles.push(bubble);
808
- }
809
- const totalBubbleRows = countBubbles(db, composerId).count;
810
- return {
811
- bubbles,
812
- head,
813
- omittedBubbleCount: Math.max(totalBubbleRows - orderedIds.length, 0),
814
- renderableBubbleCount: bubbles.length
815
- };
816
- } finally {
817
- db.close();
818
- }
819
- };
820
- var readCursorThreadTranscriptWithAgentFiles = async (globalDbPath, composerId, userDir = inferCursorUserDirFromGlobalDbPath(globalDbPath)) => {
821
- const transcript = readCursorThreadTranscript(globalDbPath, composerId);
822
- if (!transcript) return null;
823
- return mergeAgentTranscriptTail(transcript, await readCursorAgentTranscriptBubbles(composerId, userDir));
824
- };
825
- var readAllBubbleIds = (db, composerId) => {
826
- const prefix = `bubbleId:${composerId}:`;
827
- return db.query("SELECT key FROM cursorDiskKV WHERE key LIKE ? ORDER BY key ASC").all(`${prefix}%`).map((row) => row.key.slice(prefix.length));
828
- };
829
- //#endregion
830
- export { findCursorTranscriptDirs, invalidateCursorDiscoveryCache, listCursorThreadsForGroup, listCursorWorkspaceGroups, loadGlobalComposerHeaders, openCursorReadonlyDb, readCursorThreadTranscriptWithAgentFiles };