spiracha 1.5.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (401) hide show
  1. package/AGENTS.md +114 -205
  2. package/README.md +94 -269
  3. package/apps/ui/AGENTS.md +17 -7
  4. package/apps/ui/README.md +52 -8
  5. package/apps/ui/components.json +21 -0
  6. package/apps/ui/package.json +65 -0
  7. package/apps/ui/src/components/antigravity-conversations-table.tsx +245 -0
  8. package/apps/ui/src/components/antigravity-keychain-panel.tsx +76 -0
  9. package/apps/ui/src/components/antigravity-workspaces-table.tsx +63 -0
  10. package/apps/ui/src/components/app-shell.tsx +125 -0
  11. package/apps/ui/src/components/breadcrumbs.tsx +71 -0
  12. package/apps/ui/src/components/claude-code-sessions-table.tsx +150 -0
  13. package/apps/ui/src/components/claude-code-workspaces-table.tsx +57 -0
  14. package/apps/ui/src/components/cursor-threads-table.tsx +152 -0
  15. package/apps/ui/src/components/cursor-workspaces-table.tsx +140 -0
  16. package/apps/ui/src/components/data-table.tsx +243 -0
  17. package/apps/ui/src/components/delete-confirm-dialog.tsx +88 -0
  18. package/apps/ui/src/components/export-dialog.tsx +174 -0
  19. package/apps/ui/src/components/grok-sessions-table.tsx +146 -0
  20. package/apps/ui/src/components/grok-workspaces-table.tsx +53 -0
  21. package/apps/ui/src/components/json-panel.tsx +17 -0
  22. package/apps/ui/src/components/kiro-sessions-table.tsx +148 -0
  23. package/apps/ui/src/components/kiro-workspaces-table.tsx +53 -0
  24. package/apps/ui/src/components/list-search-input.tsx +18 -0
  25. package/apps/ui/src/components/loading-panel.tsx +23 -0
  26. package/apps/ui/src/components/metadata-section.tsx +31 -0
  27. package/apps/ui/src/components/metric-card.tsx +19 -0
  28. package/apps/ui/src/components/opencode-sessions-table.tsx +164 -0
  29. package/apps/ui/src/components/opencode-workspaces-table.tsx +57 -0
  30. package/apps/ui/src/components/page-header.tsx +39 -0
  31. package/apps/ui/src/components/projects-loading-state.tsx +74 -0
  32. package/apps/ui/src/components/projects-table.tsx +108 -0
  33. package/apps/ui/src/components/qoder-sessions-table.tsx +133 -0
  34. package/apps/ui/src/components/qoder-workspaces-table.tsx +57 -0
  35. package/apps/ui/src/components/recent-threads-list.tsx +52 -0
  36. package/apps/ui/src/components/reload-error-panel.tsx +20 -0
  37. package/apps/ui/src/components/selection-actions-toolbar.tsx +80 -0
  38. package/apps/ui/src/components/text-document-panel.tsx +19 -0
  39. package/apps/ui/src/components/theme-toggle.tsx +48 -0
  40. package/apps/ui/src/components/threads-table.tsx +165 -0
  41. package/apps/ui/src/components/transcript-view.tsx +648 -0
  42. package/apps/ui/src/components/ui/alert-dialog.tsx +160 -0
  43. package/apps/ui/src/components/ui/badge.tsx +45 -0
  44. package/apps/ui/src/components/ui/button.tsx +62 -0
  45. package/apps/ui/src/components/ui/checkbox.tsx +29 -0
  46. package/apps/ui/src/components/ui/dialog.tsx +137 -0
  47. package/apps/ui/src/components/ui/dropdown-menu.tsx +217 -0
  48. package/apps/ui/src/components/ui/input.tsx +21 -0
  49. package/apps/ui/src/components/ui/scroll-area.tsx +46 -0
  50. package/apps/ui/src/components/ui/select.tsx +163 -0
  51. package/apps/ui/src/components/ui/separator.tsx +28 -0
  52. package/apps/ui/src/components/ui/sheet.tsx +107 -0
  53. package/apps/ui/src/components/ui/skeleton.tsx +7 -0
  54. package/apps/ui/src/components/ui/table.tsx +76 -0
  55. package/apps/ui/src/components/ui/tabs.tsx +71 -0
  56. package/apps/ui/src/components/ui/tooltip.tsx +44 -0
  57. package/apps/ui/src/integrations/tanstack-query/devtools.tsx +6 -0
  58. package/apps/ui/src/integrations/tanstack-query/root-provider.tsx +10 -0
  59. package/apps/ui/src/lib/antigravity-conversation-state.ts +41 -0
  60. package/apps/ui/src/lib/antigravity-queries.ts +33 -0
  61. package/apps/ui/src/lib/antigravity-server.ts +273 -0
  62. package/apps/ui/src/lib/antigravity-transcript-events.ts +343 -0
  63. package/apps/ui/src/lib/claude-code-queries.ts +34 -0
  64. package/apps/ui/src/lib/claude-code-server.ts +243 -0
  65. package/apps/ui/src/lib/claude-code-transcript-events.ts +161 -0
  66. package/apps/ui/src/lib/codex-queries.ts +82 -0
  67. package/apps/ui/src/lib/codex-server.ts +291 -0
  68. package/apps/ui/src/lib/cursor-queries.ts +37 -0
  69. package/apps/ui/src/lib/cursor-server.ts +315 -0
  70. package/apps/ui/src/lib/cursor-transcript-events.ts +229 -0
  71. package/apps/ui/src/lib/download.ts +166 -0
  72. package/apps/ui/src/lib/formatters.ts +147 -0
  73. package/apps/ui/src/lib/grok-queries.ts +22 -0
  74. package/apps/ui/src/lib/grok-server.ts +169 -0
  75. package/apps/ui/src/lib/grok-transcript-events.ts +149 -0
  76. package/apps/ui/src/lib/kiro-queries.ts +22 -0
  77. package/apps/ui/src/lib/kiro-server.ts +151 -0
  78. package/apps/ui/src/lib/kiro-transcript-events.ts +113 -0
  79. package/apps/ui/src/lib/opencode-queries.ts +37 -0
  80. package/apps/ui/src/lib/opencode-server.ts +151 -0
  81. package/apps/ui/src/lib/opencode-transcript-events.ts +221 -0
  82. package/apps/ui/src/lib/package-metadata.ts +16 -0
  83. package/apps/ui/src/lib/path-utils.ts +13 -0
  84. package/apps/ui/src/lib/qoder-queries.ts +22 -0
  85. package/apps/ui/src/lib/qoder-server.ts +135 -0
  86. package/apps/ui/src/lib/qoder-transcript-events.ts +139 -0
  87. package/apps/ui/src/lib/route-search.ts +182 -0
  88. package/apps/ui/src/lib/settings-store.tsx +59 -0
  89. package/apps/ui/src/lib/source-session-export-server.ts +139 -0
  90. package/apps/ui/src/lib/text-filter.ts +22 -0
  91. package/apps/ui/src/lib/thread-id.ts +3 -0
  92. package/apps/ui/src/lib/thread-transcript-load.ts +15 -0
  93. package/apps/ui/src/lib/thread-transcript-stats.ts +57 -0
  94. package/apps/ui/src/lib/utils.ts +7 -0
  95. package/apps/ui/src/lib/workspace-delete-navigation.ts +12 -0
  96. package/apps/ui/src/routeTree.gen.ts +837 -0
  97. package/apps/ui/src/router.tsx +20 -0
  98. package/apps/ui/src/routes/$threadId.tsx +22 -0
  99. package/apps/ui/src/routes/__root.tsx +127 -0
  100. package/apps/ui/src/routes/analytics.tsx +143 -0
  101. package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +504 -0
  102. package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +365 -0
  103. package/apps/ui/src/routes/antigravity.index.tsx +51 -0
  104. package/apps/ui/src/routes/api.v1.conversation-query.ts +12 -0
  105. package/apps/ui/src/routes/api.v1.conversations.$source.$id.export.ts +12 -0
  106. package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +16 -0
  107. package/apps/ui/src/routes/api.v1.conversations.delete.ts +12 -0
  108. package/apps/ui/src/routes/api.v1.conversations.export.ts +12 -0
  109. package/apps/ui/src/routes/api.v1.conversations.ts +12 -0
  110. package/apps/ui/src/routes/api.v1.resolve.ts +12 -0
  111. package/apps/ui/src/routes/api.v1.sources.ts +12 -0
  112. package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +468 -0
  113. package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +274 -0
  114. package/apps/ui/src/routes/claude-code.index.tsx +48 -0
  115. package/apps/ui/src/routes/codex.$project.tsx +390 -0
  116. package/apps/ui/src/routes/codex.index.tsx +116 -0
  117. package/apps/ui/src/routes/cursor-threads.$composerId.tsx +435 -0
  118. package/apps/ui/src/routes/cursor.$workspaceKey.tsx +426 -0
  119. package/apps/ui/src/routes/cursor.index.tsx +120 -0
  120. package/apps/ui/src/routes/grok-sessions.$sessionId.tsx +388 -0
  121. package/apps/ui/src/routes/grok.$workspaceKey.tsx +301 -0
  122. package/apps/ui/src/routes/grok.index.tsx +48 -0
  123. package/apps/ui/src/routes/index.tsx +124 -0
  124. package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +396 -0
  125. package/apps/ui/src/routes/kiro.$workspaceKey.tsx +303 -0
  126. package/apps/ui/src/routes/kiro.index.tsx +48 -0
  127. package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +420 -0
  128. package/apps/ui/src/routes/opencode.$workspaceKey.tsx +327 -0
  129. package/apps/ui/src/routes/opencode.index.tsx +61 -0
  130. package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +344 -0
  131. package/apps/ui/src/routes/qoder.$workspaceKey.tsx +186 -0
  132. package/apps/ui/src/routes/qoder.index.tsx +48 -0
  133. package/apps/ui/src/routes/settings.tsx +91 -0
  134. package/apps/ui/src/routes/threads.$threadId.tsx +1103 -0
  135. package/apps/ui/src/styles.css +122 -0
  136. package/apps/ui/tsconfig.json +29 -0
  137. package/apps/ui/vite.config.ts +84 -0
  138. package/bin/spiracha.ts +32 -0
  139. package/package.json +54 -80
  140. package/src/client.ts +423 -0
  141. package/src/lib/antigravity-db.ts +414 -44
  142. package/src/lib/antigravity-exporter-types.ts +4 -0
  143. package/src/lib/antigravity-projects.ts +201 -0
  144. package/src/lib/claude-code-db.ts +498 -32
  145. package/src/lib/claude-code-exporter-types.ts +5 -0
  146. package/src/lib/claude-code-transcript-phase.ts +60 -1
  147. package/src/lib/claude-code-transcript.ts +8 -5
  148. package/src/lib/codex-analytics.ts +1 -1
  149. package/src/lib/codex-browser-db.ts +410 -74
  150. package/src/lib/codex-browser-export.ts +29 -41
  151. package/src/lib/codex-browser-types.ts +1 -1
  152. package/src/lib/codex-thread-cache.ts +41 -13
  153. package/src/lib/codex-thread-parser.ts +86 -35
  154. package/src/lib/{codex-exporter-types.ts → codex-thread-types.ts} +2 -30
  155. package/src/lib/codex-transcript-filter.ts +31 -0
  156. package/src/lib/{codex-exporter-transcript.ts → codex-transcript-renderer.ts} +104 -48
  157. package/src/lib/concurrency.ts +41 -0
  158. package/src/lib/conversation-api.ts +1172 -0
  159. package/src/lib/conversation-data/adapter-helpers.ts +110 -0
  160. package/src/lib/conversation-data/antigravity-adapter.ts +167 -0
  161. package/src/lib/conversation-data/claude-code-adapter.ts +206 -0
  162. package/src/lib/conversation-data/codex-adapter.ts +269 -0
  163. package/src/lib/conversation-data/cursor-adapter.ts +205 -0
  164. package/src/lib/conversation-data/grok-adapter.ts +210 -0
  165. package/src/lib/conversation-data/index.ts +386 -0
  166. package/src/lib/conversation-data/kiro-adapter.ts +174 -0
  167. package/src/lib/conversation-data/message-selector.ts +37 -0
  168. package/src/lib/conversation-data/opencode-adapter.ts +202 -0
  169. package/src/lib/conversation-data/path-match.ts +79 -0
  170. package/src/lib/conversation-data/qoder-adapter.ts +255 -0
  171. package/src/lib/conversation-data/types.ts +159 -0
  172. package/src/lib/conversation-zip-export.ts +57 -0
  173. package/src/lib/cursor-db.ts +100 -25
  174. package/src/lib/cursor-exporter-types.ts +0 -19
  175. package/src/lib/grok-db.ts +1026 -0
  176. package/src/lib/grok-exporter-types.ts +110 -0
  177. package/src/lib/grok-transcript-phase.ts +52 -0
  178. package/src/lib/grok-transcript.ts +154 -0
  179. package/src/lib/kiro-db.ts +52 -1
  180. package/src/lib/model-label.ts +11 -3
  181. package/src/lib/opencode-db.ts +598 -55
  182. package/src/lib/opencode-transcript.ts +8 -5
  183. package/src/lib/qoder-acp-client.ts +268 -0
  184. package/src/lib/qoder-db.ts +1601 -0
  185. package/src/lib/qoder-exporter-types.ts +114 -0
  186. package/src/lib/qoder-transcript-phase.ts +41 -0
  187. package/src/lib/qoder-transcript.ts +112 -0
  188. package/src/lib/shared.ts +12 -0
  189. package/src/lib/transcript-load-limiter.ts +82 -0
  190. package/src/lib/ui-cache.ts +43 -17
  191. package/src/lib/ui-export-archive.ts +60 -0
  192. package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +0 -1
  193. package/apps/ui/dist/client/assets/analytics-DOy1b6Sh.js +0 -1
  194. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-DqySVO2K.js +0 -7
  195. package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-KAcXtNxI.js +0 -1
  196. package/apps/ui/dist/client/assets/antigravity-keychain-panel-B77qJz6f.js +0 -1
  197. package/apps/ui/dist/client/assets/antigravity._workspaceKey-B3NM6gRH.js +0 -1
  198. package/apps/ui/dist/client/assets/antigravity._workspaceKey-ByitGWki.js +0 -1
  199. package/apps/ui/dist/client/assets/antigravity.index-DP9JC2P9.js +0 -1
  200. package/apps/ui/dist/client/assets/antigravity.index-DgW25FEV.js +0 -1
  201. package/apps/ui/dist/client/assets/badge-C3i4OKs8.js +0 -1
  202. package/apps/ui/dist/client/assets/checkbox-CdHitXWQ.js +0 -1
  203. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-8pQ55ci2.js +0 -1
  204. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-DVz5UmtU.js +0 -1
  205. package/apps/ui/dist/client/assets/claude-code._workspaceKey-BBKskSum.js +0 -1
  206. package/apps/ui/dist/client/assets/claude-code._workspaceKey-OkikMUFs.js +0 -1
  207. package/apps/ui/dist/client/assets/claude-code.index-Cwu76dbb.js +0 -1
  208. package/apps/ui/dist/client/assets/claude-code.index-D6eMd08t.js +0 -1
  209. package/apps/ui/dist/client/assets/createServerFn-B-KkwmHU.js +0 -3
  210. package/apps/ui/dist/client/assets/cursor-threads._composerId-CmBFclK8.js +0 -1
  211. package/apps/ui/dist/client/assets/cursor-threads._composerId-hBWlP1D-.js +0 -1
  212. package/apps/ui/dist/client/assets/cursor._workspaceKey-BFPkIRi-.js +0 -1
  213. package/apps/ui/dist/client/assets/cursor._workspaceKey-CaAZjGmm.js +0 -1
  214. package/apps/ui/dist/client/assets/cursor.index-8y4o20kb.js +0 -2
  215. package/apps/ui/dist/client/assets/cursor.index-CrnMwDCi.js +0 -1
  216. package/apps/ui/dist/client/assets/data-table-Br78_dk3.js +0 -4
  217. package/apps/ui/dist/client/assets/delete-confirm-dialog-Bxs07u-j.js +0 -7
  218. package/apps/ui/dist/client/assets/dist-B9pyYCVU.js +0 -1
  219. package/apps/ui/dist/client/assets/dist-BrJhN2A0.js +0 -5
  220. package/apps/ui/dist/client/assets/dist-Cmd3AIfD.js +0 -1
  221. package/apps/ui/dist/client/assets/dist-DvMS2965.js +0 -1
  222. package/apps/ui/dist/client/assets/download-Bf0QJKD3.js +0 -1
  223. package/apps/ui/dist/client/assets/dropdown-menu-D5cvPaZt.js +0 -1
  224. package/apps/ui/dist/client/assets/es2015-ad6040dw.js +0 -41
  225. package/apps/ui/dist/client/assets/export-dialog-Dr8d2MqD.js +0 -1
  226. package/apps/ui/dist/client/assets/formatters-BtqyrX_c.js +0 -1
  227. package/apps/ui/dist/client/assets/index-C-STgIH4.js +0 -166
  228. package/apps/ui/dist/client/assets/jsx-runtime-DGeXAQPT.js +0 -1
  229. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-CKgfJ7GR.js +0 -1
  230. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-zvIJHtQF.js +0 -1
  231. package/apps/ui/dist/client/assets/kiro._workspaceKey-DhVuJuZB.js +0 -1
  232. package/apps/ui/dist/client/assets/kiro._workspaceKey-QArsjkTY.js +0 -1
  233. package/apps/ui/dist/client/assets/kiro.index-C-fr4m7i.js +0 -1
  234. package/apps/ui/dist/client/assets/kiro.index-OYgAdtZd.js +0 -1
  235. package/apps/ui/dist/client/assets/metric-card-Dplm0ZiM.js +0 -1
  236. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-DLjiTst-.js +0 -1
  237. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-biBwrRbt.js +0 -8
  238. package/apps/ui/dist/client/assets/opencode._workspaceKey-C7OIzMOJ.js +0 -1
  239. package/apps/ui/dist/client/assets/opencode._workspaceKey-sBakX0oI.js +0 -1
  240. package/apps/ui/dist/client/assets/opencode.index-Bl_kNs9N.js +0 -1
  241. package/apps/ui/dist/client/assets/opencode.index-CN53bVmb.js +0 -1
  242. package/apps/ui/dist/client/assets/page-header-Cwa3p6Tl.js +0 -1
  243. package/apps/ui/dist/client/assets/preload-helper-B8fFrdxC.js +0 -1
  244. package/apps/ui/dist/client/assets/projects._project-D8WloxQN.js +0 -1
  245. package/apps/ui/dist/client/assets/projects._project-DSDwH4NF.js +0 -1
  246. package/apps/ui/dist/client/assets/projects.index-5xRtuJdX.js +0 -3
  247. package/apps/ui/dist/client/assets/projects.index-DEfhWqa8.js +0 -1
  248. package/apps/ui/dist/client/assets/react-dom-DL96Jor4.js +0 -1
  249. package/apps/ui/dist/client/assets/refresh-ccw-BgKjOiA6.js +0 -1
  250. package/apps/ui/dist/client/assets/reload-error-panel-AHqu0akK.js +0 -1
  251. package/apps/ui/dist/client/assets/routes-DnzF_9CX.js +0 -1
  252. package/apps/ui/dist/client/assets/scroll-text-fM0sMOB3.js +0 -1
  253. package/apps/ui/dist/client/assets/select-CYF6pF37.js +0 -1
  254. package/apps/ui/dist/client/assets/settings-Dx70jgP_.js +0 -1
  255. package/apps/ui/dist/client/assets/sqlite-error-B6uZjUe8.js +0 -1
  256. package/apps/ui/dist/client/assets/styles-B7Zi9EFA.css +0 -1
  257. package/apps/ui/dist/client/assets/tabs-CmuhkT-c.js +0 -7
  258. package/apps/ui/dist/client/assets/text-filter-DVAZySUS.js +0 -2
  259. package/apps/ui/dist/client/assets/thread-transcript-stats-BUNz6u7F.js +0 -1
  260. package/apps/ui/dist/client/assets/threads._threadId-BB9tTsV4.js +0 -1
  261. package/apps/ui/dist/client/assets/threads._threadId-BMRSFow3.js +0 -1
  262. package/apps/ui/dist/client/assets/useMutation-BSFult2i.js +0 -1
  263. package/apps/ui/dist/client/assets/useQuery-CjINKZf1.js +0 -1
  264. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CQ8Jjs3B.js +0 -387
  265. package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +0 -6
  266. package/apps/ui/dist/server/assets/analytics-CYP_LT5Y.js +0 -16
  267. package/apps/ui/dist/server/assets/analytics-CtpOMVMO.js +0 -146
  268. package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +0 -16
  269. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BKOyL2T6.js +0 -613
  270. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +0 -11
  271. package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-eS87Dx7g.js +0 -20
  272. package/apps/ui/dist/server/assets/antigravity-db-Bh8_U9uw.js +0 -580
  273. package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +0 -126
  274. package/apps/ui/dist/server/assets/antigravity-keychain-panel-CC7FLmAK.js +0 -55
  275. package/apps/ui/dist/server/assets/antigravity-queries-CGrJO9Vr.js +0 -37
  276. package/apps/ui/dist/server/assets/antigravity-server-CHRjVFqN.js +0 -114
  277. package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +0 -11
  278. package/apps/ui/dist/server/assets/antigravity._workspaceKey-B0QeYUOh.js +0 -28
  279. package/apps/ui/dist/server/assets/antigravity._workspaceKey-C3kP-qyN.js +0 -210
  280. package/apps/ui/dist/server/assets/antigravity.index-CPCYkqCi.js +0 -104
  281. package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +0 -11
  282. package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +0 -26
  283. package/apps/ui/dist/server/assets/button-CmTDnzOn.js +0 -46
  284. package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +0 -19
  285. package/apps/ui/dist/server/assets/claude-code-db-Ik3VStKZ.js +0 -361
  286. package/apps/ui/dist/server/assets/claude-code-queries-Cgzi4K-e.js +0 -37
  287. package/apps/ui/dist/server/assets/claude-code-server-PfraClXS.js +0 -72
  288. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-C55oe6zj.js +0 -18
  289. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-D1RYYi3j.js +0 -473
  290. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-DSvPLEUL.js +0 -11
  291. package/apps/ui/dist/server/assets/claude-code-transcript-C-bxh3cS.js +0 -139
  292. package/apps/ui/dist/server/assets/claude-code-transcript-phase-DmUMc8VU.js +0 -10
  293. package/apps/ui/dist/server/assets/claude-code._workspaceKey-B5Xg_-tE.js +0 -28
  294. package/apps/ui/dist/server/assets/claude-code._workspaceKey-BPlzyXPa.js +0 -11
  295. package/apps/ui/dist/server/assets/claude-code._workspaceKey-DqDve2wl.js +0 -191
  296. package/apps/ui/dist/server/assets/claude-code.index-B7yYR7dD.js +0 -92
  297. package/apps/ui/dist/server/assets/claude-code.index-BUHThG1W.js +0 -11
  298. package/apps/ui/dist/server/assets/codex-queries-CtgeZ7VL.js +0 -99
  299. package/apps/ui/dist/server/assets/codex-server-CGXU4H8-.js +0 -2294
  300. package/apps/ui/dist/server/assets/concurrency-VXtYvlGh.js +0 -18
  301. package/apps/ui/dist/server/assets/createServerRpc-CF_DEwnm.js +0 -12
  302. package/apps/ui/dist/server/assets/createSsrRpc-C754NPki.js +0 -16
  303. package/apps/ui/dist/server/assets/cursor-db-CZnYy7aT.js +0 -830
  304. package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +0 -34
  305. package/apps/ui/dist/server/assets/cursor-queries-NCIM0Nat.js +0 -67
  306. package/apps/ui/dist/server/assets/cursor-recovery-CXpO8KcD.js +0 -361
  307. package/apps/ui/dist/server/assets/cursor-server-DNu52A3K.js +0 -213
  308. package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +0 -11
  309. package/apps/ui/dist/server/assets/cursor-threads._composerId-Ckn6ItHI.js +0 -582
  310. package/apps/ui/dist/server/assets/cursor-threads._composerId-p9-ARAzc.js +0 -18
  311. package/apps/ui/dist/server/assets/cursor-transcript-B7tGnqtn.js +0 -125
  312. package/apps/ui/dist/server/assets/cursor._workspaceKey-CZuohIUL.js +0 -28
  313. package/apps/ui/dist/server/assets/cursor._workspaceKey-DPp5JSjy.js +0 -401
  314. package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +0 -11
  315. package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +0 -11
  316. package/apps/ui/dist/server/assets/cursor.index-DkWT-mxw.js +0 -189
  317. package/apps/ui/dist/server/assets/data-table-Cdct823O.js +0 -189
  318. package/apps/ui/dist/server/assets/delete-confirm-dialog-BcBNCxWB.js +0 -144
  319. package/apps/ui/dist/server/assets/download-DMmiy1xf.js +0 -92
  320. package/apps/ui/dist/server/assets/dropdown-menu-Dy_9t6TN.js +0 -36
  321. package/apps/ui/dist/server/assets/empty-plugin-adapters-B3lHh1La.js +0 -5
  322. package/apps/ui/dist/server/assets/export-dialog-D88ze9Gy.js +0 -240
  323. package/apps/ui/dist/server/assets/formatters-FJaGZgJk.js +0 -91
  324. package/apps/ui/dist/server/assets/kiro-db--fXrED_-.js +0 -552
  325. package/apps/ui/dist/server/assets/kiro-queries-CzNlM2ok.js +0 -37
  326. package/apps/ui/dist/server/assets/kiro-server-9WRxg2Au.js +0 -72
  327. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-CRY2c7YO.js +0 -11
  328. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-F1UlwxmR.js +0 -449
  329. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-bvTulT7C.js +0 -18
  330. package/apps/ui/dist/server/assets/kiro-transcript-DoekQBaH.js +0 -112
  331. package/apps/ui/dist/server/assets/kiro-transcript-phase-CJG40nQg.js +0 -27
  332. package/apps/ui/dist/server/assets/kiro._workspaceKey-BDe9sQwo.js +0 -11
  333. package/apps/ui/dist/server/assets/kiro._workspaceKey-CJsjgNwO.js +0 -28
  334. package/apps/ui/dist/server/assets/kiro._workspaceKey-D_-4Qb7y.js +0 -193
  335. package/apps/ui/dist/server/assets/kiro.index-C__-UROk.js +0 -11
  336. package/apps/ui/dist/server/assets/kiro.index-CmTbqeYj.js +0 -93
  337. package/apps/ui/dist/server/assets/loading-panel-BGFnWseS.js +0 -27
  338. package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +0 -23
  339. package/apps/ui/dist/server/assets/model-label-B1NWGc65.js +0 -13
  340. package/apps/ui/dist/server/assets/opencode-db-BM7KjOzc.js +0 -397
  341. package/apps/ui/dist/server/assets/opencode-queries-BeNYXnQv.js +0 -50
  342. package/apps/ui/dist/server/assets/opencode-server-BpQ_kRze.js +0 -72
  343. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-CGQ-t0vD.js +0 -518
  344. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-D8Q7in_Z.js +0 -18
  345. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-DKOvi0lV.js +0 -11
  346. package/apps/ui/dist/server/assets/opencode-think-tags-CAoD-EcZ.js +0 -87
  347. package/apps/ui/dist/server/assets/opencode-transcript-BNTcGNym.js +0 -141
  348. package/apps/ui/dist/server/assets/opencode-transcript-phase-OqLkiQD0.js +0 -32
  349. package/apps/ui/dist/server/assets/opencode._workspaceKey-BdqcWHw1.js +0 -11
  350. package/apps/ui/dist/server/assets/opencode._workspaceKey-CfH96HTT.js +0 -28
  351. package/apps/ui/dist/server/assets/opencode._workspaceKey-DdbHPDrO.js +0 -207
  352. package/apps/ui/dist/server/assets/opencode.index-BbVzkJXP.js +0 -11
  353. package/apps/ui/dist/server/assets/opencode.index-Vh_Gq_1L.js +0 -93
  354. package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +0 -29
  355. package/apps/ui/dist/server/assets/path-transforms-DL2IwtYd.js +0 -31
  356. package/apps/ui/dist/server/assets/projects._project-4io5LO0E.js +0 -20
  357. package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +0 -12
  358. package/apps/ui/dist/server/assets/projects._project-D6ZoGhJ8.js +0 -395
  359. package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +0 -12
  360. package/apps/ui/dist/server/assets/projects.index-BkLiF2FF.js +0 -182
  361. package/apps/ui/dist/server/assets/projects.index-DesYXwfi.js +0 -14
  362. package/apps/ui/dist/server/assets/reload-error-panel-BJMxY3U1.js +0 -25
  363. package/apps/ui/dist/server/assets/route-search-ts4W9MJ9.js +0 -38
  364. package/apps/ui/dist/server/assets/router-Sac2DGk6.js +0 -518
  365. package/apps/ui/dist/server/assets/routes-Bsact1uB.js +0 -184
  366. package/apps/ui/dist/server/assets/routes-BzkJgq4W.js +0 -34
  367. package/apps/ui/dist/server/assets/select-GW76p-ld.js +0 -76
  368. package/apps/ui/dist/server/assets/settings-OayxIYQQ.js +0 -100
  369. package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +0 -52
  370. package/apps/ui/dist/server/assets/shared-DyhChtHf.js +0 -137
  371. package/apps/ui/dist/server/assets/source-session-export-server-DNutCawb.js +0 -38
  372. package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +0 -13
  373. package/apps/ui/dist/server/assets/start-B_HFwkkk.js +0 -4
  374. package/apps/ui/dist/server/assets/tabs-DkaChNVg.js +0 -501
  375. package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +0 -36
  376. package/apps/ui/dist/server/assets/thread-transcript-stats-Dh34mt2u.js +0 -45
  377. package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +0 -26
  378. package/apps/ui/dist/server/assets/threads._threadId-BeXEc4Lo.js +0 -648
  379. package/apps/ui/dist/server/assets/threads._threadId-Ci0S4mKU.js +0 -18
  380. package/apps/ui/dist/server/assets/ui-export-files-BHLX9bhN.js +0 -83
  381. package/apps/ui/dist/server/assets/utils-C_uf36nf.js +0 -8
  382. package/apps/ui/dist/server/server.js +0 -5895
  383. package/bin/codex-chats-claude.js +0 -5
  384. package/bin/codex-chats.js +0 -5
  385. package/bin/spiracha.js +0 -5
  386. package/src/export-chats.ts +0 -120
  387. package/src/export-claude.ts +0 -36
  388. package/src/export-cursor.ts +0 -244
  389. package/src/lib/claude-exporter.ts +0 -864
  390. package/src/lib/codex-exporter-cli.ts +0 -277
  391. package/src/lib/codex-exporter-db.ts +0 -319
  392. package/src/lib/codex-exporter.ts +0 -115
  393. package/src/lib/cursor-exporter.ts +0 -266
  394. package/src/lib/interactive-cli.ts +0 -433
  395. package/src/lib/native-open.ts +0 -54
  396. package/src/mcp-server.ts +0 -137
  397. package/src/spiracha.ts +0 -116
  398. package/src/ui-cli.ts +0 -310
  399. /package/apps/ui/{dist/client → public}/icon.svg +0 -0
  400. /package/apps/ui/{dist/client → public}/manifest.json +0 -0
  401. /package/apps/ui/{dist/client → public}/robots.txt +0 -0
@@ -1,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 };