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
@@ -360,8 +360,11 @@ export const groupCursorBuckets = (buckets: CursorWorkspaceBucket[]): CursorWork
360
360
  return groups.sort((a, b) => b.lastActiveMs - a.lastActiveMs);
361
361
  };
362
362
 
363
- export const listCursorWorkspaceGroups = async (userDir = resolveCursorUserDir()): Promise<CursorWorkspaceGroup[]> => {
364
- return (await discoverCursorWorkspaces(userDir)).groups;
363
+ export const listCursorWorkspaceGroups = async (
364
+ userDir = resolveCursorUserDir(),
365
+ options: CursorDiscoveryOptions = {},
366
+ ): Promise<CursorWorkspaceGroup[]> => {
367
+ return (await discoverCursorWorkspaces(userDir, options)).groups;
365
368
  };
366
369
 
367
370
  export const cursorBucketMatchesQuery = (bucket: CursorWorkspaceBucket, query: string): boolean => {
@@ -462,6 +465,7 @@ export const findCursorTranscriptDirs = async (
462
465
 
463
466
  export type ListCursorThreadsOptions = {
464
467
  includeTranscriptDirs?: boolean;
468
+ updatedAfterMs?: number;
465
469
  };
466
470
 
467
471
  export const listCursorThreadsForGroup = async (
@@ -469,7 +473,7 @@ export const listCursorThreadsForGroup = async (
469
473
  userDir = resolveCursorUserDir(),
470
474
  options: ListCursorThreadsOptions = {},
471
475
  ): Promise<CursorThreadSummary[]> => {
472
- const discovery = await discoverCursorWorkspaces(userDir);
476
+ const discovery = await discoverCursorWorkspaces(userDir, options);
473
477
  const threads = discovery.threadsByKey.get(group.key) ?? [];
474
478
 
475
479
  if (options.includeTranscriptDirs === false) {
@@ -505,6 +509,10 @@ type CursorDiscovery = {
505
509
  threadsByKey: Map<string, CursorThreadSummary[]>;
506
510
  };
507
511
 
512
+ type CursorDiscoveryOptions = {
513
+ updatedAfterMs?: number;
514
+ };
515
+
508
516
  // Discovery does a full scan of the (potentially multi-GB) global DB, so cache it briefly. Writes
509
517
  // (recover/prune/delete) call invalidateCursorDiscoveryCache() so the UI never shows stale results.
510
518
  const DISCOVERY_TTL_MS = 60_000;
@@ -662,7 +670,20 @@ const inferFolderFromBubbles = (db: Database, composerId: string): string | null
662
670
  return inferFolderFromPaths(paths);
663
671
  };
664
672
 
665
- const readAllHeads = (db: Database): Map<string, GlobalHead> => {
673
+ const readAllHeads = (db: Database, options: CursorDiscoveryOptions = {}): Map<string, GlobalHead> => {
674
+ if (options.updatedAfterMs !== undefined) {
675
+ const rows = db
676
+ .query(
677
+ `SELECT substr(key, 14) AS id, value
678
+ FROM cursorDiskKV
679
+ WHERE key LIKE 'composerData:%'
680
+ AND COALESCE(json_extract(value, '$.lastUpdatedAt'), 0) >= ?`,
681
+ )
682
+ .all(options.updatedAfterMs) as Array<{ id: string; value: string }>;
683
+
684
+ return new Map(rows.map((row) => [row.id, parseGlobalHead(row.value)]));
685
+ }
686
+
666
687
  const rows = db
667
688
  .query(`SELECT substr(key, 14) AS id, value FROM cursorDiskKV WHERE key LIKE 'composerData:%'`)
668
689
  .all() as Array<{ id: string; value: string }>;
@@ -693,17 +714,28 @@ const parseGlobalHead = (value: string): GlobalHead => {
693
714
  };
694
715
  };
695
716
 
696
- const readBubbleStats = (db: Database): Map<string, BubbleStat> => {
717
+ const readBubbleStats = (db: Database, composerIds?: Iterable<string>): Map<string, BubbleStat> => {
718
+ const ids = composerIds ? [...composerIds] : null;
719
+ if (ids?.length === 0) {
720
+ return new Map();
721
+ }
722
+
697
723
  // Keys are `bubbleId:<composerId>:<bubbleId>`; composer ids contain no colon, so slice up to the
698
724
  // next ':' rather than assuming a fixed UUID length (keeps tests and any id format working).
699
- const rows = db
700
- .query(
701
- `SELECT substr(key, 10, instr(substr(key, 10), ':') - 1) AS id,
725
+ const query =
726
+ ids === null
727
+ ? `SELECT substr(key, 10, instr(substr(key, 10), ':') - 1) AS id,
728
+ COUNT(*) AS count,
729
+ COALESCE(SUM(length(value)), 0) AS bytes
730
+ FROM cursorDiskKV WHERE key GLOB 'bubbleId:*:*' GROUP BY id`
731
+ : `SELECT substr(key, 10, instr(substr(key, 10), ':') - 1) AS id,
702
732
  COUNT(*) AS count,
703
733
  COALESCE(SUM(length(value)), 0) AS bytes
704
- FROM cursorDiskKV WHERE key GLOB 'bubbleId:*:*' GROUP BY id`,
705
- )
706
- .all() as Array<{ id: string; count: number; bytes: number }>;
734
+ FROM cursorDiskKV
735
+ WHERE key GLOB 'bubbleId:*:*'
736
+ AND substr(key, 10, instr(substr(key, 10), ':') - 1) IN (${ids.map(() => '?').join(',')})
737
+ GROUP BY id`;
738
+ const rows = db.query(query).all(...(ids ?? [])) as Array<{ id: string; count: number; bytes: number }>;
707
739
 
708
740
  return new Map(rows.map((row) => [row.id, { bytes: row.bytes, count: row.count }]));
709
741
  };
@@ -936,14 +968,13 @@ const buildDiscoveryGroups = (
936
968
  return groups.sort((a, b) => b.lastActiveMs - a.lastActiveMs);
937
969
  };
938
970
 
939
- const buildDiscovery = async (userDir: string): Promise<CursorDiscovery> => {
971
+ const buildDiscovery = async (userDir: string, options: CursorDiscoveryOptions = {}): Promise<CursorDiscovery> => {
940
972
  const buckets = await loadCursorBuckets(userDir);
941
973
  const bucketGroups = groupCursorBuckets(buckets);
942
- const fileHistoryActivity = await readCursorFileHistoryProjectActivity(userDir);
943
974
  const globalDbPath = getCursorGlobalDbPath(userDir);
944
975
 
945
976
  if (!(await pathExists(globalDbPath))) {
946
- return assembleDiscovery([], bucketGroups, fileHistoryActivity);
977
+ return assembleDiscovery([], bucketGroups, new Map());
947
978
  }
948
979
 
949
980
  const bucketIdToGroupKey = new Map<string, string>();
@@ -955,14 +986,20 @@ const buildDiscovery = async (userDir: string): Promise<CursorDiscovery> => {
955
986
  }
956
987
  }
957
988
 
958
- const headerInfo = readHeaderInfo(globalDbPath);
959
- const bucketComposerIds = collectBucketComposerIds(buckets);
960
-
961
989
  const db = openCursorReadonlyDb(globalDbPath);
962
990
  try {
963
- const heads = readAllHeads(db);
964
- const stats = readBubbleStats(db);
965
- const universe = new Set<string>([...heads.keys(), ...headerInfo.keys(), ...bucketComposerIds.keys()]);
991
+ const heads = readAllHeads(db, options);
992
+ if (options.updatedAfterMs !== undefined && heads.size === 0) {
993
+ return assembleDiscovery([], bucketGroups, new Map());
994
+ }
995
+
996
+ const headerInfo = readHeaderInfo(globalDbPath);
997
+ const bucketComposerIds = options.updatedAfterMs === undefined ? collectBucketComposerIds(buckets) : new Map();
998
+ const stats = readBubbleStats(db, options.updatedAfterMs === undefined ? undefined : heads.keys());
999
+ const universe =
1000
+ options.updatedAfterMs === undefined
1001
+ ? new Set<string>([...heads.keys(), ...headerInfo.keys(), ...bucketComposerIds.keys()])
1002
+ : new Set<string>(heads.keys());
966
1003
  const resolved: ResolvedThread[] = [];
967
1004
 
968
1005
  for (const composerId of universe) {
@@ -980,13 +1017,22 @@ const buildDiscovery = async (userDir: string): Promise<CursorDiscovery> => {
980
1017
  );
981
1018
  }
982
1019
 
1020
+ const fileHistoryActivity =
1021
+ options.updatedAfterMs === undefined ? await readCursorFileHistoryProjectActivity(userDir) : new Map();
983
1022
  return assembleDiscovery(resolved, bucketGroups, fileHistoryActivity);
984
1023
  } finally {
985
1024
  db.close();
986
1025
  }
987
1026
  };
988
1027
 
989
- const discoverCursorWorkspaces = async (userDir: string): Promise<CursorDiscovery> => {
1028
+ const discoverCursorWorkspaces = async (
1029
+ userDir: string,
1030
+ options: CursorDiscoveryOptions = {},
1031
+ ): Promise<CursorDiscovery> => {
1032
+ if (options.updatedAfterMs !== undefined) {
1033
+ return await buildDiscovery(userDir, options);
1034
+ }
1035
+
990
1036
  const now = Date.now();
991
1037
  if (discoveryCache && discoveryCache.userDir === userDir && now - discoveryCache.at < DISCOVERY_TTL_MS) {
992
1038
  return discoveryCache.value;
@@ -152,25 +152,6 @@ export type CursorExportOptions = {
152
152
  outputFormat: ExportFormat;
153
153
  };
154
154
 
155
- export type CursorCliOptions = CursorExportOptions & {
156
- userDir: string;
157
- workspaceQuery: string | null;
158
- threadIds: string[];
159
- outputDir: string | null;
160
- };
161
-
162
- export type CursorExportedFile = {
163
- composerId: string;
164
- outputPath: string;
165
- };
166
-
167
- export type CursorExportRunResult = {
168
- outputDir: string;
169
- exportedCount: number;
170
- files: CursorExportedFile[];
171
- missingThreadIds: string[];
172
- };
173
-
174
155
  export type CursorRecoverResult = {
175
156
  workspaceKey: string;
176
157
  activeBucketId: string;
@@ -0,0 +1,268 @@
1
+ import net from 'node:net';
2
+ import path from 'node:path';
3
+ import { resolveQoderUserDir } from './qoder-exporter-types';
4
+ import { asObject, asString, type JsonValue } from './shared';
5
+
6
+ const DEFAULT_TIMEOUT_MS = 2_500;
7
+ const DEFAULT_DRAIN_MS = 300;
8
+ const INITIALIZE_REQUEST_ID = 1;
9
+ const LOAD_REQUEST_ID = 2;
10
+
11
+ type JsonRpcMessage = {
12
+ id?: number;
13
+ jsonrpc?: '2.0';
14
+ method?: string;
15
+ params?: Record<string, JsonValue>;
16
+ result?: JsonValue;
17
+ };
18
+
19
+ export type QoderAcpSessionUpdate = {
20
+ requestId: string | null;
21
+ sessionId: string;
22
+ update: Record<string, JsonValue>;
23
+ };
24
+
25
+ export type QoderAcpSessionLoadResult = {
26
+ events: QoderAcpSessionUpdate[];
27
+ socketPath: string;
28
+ };
29
+
30
+ export type QoderAcpSessionLoadOptions = {
31
+ cwd: string;
32
+ drainMs?: number;
33
+ requestLimit?: number;
34
+ sessionId: string;
35
+ socketPath?: string;
36
+ taskId?: string | null;
37
+ timeoutMs?: number;
38
+ };
39
+
40
+ export const resolveQoderAcpSocketPath = (): string => {
41
+ const configured = process.env.SPIRACHA_QODER_SOCKET_PATH?.trim() || process.env.SPIRACHA_QODER_SOCKET?.trim();
42
+ return configured ? configured : path.join(path.dirname(resolveQoderUserDir()), 'SharedClientCache', 'qoder.sock');
43
+ };
44
+
45
+ const encodeJsonRpcMessage = (message: JsonRpcMessage): string => {
46
+ const body = JSON.stringify(message);
47
+ return `Content-Length: ${Buffer.byteLength(body)}\r\n\r\n${body}`;
48
+ };
49
+
50
+ const appendSocketChunk = (
51
+ buffer: Buffer<ArrayBufferLike>,
52
+ chunk: Buffer<ArrayBufferLike> | string,
53
+ ): Buffer<ArrayBufferLike> => {
54
+ return Buffer.concat([buffer, typeof chunk === 'string' ? Buffer.from(chunk) : chunk]);
55
+ };
56
+
57
+ const parseJsonRpcMessages = (
58
+ buffer: Buffer<ArrayBufferLike>,
59
+ ): {
60
+ messages: JsonRpcMessage[];
61
+ rest: Buffer<ArrayBufferLike>;
62
+ } => {
63
+ const messages: JsonRpcMessage[] = [];
64
+ let rest = buffer;
65
+
66
+ while (true) {
67
+ const headerEnd = rest.indexOf('\r\n\r\n');
68
+ if (headerEnd < 0) {
69
+ return { messages, rest };
70
+ }
71
+
72
+ const header = rest.subarray(0, headerEnd).toString('utf8');
73
+ const lengthMatch = /Content-Length:\s*(\d+)/iu.exec(header);
74
+ if (!lengthMatch) {
75
+ return { messages, rest: Buffer.alloc(0) };
76
+ }
77
+
78
+ const contentLength = Number(lengthMatch[1]);
79
+ const bodyStart = headerEnd + 4;
80
+ const bodyEnd = bodyStart + contentLength;
81
+ if (rest.length < bodyEnd) {
82
+ return { messages, rest };
83
+ }
84
+
85
+ try {
86
+ messages.push(JSON.parse(rest.subarray(bodyStart, bodyEnd).toString('utf8')) as JsonRpcMessage);
87
+ } catch {}
88
+
89
+ rest = rest.subarray(bodyEnd);
90
+ }
91
+ };
92
+
93
+ const getRequestId = (params: Record<string, JsonValue> | null): string | null => {
94
+ const meta = asObject(params?._meta ?? null);
95
+ return asString(meta?.['ai-coding/request-id'] ?? null);
96
+ };
97
+
98
+ const getSessionUpdate = (message: JsonRpcMessage): QoderAcpSessionUpdate | null => {
99
+ if (message.method !== 'session/update') {
100
+ return null;
101
+ }
102
+
103
+ const params = asObject(message.params ?? null);
104
+ const sessionId = asString(params?.sessionId ?? null);
105
+ const update = asObject(params?.update ?? null);
106
+ if (!sessionId || !update) {
107
+ return null;
108
+ }
109
+
110
+ return {
111
+ requestId: getRequestId(params),
112
+ sessionId,
113
+ update,
114
+ };
115
+ };
116
+
117
+ export const loadQoderAcpSession = async (
118
+ options: QoderAcpSessionLoadOptions,
119
+ ): Promise<QoderAcpSessionLoadResult | null> => {
120
+ const socketPath = options.socketPath ?? resolveQoderAcpSocketPath();
121
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
122
+ const drainMs = options.drainMs ?? DEFAULT_DRAIN_MS;
123
+ const requestLimit = options.requestLimit ?? 50;
124
+
125
+ return await new Promise<QoderAcpSessionLoadResult | null>((resolve) => {
126
+ const socket = net.createConnection(socketPath);
127
+ const events: QoderAcpSessionUpdate[] = [];
128
+ let buffer: Buffer<ArrayBufferLike> = Buffer.alloc(0);
129
+ let resolved = false;
130
+ let loadCompleted = false;
131
+ let drainTimer: ReturnType<typeof setTimeout> | null = null;
132
+ let timeout: ReturnType<typeof setTimeout> | null = null;
133
+
134
+ const cleanup = () => {
135
+ if (drainTimer) {
136
+ clearTimeout(drainTimer);
137
+ }
138
+ if (timeout) {
139
+ clearTimeout(timeout);
140
+ }
141
+ socket.destroy();
142
+ };
143
+
144
+ const finish = (result: QoderAcpSessionLoadResult | null) => {
145
+ if (resolved) {
146
+ return;
147
+ }
148
+
149
+ resolved = true;
150
+ cleanup();
151
+ resolve(result);
152
+ };
153
+
154
+ timeout = setTimeout(() => {
155
+ finish(events.length > 0 ? { events, socketPath } : null);
156
+ }, timeoutMs);
157
+
158
+ const write = (message: JsonRpcMessage) => {
159
+ socket.write(encodeJsonRpcMessage(message));
160
+ };
161
+
162
+ const sendLoadRequest = () => {
163
+ write({
164
+ id: LOAD_REQUEST_ID,
165
+ jsonrpc: '2.0',
166
+ method: 'session/load',
167
+ params: {
168
+ _meta: {
169
+ 'ai-coding/load-request-limit': requestLimit,
170
+ ...(options.taskId ? { 'ai-coding/quest-task-id': options.taskId } : {}),
171
+ },
172
+ cwd: options.cwd,
173
+ mcpServers: [],
174
+ sessionId: options.sessionId,
175
+ timestamp: Date.now(),
176
+ },
177
+ });
178
+ };
179
+
180
+ const scheduleDrain = () => {
181
+ if (drainTimer) {
182
+ clearTimeout(drainTimer);
183
+ }
184
+
185
+ drainTimer = setTimeout(() => {
186
+ finish(events.length > 0 ? { events, socketPath } : null);
187
+ }, drainMs);
188
+ };
189
+
190
+ const recordMatchingUpdate = (message: JsonRpcMessage) => {
191
+ const update = getSessionUpdate(message);
192
+ if (update?.sessionId !== options.sessionId) {
193
+ return false;
194
+ }
195
+
196
+ if (events.length < requestLimit) {
197
+ events.push(update);
198
+ }
199
+ if (loadCompleted && events.length >= requestLimit) {
200
+ finish({ events, socketPath });
201
+ return true;
202
+ }
203
+ if (loadCompleted) {
204
+ scheduleDrain();
205
+ }
206
+ return true;
207
+ };
208
+
209
+ const markLoadCompleted = (message: JsonRpcMessage) => {
210
+ if (message.id !== LOAD_REQUEST_ID || loadCompleted) {
211
+ return false;
212
+ }
213
+
214
+ loadCompleted = true;
215
+ if (events.length >= requestLimit) {
216
+ finish({ events, socketPath });
217
+ return true;
218
+ }
219
+ scheduleDrain();
220
+ return true;
221
+ };
222
+
223
+ const handleMessage = (message: JsonRpcMessage) => {
224
+ if (message.id === INITIALIZE_REQUEST_ID) {
225
+ sendLoadRequest();
226
+ return;
227
+ }
228
+
229
+ if (recordMatchingUpdate(message)) {
230
+ return;
231
+ }
232
+
233
+ markLoadCompleted(message);
234
+ };
235
+
236
+ socket.on('connect', () => {
237
+ write({
238
+ id: INITIALIZE_REQUEST_ID,
239
+ jsonrpc: '2.0',
240
+ method: 'initialize',
241
+ params: {
242
+ clientCapabilities: {},
243
+ ideWindowType: 'quest',
244
+ protocolVersion: 1,
245
+ timestamp: Date.now(),
246
+ },
247
+ });
248
+ });
249
+
250
+ socket.on('data', (chunk) => {
251
+ try {
252
+ const parsed = parseJsonRpcMessages(appendSocketChunk(buffer, chunk));
253
+ buffer = parsed.rest;
254
+ parsed.messages.forEach(handleMessage);
255
+ } catch {
256
+ finish(events.length > 0 ? { events, socketPath } : null);
257
+ }
258
+ });
259
+
260
+ socket.on('error', () => {
261
+ finish(null);
262
+ });
263
+
264
+ socket.on('close', () => {
265
+ finish(events.length > 0 ? { events, socketPath } : null);
266
+ });
267
+ });
268
+ };