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,864 +0,0 @@
1
- import { access, lstat, readdir } from 'node:fs/promises';
2
- import path from 'node:path';
3
- import {
4
- asBoolean,
5
- asNumber,
6
- asObject,
7
- asString,
8
- CliUsageError,
9
- cleanExtractedText,
10
- cleanInlineTitle,
11
- type ExportFormat,
12
- expandHome,
13
- formatInlineLiteral,
14
- type JsonValue,
15
- type MetadataEntry,
16
- readJsonlObjects,
17
- renderCodeBlock,
18
- renderDocumentTitle,
19
- renderMetadataBlock,
20
- renderSection,
21
- writeExportFile,
22
- } from './shared';
23
-
24
- export type ClaudeCliOptions = {
25
- inputPath: string;
26
- outputPath: string | null;
27
- outputFormat: ExportFormat;
28
- includeTools: boolean;
29
- };
30
-
31
- export type ClaudeExportResult = {
32
- outputPath: string;
33
- sourcePath: string;
34
- };
35
-
36
- type ClaudeExportMetadata = {
37
- sessionId?: string;
38
- cliSessionId?: string;
39
- cwd?: string;
40
- originCwd?: string;
41
- createdAt?: number;
42
- lastActivityAt?: number;
43
- model?: string;
44
- effort?: string;
45
- isArchived?: boolean;
46
- title?: string;
47
- titleSource?: string;
48
- permissionMode?: string;
49
- prNumber?: number;
50
- prUrl?: string;
51
- prRepository?: string;
52
- prState?: string;
53
- completedTurns?: number;
54
- };
55
-
56
- type ClaudeSource = {
57
- jsonlPath: string;
58
- metadataPath: string | null;
59
- metadata: ClaudeExportMetadata | null;
60
- outputBaseName: string;
61
- };
62
-
63
- type ClaudeSessionMeta = {
64
- sessionId?: string;
65
- cwd?: string;
66
- entrypoint?: string;
67
- version?: string;
68
- gitBranch?: string;
69
- model?: string;
70
- firstTimestamp?: string;
71
- lastTimestamp?: string;
72
- };
73
-
74
- type BashToolCall = {
75
- id: string;
76
- command: string;
77
- };
78
-
79
- type ConvertState = {
80
- bashCallsById: Map<string, BashToolCall>;
81
- firstUserText: string | null;
82
- };
83
-
84
- export const DEFAULT_OUTPUT_DIR = path.join(process.cwd(), 'exports', 'claude');
85
-
86
- export const parseClaudeCliArgs = (argv: string[]): ClaudeCliOptions => {
87
- let inputPath: string | null = null;
88
- let outputPath: string | null = null;
89
- let outputFormat: ExportFormat = 'md';
90
- let includeTools = false;
91
-
92
- for (let index = 0; index < argv.length; index += 1) {
93
- const nextIndex = applyClaudeCliArg(argv, index, {
94
- includeTools,
95
- inputPath,
96
- outputFormat,
97
- outputPath,
98
- });
99
-
100
- includeTools = nextIndex.state.includeTools;
101
- inputPath = nextIndex.state.inputPath;
102
- outputFormat = nextIndex.state.outputFormat;
103
- outputPath = nextIndex.state.outputPath;
104
- index = nextIndex.index;
105
- }
106
-
107
- if (!inputPath) {
108
- throw new CliUsageError('A Claude export path is required.');
109
- }
110
-
111
- return {
112
- includeTools,
113
- inputPath,
114
- outputFormat,
115
- outputPath,
116
- };
117
- };
118
-
119
- type ClaudeCliState = {
120
- inputPath: string | null;
121
- outputPath: string | null;
122
- outputFormat: ExportFormat;
123
- includeTools: boolean;
124
- };
125
-
126
- type ClaudeCliNext = {
127
- index: number;
128
- state: ClaudeCliState;
129
- };
130
-
131
- const applyClaudeCliArg = (argv: string[], index: number, state: ClaudeCliState): ClaudeCliNext => {
132
- const arg = argv[index];
133
-
134
- if (arg === '--input' || arg === '-i') {
135
- return {
136
- index: index + 1,
137
- state: {
138
- ...state,
139
- inputPath: expandHome(requireValue(argv[index + 1], arg)),
140
- },
141
- };
142
- }
143
-
144
- if (arg === '--output' || arg === '-o') {
145
- return {
146
- index: index + 1,
147
- state: {
148
- ...state,
149
- outputPath: expandHome(requireValue(argv[index + 1], arg)),
150
- },
151
- };
152
- }
153
-
154
- if (arg === '--tools') {
155
- return {
156
- index,
157
- state: {
158
- ...state,
159
- includeTools: true,
160
- },
161
- };
162
- }
163
-
164
- if (arg.startsWith('--output-format=')) {
165
- return {
166
- index,
167
- state: {
168
- ...state,
169
- outputFormat: parseExportFormat(arg.slice('--output-format='.length)),
170
- },
171
- };
172
- }
173
-
174
- if (arg === '--output-format') {
175
- return {
176
- index: index + 1,
177
- state: {
178
- ...state,
179
- outputFormat: parseExportFormat(requireValue(argv[index + 1], '--output-format')),
180
- },
181
- };
182
- }
183
-
184
- if (!arg.startsWith('-') && !state.inputPath) {
185
- return {
186
- index,
187
- state: {
188
- ...state,
189
- inputPath: expandHome(arg),
190
- },
191
- };
192
- }
193
-
194
- if (!arg.startsWith('-') && !state.outputPath) {
195
- return {
196
- index,
197
- state: {
198
- ...state,
199
- outputPath: expandHome(arg),
200
- },
201
- };
202
- }
203
-
204
- throw new CliUsageError(`Unknown argument: ${arg}`);
205
- };
206
-
207
- export const getClaudeHelpText = (): string => {
208
- return [
209
- 'Export a Claude Code transcript JSONL to Markdown or TXT.',
210
- '',
211
- 'Usage:',
212
- ' codex-chats-claude --input PATH [--output PATH] [--output-format md|txt] [--tools]',
213
- ' codex-chats-claude PATH [OUTPUT_PATH]',
214
- '',
215
- 'Input:',
216
- ' PATH can be either the exported Claude .jsonl file or the export directory that contains metadata.json.',
217
- '',
218
- 'Options:',
219
- ' --input, -i Claude transcript file or export directory',
220
- ' --output, -o Output file path, or output directory when no .md/.txt extension is supplied',
221
- ' --output-format Output file format: md or txt (default: md)',
222
- ' --tools Include Bash tool calls and their outputs',
223
- ' --help, -h Show this help text',
224
- '',
225
- 'Default output:',
226
- ` ${DEFAULT_OUTPUT_DIR}/<session-id>.md`,
227
- ].join('\n');
228
- };
229
-
230
- export const runClaudeExport = async (options: ClaudeCliOptions): Promise<ClaudeExportResult> => {
231
- const source = await resolveClaudeSource(options.inputPath);
232
- const outputPath = await resolveOutputPath(source, options);
233
- const content = await convertClaudeTranscript(source, outputPath, options);
234
-
235
- if (!content) {
236
- throw new Error(`No transcript content found in ${source.jsonlPath}`);
237
- }
238
-
239
- await writeExportFile(outputPath, content);
240
-
241
- return {
242
- outputPath,
243
- sourcePath: source.jsonlPath,
244
- };
245
- };
246
-
247
- const resolveClaudeSource = async (inputPath: string): Promise<ClaudeSource> => {
248
- const resolvedInput = path.resolve(inputPath);
249
- const stats = await lstat(resolvedInput).catch(() => null);
250
-
251
- if (!stats) {
252
- throw new Error(`Input path does not exist: ${resolvedInput}`);
253
- }
254
-
255
- if (stats.isFile()) {
256
- return await resolveClaudeFileSource(resolvedInput);
257
- }
258
-
259
- if (!stats.isDirectory()) {
260
- throw new Error(`Unsupported input path: ${resolvedInput}`);
261
- }
262
-
263
- return await resolveClaudeDirectorySource(resolvedInput);
264
- };
265
-
266
- const findMetadataPathForJsonl = async (jsonlPath: string): Promise<string | null> => {
267
- const parentMetadataPath = path.join(path.dirname(jsonlPath), 'metadata.json');
268
- return (await fileExists(parentMetadataPath)) ? parentMetadataPath : null;
269
- };
270
-
271
- const readClaudeMetadata = async (metadataPath: string | null): Promise<ClaudeExportMetadata | null> => {
272
- if (!metadataPath) {
273
- return null;
274
- }
275
-
276
- try {
277
- const raw = await Bun.file(metadataPath).text();
278
- return parseClaudeMetadata(JSON.parse(raw) as Record<string, JsonValue>);
279
- } catch {
280
- return null;
281
- }
282
- };
283
-
284
- const resolveOutputPath = async (source: ClaudeSource, options: ClaudeCliOptions): Promise<string> => {
285
- const fileName = `${source.outputBaseName}.${options.outputFormat}`;
286
-
287
- if (!options.outputPath) {
288
- return path.join(DEFAULT_OUTPUT_DIR, fileName);
289
- }
290
-
291
- const resolvedOutput = path.resolve(options.outputPath);
292
- const extension = path.extname(resolvedOutput).toLowerCase();
293
-
294
- if (extension === '.md' || extension === '.txt') {
295
- return resolvedOutput;
296
- }
297
-
298
- const stats = await lstat(resolvedOutput).catch(() => null);
299
- if (stats?.isDirectory()) {
300
- return path.join(resolvedOutput, fileName);
301
- }
302
-
303
- return path.join(resolvedOutput, fileName);
304
- };
305
-
306
- const convertClaudeTranscript = async (
307
- source: ClaudeSource,
308
- outputPath: string,
309
- options: ClaudeCliOptions,
310
- ): Promise<string | null> => {
311
- const sessionMeta: ClaudeSessionMeta = {
312
- cwd: source.metadata?.cwd ?? source.metadata?.originCwd,
313
- model: source.metadata?.model,
314
- sessionId: source.metadata?.cliSessionId ?? source.metadata?.sessionId,
315
- };
316
- const state: ConvertState = {
317
- bashCallsById: new Map(),
318
- firstUserText: null,
319
- };
320
- const sections: string[] = [];
321
-
322
- try {
323
- for await (const parsed of readJsonlObjects(source.jsonlPath)) {
324
- captureClaudeSessionMeta(parsed, sessionMeta);
325
- sections.push(...extractClaudeBlocks(parsed, options, state));
326
- }
327
- } catch (error) {
328
- const message = error instanceof Error ? error.message : String(error);
329
- throw new Error(`Failed to read Claude transcript ${source.jsonlPath}: ${message}`);
330
- }
331
-
332
- if (sections.length === 0) {
333
- return null;
334
- }
335
-
336
- const title = getTitle(source, state, sessionMeta);
337
- const metadata = buildMetadataEntries(source, outputPath, sessionMeta);
338
- const parts = [
339
- renderDocumentTitle(title, options.outputFormat),
340
- '',
341
- renderMetadataBlock(metadata, options.outputFormat),
342
- ...sections,
343
- ].filter(Boolean);
344
-
345
- return parts.join('\n').trimEnd() + '\n';
346
- };
347
-
348
- const resolveClaudeFileSource = async (resolvedInput: string): Promise<ClaudeSource> => {
349
- if (!resolvedInput.endsWith('.jsonl')) {
350
- throw new Error(`Expected a .jsonl file, got: ${resolvedInput}`);
351
- }
352
-
353
- const metadataPath = await findMetadataPathForJsonl(resolvedInput);
354
- const metadata = await readClaudeMetadata(metadataPath);
355
-
356
- return {
357
- jsonlPath: resolvedInput,
358
- metadata,
359
- metadataPath,
360
- outputBaseName: metadata?.cliSessionId ?? path.basename(resolvedInput, '.jsonl'),
361
- };
362
- };
363
-
364
- const resolveClaudeDirectorySource = async (resolvedInput: string): Promise<ClaudeSource> => {
365
- const metadataPathCandidate = path.join(resolvedInput, 'metadata.json');
366
- const metadataPath = (await fileExists(metadataPathCandidate)) ? metadataPathCandidate : null;
367
- const metadata = await readClaudeMetadata(metadataPath);
368
- const jsonlPath = await findClaudeJsonlPath(resolvedInput, metadata);
369
-
370
- return {
371
- jsonlPath,
372
- metadata,
373
- metadataPath,
374
- outputBaseName: metadata?.cliSessionId ?? path.basename(jsonlPath, '.jsonl'),
375
- };
376
- };
377
-
378
- const findClaudeJsonlPath = async (resolvedInput: string, metadata: ClaudeExportMetadata | null): Promise<string> => {
379
- if (metadata?.cliSessionId) {
380
- const metadataJsonlPath = path.join(resolvedInput, `${metadata.cliSessionId}.jsonl`);
381
- if (await fileExists(metadataJsonlPath)) {
382
- return metadataJsonlPath;
383
- }
384
- }
385
-
386
- const files = (await readdir(resolvedInput, { withFileTypes: true }))
387
- .filter((entry) => entry.isFile() && entry.name.endsWith('.jsonl'))
388
- .map((entry) => path.join(resolvedInput, entry.name))
389
- .sort();
390
-
391
- if (files.length === 1) {
392
- return files[0] ?? resolvedInput;
393
- }
394
-
395
- if (files.length > 1) {
396
- throw new Error(
397
- `Multiple top-level .jsonl files found in ${resolvedInput}; pass the specific transcript file instead.`,
398
- );
399
- }
400
-
401
- throw new Error(`No top-level Claude transcript .jsonl found in ${resolvedInput}`);
402
- };
403
-
404
- const parseClaudeMetadata = (parsed: Record<string, JsonValue>): ClaudeExportMetadata => ({
405
- ...buildClaudeMetadataIdentity(parsed),
406
- ...buildClaudeMetadataContext(parsed),
407
- ...buildClaudeMetadataActivity(parsed),
408
- ...buildClaudeMetadataProject(parsed),
409
- });
410
-
411
- const buildClaudeMetadataIdentity = (
412
- parsed: Record<string, JsonValue>,
413
- ): Pick<ClaudeExportMetadata, 'cliSessionId' | 'sessionId'> => ({
414
- cliSessionId: asString(parsed.cliSessionId) ?? undefined,
415
- sessionId: asString(parsed.sessionId) ?? undefined,
416
- });
417
-
418
- const buildClaudeMetadataContext = (
419
- parsed: Record<string, JsonValue>,
420
- ): Pick<
421
- ClaudeExportMetadata,
422
- 'cwd' | 'originCwd' | 'model' | 'effort' | 'permissionMode' | 'title' | 'titleSource'
423
- > => ({
424
- cwd: asString(parsed.cwd) ?? undefined,
425
- effort: asString(parsed.effort) ?? undefined,
426
- model: asString(parsed.model) ?? undefined,
427
- originCwd: asString(parsed.originCwd) ?? undefined,
428
- permissionMode: asString(parsed.permissionMode) ?? undefined,
429
- title: asString(parsed.title) ?? undefined,
430
- titleSource: asString(parsed.titleSource) ?? undefined,
431
- });
432
-
433
- const buildClaudeMetadataActivity = (
434
- parsed: Record<string, JsonValue>,
435
- ): Pick<ClaudeExportMetadata, 'completedTurns' | 'createdAt' | 'lastActivityAt' | 'isArchived'> => ({
436
- completedTurns: asNumber(parsed.completedTurns) ?? undefined,
437
- createdAt: asNumber(parsed.createdAt) ?? undefined,
438
- isArchived: typeof parsed.isArchived === 'boolean' ? parsed.isArchived : undefined,
439
- lastActivityAt: asNumber(parsed.lastActivityAt) ?? undefined,
440
- });
441
-
442
- const buildClaudeMetadataProject = (
443
- parsed: Record<string, JsonValue>,
444
- ): Pick<ClaudeExportMetadata, 'prNumber' | 'prRepository' | 'prState' | 'prUrl'> => ({
445
- prNumber: asNumber(parsed.prNumber) ?? undefined,
446
- prRepository: asString(parsed.prRepository) ?? undefined,
447
- prState: asString(parsed.prState) ?? undefined,
448
- prUrl: asString(parsed.prUrl) ?? undefined,
449
- });
450
-
451
- const captureClaudeSessionMeta = (parsed: Record<string, JsonValue>, meta: ClaudeSessionMeta) => {
452
- meta.sessionId = asString(parsed.sessionId) ?? meta.sessionId;
453
- meta.cwd = asString(parsed.cwd) ?? meta.cwd;
454
- meta.entrypoint = asString(parsed.entrypoint) ?? meta.entrypoint;
455
- meta.version = asString(parsed.version) ?? meta.version;
456
- meta.gitBranch = asString(parsed.gitBranch) ?? meta.gitBranch;
457
-
458
- const timestamp = asString(parsed.timestamp);
459
- if (timestamp) {
460
- meta.firstTimestamp = meta.firstTimestamp && meta.firstTimestamp < timestamp ? meta.firstTimestamp : timestamp;
461
- meta.lastTimestamp = meta.lastTimestamp && meta.lastTimestamp > timestamp ? meta.lastTimestamp : timestamp;
462
- }
463
-
464
- const message = asObject(parsed.message);
465
- meta.model = asString(message?.model ?? null) ?? meta.model;
466
- };
467
-
468
- const extractClaudeBlocks = (
469
- parsed: Record<string, JsonValue>,
470
- options: ClaudeCliOptions,
471
- state: ConvertState,
472
- ): string[] => {
473
- if (asBoolean(parsed.isCompactSummary)) {
474
- return [];
475
- }
476
-
477
- const type = asString(parsed.type);
478
- if (type === 'assistant') {
479
- return extractAssistantBlocks(parsed, options, state);
480
- }
481
-
482
- if (type === 'user') {
483
- return extractUserBlocks(parsed, options, state);
484
- }
485
-
486
- return [];
487
- };
488
-
489
- const extractAssistantBlocks = (
490
- parsed: Record<string, JsonValue>,
491
- options: ClaudeCliOptions,
492
- state: ConvertState,
493
- ): string[] => {
494
- const message = asObject(parsed.message);
495
- if (!message || asString(message.role) !== 'assistant') {
496
- return [];
497
- }
498
-
499
- return extractBlocksFromContentSequence('assistant', message.content, options, state);
500
- };
501
-
502
- const extractUserBlocks = (
503
- parsed: Record<string, JsonValue>,
504
- options: ClaudeCliOptions,
505
- state: ConvertState,
506
- ): string[] => {
507
- const message = asObject(parsed.message);
508
- if (!message || asString(message.role) !== 'user') {
509
- return [];
510
- }
511
-
512
- return extractBlocksFromContentSequence('user', message.content, options, state);
513
- };
514
-
515
- const extractBlocksFromContentSequence = (
516
- role: 'user' | 'assistant',
517
- content: JsonValue,
518
- options: ClaudeCliOptions,
519
- state: ConvertState,
520
- ): string[] => {
521
- const items = Array.isArray(content) ? content : [content];
522
- const blocks: string[] = [];
523
- const textParts: string[] = [];
524
-
525
- const flushText = () => {
526
- const text = cleanExtractedText(textParts.join('\n\n')).trim();
527
- textParts.length = 0;
528
-
529
- if (!text) {
530
- return;
531
- }
532
-
533
- if (role === 'user' && !state.firstUserText) {
534
- state.firstUserText = text;
535
- }
536
-
537
- blocks.push(renderSection(role === 'user' ? 'User' : 'Assistant', text, options.outputFormat));
538
- };
539
-
540
- for (const item of items) {
541
- appendClaudeContentItem(item, options, state, blocks, textParts, flushText);
542
- }
543
-
544
- flushText();
545
- return blocks;
546
- };
547
-
548
- const appendClaudeContentItem = (
549
- item: JsonValue,
550
- options: ClaudeCliOptions,
551
- state: ConvertState,
552
- blocks: string[],
553
- textParts: string[],
554
- flushText: () => void,
555
- ) => {
556
- if (typeof item === 'string') {
557
- textParts.push(item);
558
- return;
559
- }
560
-
561
- const contentItem = asObject(item);
562
- if (!contentItem) {
563
- return;
564
- }
565
-
566
- appendClaudeStructuredContentItem(contentItem, options, state, blocks, textParts, flushText);
567
- };
568
-
569
- const appendClaudeStructuredContentItem = (
570
- contentItem: Record<string, JsonValue>,
571
- options: ClaudeCliOptions,
572
- state: ConvertState,
573
- blocks: string[],
574
- textParts: string[],
575
- flushText: () => void,
576
- ) => {
577
- const type = asString(contentItem.type);
578
- if (isClaudeTextContentType(type)) {
579
- appendClaudeTextContentItem(contentItem, textParts);
580
- return;
581
- }
582
-
583
- if (type === 'thinking') {
584
- flushText();
585
- return;
586
- }
587
-
588
- if (type === 'tool_use') {
589
- appendClaudeToolUseContentItem(contentItem, options, state, blocks, flushText);
590
- return;
591
- }
592
-
593
- if (type === 'tool_result') {
594
- appendClaudeToolResultContentItem(contentItem, options, state, blocks, flushText);
595
- return;
596
- }
597
-
598
- appendClaudeFallbackContentItem(contentItem, textParts);
599
- };
600
-
601
- const appendClaudeTextContentItem = (contentItem: Record<string, JsonValue>, textParts: string[]) => {
602
- const text = asString(contentItem.text);
603
- if (text) {
604
- textParts.push(text);
605
- }
606
- };
607
-
608
- const appendClaudeToolUseContentItem = (
609
- contentItem: Record<string, JsonValue>,
610
- options: ClaudeCliOptions,
611
- state: ConvertState,
612
- blocks: string[],
613
- flushText: () => void,
614
- ) => {
615
- flushText();
616
- captureBashToolCall(contentItem, state);
617
-
618
- if (options.includeTools) {
619
- const block = renderToolCallBlock(contentItem, options.outputFormat);
620
- if (block) {
621
- blocks.push(block);
622
- }
623
- }
624
- };
625
-
626
- const appendClaudeToolResultContentItem = (
627
- contentItem: Record<string, JsonValue>,
628
- options: ClaudeCliOptions,
629
- state: ConvertState,
630
- blocks: string[],
631
- flushText: () => void,
632
- ) => {
633
- flushText();
634
-
635
- if (options.includeTools) {
636
- const block = renderToolResultBlock(contentItem, state, options.outputFormat);
637
- if (block) {
638
- blocks.push(block);
639
- }
640
- }
641
- };
642
-
643
- const appendClaudeFallbackContentItem = (contentItem: Record<string, JsonValue>, textParts: string[]) => {
644
- const fallbackText = asString(contentItem.text);
645
- if (fallbackText) {
646
- textParts.push(fallbackText);
647
- }
648
- };
649
-
650
- const isClaudeTextContentType = (type: string | null): boolean =>
651
- type === 'text' || type === 'input_text' || type === 'output_text';
652
-
653
- const captureBashToolCall = (contentItem: Record<string, JsonValue>, state: ConvertState) => {
654
- if (asString(contentItem.name) !== 'Bash') {
655
- return;
656
- }
657
-
658
- const toolId = asString(contentItem.id);
659
- const input = asObject(contentItem.input);
660
- const command = asString(input?.command ?? null);
661
-
662
- if (!toolId || !command) {
663
- return;
664
- }
665
-
666
- state.bashCallsById.set(toolId, {
667
- command,
668
- id: toolId,
669
- });
670
- };
671
-
672
- const renderToolCallBlock = (contentItem: Record<string, JsonValue>, outputFormat: ExportFormat): string => {
673
- if (asString(contentItem.name) !== 'Bash') {
674
- return '';
675
- }
676
-
677
- const input = asObject(contentItem.input);
678
- const command = asString(input?.command ?? null)?.trim();
679
- if (!command) {
680
- return '';
681
- }
682
-
683
- return renderSection('Tool', `Command: ${formatInlineLiteral(command, outputFormat)}`, outputFormat);
684
- };
685
-
686
- const renderToolResultBlock = (
687
- contentItem: Record<string, JsonValue>,
688
- state: ConvertState,
689
- outputFormat: ExportFormat,
690
- ): string => {
691
- const toolUseId = asString(contentItem.tool_use_id);
692
- if (!toolUseId || !state.bashCallsById.has(toolUseId)) {
693
- return '';
694
- }
695
-
696
- const outputText = cleanExtractedText(extractClaudeText(contentItem.content)).trim();
697
- if (!outputText) {
698
- return '';
699
- }
700
-
701
- const lines: string[] = [];
702
- if (asBoolean(contentItem.is_error)) {
703
- lines.push('Error: true', '');
704
- }
705
- lines.push(renderCodeBlock(outputText, outputFormat));
706
-
707
- return renderSection('Tool Output', lines.join('\n'), outputFormat);
708
- };
709
-
710
- const getTitle = (source: ClaudeSource, state: ConvertState, sessionMeta: ClaudeSessionMeta): string => {
711
- if (source.metadata?.title) {
712
- return cleanInlineTitle(source.metadata.title);
713
- }
714
-
715
- if (state.firstUserText) {
716
- return cleanInlineTitle(state.firstUserText);
717
- }
718
-
719
- return source.metadata?.cliSessionId ?? sessionMeta.sessionId ?? path.basename(source.jsonlPath, '.jsonl');
720
- };
721
-
722
- const buildMetadataEntries = (
723
- source: ClaudeSource,
724
- outputPath: string,
725
- sessionMeta: ClaudeSessionMeta,
726
- ): MetadataEntry[] => {
727
- return [
728
- { key: 'exported_from', value: 'claude_code_session_export_jsonl' },
729
- ...buildClaudeSourceMetadataEntries(source, outputPath),
730
- ...buildClaudeTimelineMetadataEntries(source, sessionMeta),
731
- ...buildClaudePullRequestMetadataEntries(source),
732
- ];
733
- };
734
-
735
- const buildClaudeSourceMetadataEntries = (source: ClaudeSource, outputPath: string): MetadataEntry[] => {
736
- return [
737
- {
738
- key: 'session_id',
739
- value: source.metadata?.cliSessionId ?? source.metadata?.sessionId ?? null,
740
- },
741
- { key: 'title', value: source.metadata?.title ?? null },
742
- { key: 'source_transcript_path', value: source.jsonlPath },
743
- { key: 'source_metadata_path', value: source.metadataPath },
744
- { key: 'output_path', value: outputPath },
745
- ];
746
- };
747
-
748
- const buildClaudeTimelineMetadataEntries = (source: ClaudeSource, sessionMeta: ClaudeSessionMeta): MetadataEntry[] => {
749
- return [
750
- {
751
- key: 'cwd',
752
- value: source.metadata?.cwd ?? source.metadata?.originCwd ?? sessionMeta.cwd ?? null,
753
- },
754
- { key: 'entrypoint', value: sessionMeta.entrypoint ?? null },
755
- { key: 'model', value: source.metadata?.model ?? sessionMeta.model ?? null },
756
- { key: 'effort', value: source.metadata?.effort ?? null },
757
- { key: 'permission_mode', value: source.metadata?.permissionMode ?? null },
758
- { key: 'is_archived', value: source.metadata?.isArchived ?? null },
759
- { key: 'completed_turns', value: source.metadata?.completedTurns ?? null },
760
- { key: 'created_at_unix_ms', value: source.metadata?.createdAt ?? null },
761
- { key: 'created_at_iso', value: formatUnixMillis(source.metadata?.createdAt ?? null) },
762
- {
763
- key: 'last_activity_at_unix_ms',
764
- value: source.metadata?.lastActivityAt ?? null,
765
- },
766
- {
767
- key: 'last_activity_at_iso',
768
- value: formatUnixMillis(source.metadata?.lastActivityAt ?? null),
769
- },
770
- { key: 'first_event_at_iso', value: sessionMeta.firstTimestamp ?? null },
771
- { key: 'last_event_at_iso', value: sessionMeta.lastTimestamp ?? null },
772
- { key: 'version', value: sessionMeta.version ?? null },
773
- { key: 'git_branch', value: sessionMeta.gitBranch ?? null },
774
- ];
775
- };
776
-
777
- const buildClaudePullRequestMetadataEntries = (source: ClaudeSource): MetadataEntry[] => {
778
- return [
779
- { key: 'pr_number', value: source.metadata?.prNumber ?? null },
780
- { key: 'pr_url', value: source.metadata?.prUrl ?? null },
781
- { key: 'pr_repository', value: source.metadata?.prRepository ?? null },
782
- { key: 'pr_state', value: source.metadata?.prState ?? null },
783
- ];
784
- };
785
-
786
- const formatUnixMillis = (value: number | null): string | null => {
787
- if (value === null || value === undefined) {
788
- return null;
789
- }
790
-
791
- return new Date(value).toISOString();
792
- };
793
-
794
- const extractClaudeText = (content: JsonValue): string => {
795
- if (typeof content === 'string') {
796
- return content;
797
- }
798
-
799
- if (Array.isArray(content)) {
800
- return content
801
- .map((item) => extractClaudeContentPart(item))
802
- .filter((part) => part.length > 0)
803
- .join('\n\n');
804
- }
805
-
806
- const object = asObject(content);
807
- if (!object) {
808
- return '';
809
- }
810
-
811
- const type = asString(object.type);
812
- const text = asString(object.text);
813
-
814
- if ((type === 'text' || type === 'input_text' || type === 'output_text') && text) {
815
- return text;
816
- }
817
-
818
- return text ?? '';
819
- };
820
-
821
- const extractClaudeContentPart = (value: JsonValue): string => {
822
- if (typeof value === 'string') {
823
- return value;
824
- }
825
-
826
- const object = asObject(value);
827
- if (!object) {
828
- return '';
829
- }
830
-
831
- const type = asString(object.type);
832
- const text = asString(object.text);
833
-
834
- if ((type === 'text' || type === 'input_text' || type === 'output_text') && text) {
835
- return text;
836
- }
837
-
838
- return text ?? '';
839
- };
840
-
841
- const fileExists = async (targetPath: string): Promise<boolean> => {
842
- try {
843
- await access(targetPath);
844
- return true;
845
- } catch {
846
- return false;
847
- }
848
- };
849
-
850
- const requireValue = (value: string | undefined, flag: string): string => {
851
- if (!value || (value.startsWith('-') && value !== '-')) {
852
- throw new CliUsageError(`Missing value for ${flag}`);
853
- }
854
-
855
- return value;
856
- };
857
-
858
- const parseExportFormat = (value: string): ExportFormat => {
859
- if (value === 'md' || value === 'txt') {
860
- return value;
861
- }
862
-
863
- throw new CliUsageError(`Unsupported output format: ${value}`);
864
- };