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.
- package/AGENTS.md +114 -205
- package/README.md +89 -269
- package/apps/ui/AGENTS.md +17 -7
- package/apps/ui/README.md +34 -8
- package/apps/ui/components.json +21 -0
- package/apps/ui/package.json +65 -0
- package/apps/ui/src/components/antigravity-conversations-table.tsx +206 -0
- package/apps/ui/src/components/antigravity-keychain-panel.tsx +76 -0
- package/apps/ui/src/components/antigravity-workspaces-table.tsx +63 -0
- package/apps/ui/src/components/app-shell.tsx +124 -0
- package/apps/ui/src/components/breadcrumbs.tsx +53 -0
- package/apps/ui/src/components/claude-code-sessions-table.tsx +114 -0
- package/apps/ui/src/components/claude-code-workspaces-table.tsx +55 -0
- package/apps/ui/src/components/cursor-threads-table.tsx +189 -0
- package/apps/ui/src/components/cursor-workspaces-table.tsx +140 -0
- package/apps/ui/src/components/data-table.tsx +241 -0
- package/apps/ui/src/components/delete-confirm-dialog.tsx +88 -0
- package/apps/ui/src/components/export-dialog.tsx +184 -0
- package/apps/ui/src/components/json-panel.tsx +17 -0
- package/apps/ui/src/components/kiro-sessions-table.tsx +112 -0
- package/apps/ui/src/components/kiro-workspaces-table.tsx +53 -0
- package/apps/ui/src/components/list-search-input.tsx +18 -0
- package/apps/ui/src/components/loading-panel.tsx +23 -0
- package/apps/ui/src/components/metadata-section.tsx +31 -0
- package/apps/ui/src/components/metric-card.tsx +19 -0
- package/apps/ui/src/components/opencode-sessions-table.tsx +128 -0
- package/apps/ui/src/components/opencode-workspaces-table.tsx +57 -0
- package/apps/ui/src/components/page-header.tsx +33 -0
- package/apps/ui/src/components/projects-loading-state.tsx +74 -0
- package/apps/ui/src/components/projects-table.tsx +108 -0
- package/apps/ui/src/components/qoder-sessions-table.tsx +112 -0
- package/apps/ui/src/components/qoder-workspaces-table.tsx +53 -0
- package/apps/ui/src/components/recent-threads-list.tsx +52 -0
- package/apps/ui/src/components/reload-error-panel.tsx +20 -0
- package/apps/ui/src/components/text-document-panel.tsx +19 -0
- package/apps/ui/src/components/theme-toggle.tsx +48 -0
- package/apps/ui/src/components/threads-table.tsx +202 -0
- package/apps/ui/src/components/transcript-view.tsx +552 -0
- package/apps/ui/src/components/ui/alert-dialog.tsx +160 -0
- package/apps/ui/src/components/ui/badge.tsx +45 -0
- package/apps/ui/src/components/ui/button.tsx +62 -0
- package/apps/ui/src/components/ui/checkbox.tsx +29 -0
- package/apps/ui/src/components/ui/dialog.tsx +137 -0
- package/apps/ui/src/components/ui/dropdown-menu.tsx +217 -0
- package/apps/ui/src/components/ui/input.tsx +21 -0
- package/apps/ui/src/components/ui/scroll-area.tsx +46 -0
- package/apps/ui/src/components/ui/select.tsx +163 -0
- package/apps/ui/src/components/ui/separator.tsx +28 -0
- package/apps/ui/src/components/ui/sheet.tsx +107 -0
- package/apps/ui/src/components/ui/skeleton.tsx +7 -0
- package/apps/ui/src/components/ui/table.tsx +76 -0
- package/apps/ui/src/components/ui/tabs.tsx +71 -0
- package/apps/ui/src/components/ui/tooltip.tsx +44 -0
- package/apps/ui/src/integrations/tanstack-query/devtools.tsx +6 -0
- package/apps/ui/src/integrations/tanstack-query/root-provider.tsx +10 -0
- package/apps/ui/src/lib/antigravity-conversation-state.ts +28 -0
- package/apps/ui/src/lib/antigravity-queries.ts +33 -0
- package/apps/ui/src/lib/antigravity-server.ts +128 -0
- package/apps/ui/src/lib/antigravity-transcript-events.ts +335 -0
- package/apps/ui/src/lib/claude-code-queries.ts +26 -0
- package/apps/ui/src/lib/claude-code-server.ts +75 -0
- package/apps/ui/src/lib/claude-code-transcript-events.ts +154 -0
- package/apps/ui/src/lib/codex-queries.ts +66 -0
- package/apps/ui/src/lib/codex-server.ts +209 -0
- package/apps/ui/src/lib/cursor-queries.ts +37 -0
- package/apps/ui/src/lib/cursor-server.ts +272 -0
- package/apps/ui/src/lib/cursor-transcript-events.ts +229 -0
- package/apps/ui/src/lib/download.ts +166 -0
- package/apps/ui/src/lib/formatters.ts +149 -0
- package/apps/ui/src/lib/kiro-queries.ts +22 -0
- package/apps/ui/src/lib/kiro-server.ts +73 -0
- package/apps/ui/src/lib/kiro-transcript-events.ts +113 -0
- package/apps/ui/src/lib/opencode-queries.ts +37 -0
- package/apps/ui/src/lib/opencode-server.ts +73 -0
- package/apps/ui/src/lib/opencode-transcript-events.ts +221 -0
- package/apps/ui/src/lib/package-metadata.ts +16 -0
- package/apps/ui/src/lib/path-utils.ts +13 -0
- package/apps/ui/src/lib/qoder-queries.ts +22 -0
- package/apps/ui/src/lib/qoder-server.ts +79 -0
- package/apps/ui/src/lib/qoder-transcript-events.ts +139 -0
- package/apps/ui/src/lib/route-search.ts +68 -0
- package/apps/ui/src/lib/settings-store.tsx +59 -0
- package/apps/ui/src/lib/source-session-export-server.ts +56 -0
- package/apps/ui/src/lib/text-filter.ts +22 -0
- package/apps/ui/src/lib/thread-id.ts +3 -0
- package/apps/ui/src/lib/thread-transcript-stats.ts +57 -0
- package/apps/ui/src/lib/utils.ts +7 -0
- package/apps/ui/src/routeTree.gen.ts +730 -0
- package/apps/ui/src/router.tsx +20 -0
- package/apps/ui/src/routes/$threadId.tsx +22 -0
- package/apps/ui/src/routes/__root.tsx +127 -0
- package/apps/ui/src/routes/analytics.tsx +143 -0
- package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +438 -0
- package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +127 -0
- package/apps/ui/src/routes/antigravity.index.tsx +51 -0
- package/apps/ui/src/routes/api.v1.conversation-query.ts +12 -0
- package/apps/ui/src/routes/api.v1.conversations.$source.$id.export.ts +12 -0
- package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +12 -0
- package/apps/ui/src/routes/api.v1.conversations.ts +12 -0
- package/apps/ui/src/routes/api.v1.resolve.ts +12 -0
- package/apps/ui/src/routes/api.v1.sources.ts +12 -0
- package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +342 -0
- package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +135 -0
- package/apps/ui/src/routes/claude-code.index.tsx +48 -0
- package/apps/ui/src/routes/codex.$project.tsx +390 -0
- package/apps/ui/src/routes/codex.index.tsx +116 -0
- package/apps/ui/src/routes/cursor-threads.$composerId.tsx +435 -0
- package/apps/ui/src/routes/cursor.$workspaceKey.tsx +416 -0
- package/apps/ui/src/routes/cursor.index.tsx +120 -0
- package/apps/ui/src/routes/index.tsx +124 -0
- package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +345 -0
- package/apps/ui/src/routes/kiro.$workspaceKey.tsx +136 -0
- package/apps/ui/src/routes/kiro.index.tsx +48 -0
- package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +334 -0
- package/apps/ui/src/routes/opencode.$workspaceKey.tsx +135 -0
- package/apps/ui/src/routes/opencode.index.tsx +48 -0
- package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +341 -0
- package/apps/ui/src/routes/qoder.$workspaceKey.tsx +139 -0
- package/apps/ui/src/routes/qoder.index.tsx +48 -0
- package/apps/ui/src/routes/settings.tsx +91 -0
- package/apps/ui/src/routes/threads.$threadId.tsx +619 -0
- package/apps/ui/src/styles.css +122 -0
- package/apps/ui/tsconfig.json +29 -0
- package/apps/ui/vite.config.ts +84 -0
- package/bin/spiracha.ts +32 -0
- package/package.json +46 -73
- package/src/client.ts +290 -0
- package/src/lib/antigravity-db.ts +213 -19
- package/src/lib/antigravity-exporter-types.ts +1 -0
- package/src/lib/codex-analytics.ts +1 -1
- package/src/lib/codex-browser-db.ts +410 -74
- package/src/lib/codex-browser-export.ts +6 -14
- package/src/lib/codex-browser-types.ts +1 -1
- package/src/lib/{codex-exporter-types.ts → codex-thread-types.ts} +2 -30
- package/src/lib/{codex-exporter-transcript.ts → codex-transcript-renderer.ts} +64 -28
- package/src/lib/conversation-api.ts +792 -0
- package/src/lib/conversation-data/adapter-helpers.ts +110 -0
- package/src/lib/conversation-data/antigravity-adapter.ts +148 -0
- package/src/lib/conversation-data/claude-code-adapter.ts +175 -0
- package/src/lib/conversation-data/codex-adapter.ts +245 -0
- package/src/lib/conversation-data/cursor-adapter.ts +171 -0
- package/src/lib/conversation-data/index.ts +311 -0
- package/src/lib/conversation-data/kiro-adapter.ts +140 -0
- package/src/lib/conversation-data/message-selector.ts +37 -0
- package/src/lib/conversation-data/opencode-adapter.ts +180 -0
- package/src/lib/conversation-data/path-match.ts +79 -0
- package/src/lib/conversation-data/qoder-adapter.ts +230 -0
- package/src/lib/conversation-data/types.ts +116 -0
- package/src/lib/cursor-db.ts +67 -21
- package/src/lib/cursor-exporter-types.ts +0 -19
- package/src/lib/qoder-acp-client.ts +268 -0
- package/src/lib/qoder-db.ts +1601 -0
- package/src/lib/qoder-exporter-types.ts +114 -0
- package/src/lib/qoder-transcript-phase.ts +41 -0
- package/src/lib/qoder-transcript.ts +112 -0
- package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +0 -1
- package/apps/ui/dist/client/assets/analytics-DOy1b6Sh.js +0 -1
- package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-DqySVO2K.js +0 -7
- package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-KAcXtNxI.js +0 -1
- package/apps/ui/dist/client/assets/antigravity-keychain-panel-B77qJz6f.js +0 -1
- package/apps/ui/dist/client/assets/antigravity._workspaceKey-B3NM6gRH.js +0 -1
- package/apps/ui/dist/client/assets/antigravity._workspaceKey-ByitGWki.js +0 -1
- package/apps/ui/dist/client/assets/antigravity.index-DP9JC2P9.js +0 -1
- package/apps/ui/dist/client/assets/antigravity.index-DgW25FEV.js +0 -1
- package/apps/ui/dist/client/assets/badge-C3i4OKs8.js +0 -1
- package/apps/ui/dist/client/assets/checkbox-CdHitXWQ.js +0 -1
- package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-8pQ55ci2.js +0 -1
- package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-DVz5UmtU.js +0 -1
- package/apps/ui/dist/client/assets/claude-code._workspaceKey-BBKskSum.js +0 -1
- package/apps/ui/dist/client/assets/claude-code._workspaceKey-OkikMUFs.js +0 -1
- package/apps/ui/dist/client/assets/claude-code.index-Cwu76dbb.js +0 -1
- package/apps/ui/dist/client/assets/claude-code.index-D6eMd08t.js +0 -1
- package/apps/ui/dist/client/assets/createServerFn-B-KkwmHU.js +0 -3
- package/apps/ui/dist/client/assets/cursor-threads._composerId-CmBFclK8.js +0 -1
- package/apps/ui/dist/client/assets/cursor-threads._composerId-hBWlP1D-.js +0 -1
- package/apps/ui/dist/client/assets/cursor._workspaceKey-BFPkIRi-.js +0 -1
- package/apps/ui/dist/client/assets/cursor._workspaceKey-CaAZjGmm.js +0 -1
- package/apps/ui/dist/client/assets/cursor.index-8y4o20kb.js +0 -2
- package/apps/ui/dist/client/assets/cursor.index-CrnMwDCi.js +0 -1
- package/apps/ui/dist/client/assets/data-table-Br78_dk3.js +0 -4
- package/apps/ui/dist/client/assets/delete-confirm-dialog-Bxs07u-j.js +0 -7
- package/apps/ui/dist/client/assets/dist-B9pyYCVU.js +0 -1
- package/apps/ui/dist/client/assets/dist-BrJhN2A0.js +0 -5
- package/apps/ui/dist/client/assets/dist-Cmd3AIfD.js +0 -1
- package/apps/ui/dist/client/assets/dist-DvMS2965.js +0 -1
- package/apps/ui/dist/client/assets/download-Bf0QJKD3.js +0 -1
- package/apps/ui/dist/client/assets/dropdown-menu-D5cvPaZt.js +0 -1
- package/apps/ui/dist/client/assets/es2015-ad6040dw.js +0 -41
- package/apps/ui/dist/client/assets/export-dialog-Dr8d2MqD.js +0 -1
- package/apps/ui/dist/client/assets/formatters-BtqyrX_c.js +0 -1
- package/apps/ui/dist/client/assets/index-C-STgIH4.js +0 -166
- package/apps/ui/dist/client/assets/jsx-runtime-DGeXAQPT.js +0 -1
- package/apps/ui/dist/client/assets/kiro-sessions._sessionId-CKgfJ7GR.js +0 -1
- package/apps/ui/dist/client/assets/kiro-sessions._sessionId-zvIJHtQF.js +0 -1
- package/apps/ui/dist/client/assets/kiro._workspaceKey-DhVuJuZB.js +0 -1
- package/apps/ui/dist/client/assets/kiro._workspaceKey-QArsjkTY.js +0 -1
- package/apps/ui/dist/client/assets/kiro.index-C-fr4m7i.js +0 -1
- package/apps/ui/dist/client/assets/kiro.index-OYgAdtZd.js +0 -1
- package/apps/ui/dist/client/assets/metric-card-Dplm0ZiM.js +0 -1
- package/apps/ui/dist/client/assets/opencode-sessions._sessionId-DLjiTst-.js +0 -1
- package/apps/ui/dist/client/assets/opencode-sessions._sessionId-biBwrRbt.js +0 -8
- package/apps/ui/dist/client/assets/opencode._workspaceKey-C7OIzMOJ.js +0 -1
- package/apps/ui/dist/client/assets/opencode._workspaceKey-sBakX0oI.js +0 -1
- package/apps/ui/dist/client/assets/opencode.index-Bl_kNs9N.js +0 -1
- package/apps/ui/dist/client/assets/opencode.index-CN53bVmb.js +0 -1
- package/apps/ui/dist/client/assets/page-header-Cwa3p6Tl.js +0 -1
- package/apps/ui/dist/client/assets/preload-helper-B8fFrdxC.js +0 -1
- package/apps/ui/dist/client/assets/projects._project-D8WloxQN.js +0 -1
- package/apps/ui/dist/client/assets/projects._project-DSDwH4NF.js +0 -1
- package/apps/ui/dist/client/assets/projects.index-5xRtuJdX.js +0 -3
- package/apps/ui/dist/client/assets/projects.index-DEfhWqa8.js +0 -1
- package/apps/ui/dist/client/assets/react-dom-DL96Jor4.js +0 -1
- package/apps/ui/dist/client/assets/refresh-ccw-BgKjOiA6.js +0 -1
- package/apps/ui/dist/client/assets/reload-error-panel-AHqu0akK.js +0 -1
- package/apps/ui/dist/client/assets/routes-DnzF_9CX.js +0 -1
- package/apps/ui/dist/client/assets/scroll-text-fM0sMOB3.js +0 -1
- package/apps/ui/dist/client/assets/select-CYF6pF37.js +0 -1
- package/apps/ui/dist/client/assets/settings-Dx70jgP_.js +0 -1
- package/apps/ui/dist/client/assets/sqlite-error-B6uZjUe8.js +0 -1
- package/apps/ui/dist/client/assets/styles-B7Zi9EFA.css +0 -1
- package/apps/ui/dist/client/assets/tabs-CmuhkT-c.js +0 -7
- package/apps/ui/dist/client/assets/text-filter-DVAZySUS.js +0 -2
- package/apps/ui/dist/client/assets/thread-transcript-stats-BUNz6u7F.js +0 -1
- package/apps/ui/dist/client/assets/threads._threadId-BB9tTsV4.js +0 -1
- package/apps/ui/dist/client/assets/threads._threadId-BMRSFow3.js +0 -1
- package/apps/ui/dist/client/assets/useMutation-BSFult2i.js +0 -1
- package/apps/ui/dist/client/assets/useQuery-CjINKZf1.js +0 -1
- package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CQ8Jjs3B.js +0 -387
- package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +0 -6
- package/apps/ui/dist/server/assets/analytics-CYP_LT5Y.js +0 -16
- package/apps/ui/dist/server/assets/analytics-CtpOMVMO.js +0 -146
- package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +0 -16
- package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BKOyL2T6.js +0 -613
- package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +0 -11
- package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-eS87Dx7g.js +0 -20
- package/apps/ui/dist/server/assets/antigravity-db-Bh8_U9uw.js +0 -580
- package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +0 -126
- package/apps/ui/dist/server/assets/antigravity-keychain-panel-CC7FLmAK.js +0 -55
- package/apps/ui/dist/server/assets/antigravity-queries-CGrJO9Vr.js +0 -37
- package/apps/ui/dist/server/assets/antigravity-server-CHRjVFqN.js +0 -114
- package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +0 -11
- package/apps/ui/dist/server/assets/antigravity._workspaceKey-B0QeYUOh.js +0 -28
- package/apps/ui/dist/server/assets/antigravity._workspaceKey-C3kP-qyN.js +0 -210
- package/apps/ui/dist/server/assets/antigravity.index-CPCYkqCi.js +0 -104
- package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +0 -11
- package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +0 -26
- package/apps/ui/dist/server/assets/button-CmTDnzOn.js +0 -46
- package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +0 -19
- package/apps/ui/dist/server/assets/claude-code-db-Ik3VStKZ.js +0 -361
- package/apps/ui/dist/server/assets/claude-code-queries-Cgzi4K-e.js +0 -37
- package/apps/ui/dist/server/assets/claude-code-server-PfraClXS.js +0 -72
- package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-C55oe6zj.js +0 -18
- package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-D1RYYi3j.js +0 -473
- package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-DSvPLEUL.js +0 -11
- package/apps/ui/dist/server/assets/claude-code-transcript-C-bxh3cS.js +0 -139
- package/apps/ui/dist/server/assets/claude-code-transcript-phase-DmUMc8VU.js +0 -10
- package/apps/ui/dist/server/assets/claude-code._workspaceKey-B5Xg_-tE.js +0 -28
- package/apps/ui/dist/server/assets/claude-code._workspaceKey-BPlzyXPa.js +0 -11
- package/apps/ui/dist/server/assets/claude-code._workspaceKey-DqDve2wl.js +0 -191
- package/apps/ui/dist/server/assets/claude-code.index-B7yYR7dD.js +0 -92
- package/apps/ui/dist/server/assets/claude-code.index-BUHThG1W.js +0 -11
- package/apps/ui/dist/server/assets/codex-queries-CtgeZ7VL.js +0 -99
- package/apps/ui/dist/server/assets/codex-server-CGXU4H8-.js +0 -2294
- package/apps/ui/dist/server/assets/concurrency-VXtYvlGh.js +0 -18
- package/apps/ui/dist/server/assets/createServerRpc-CF_DEwnm.js +0 -12
- package/apps/ui/dist/server/assets/createSsrRpc-C754NPki.js +0 -16
- package/apps/ui/dist/server/assets/cursor-db-CZnYy7aT.js +0 -830
- package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +0 -34
- package/apps/ui/dist/server/assets/cursor-queries-NCIM0Nat.js +0 -67
- package/apps/ui/dist/server/assets/cursor-recovery-CXpO8KcD.js +0 -361
- package/apps/ui/dist/server/assets/cursor-server-DNu52A3K.js +0 -213
- package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +0 -11
- package/apps/ui/dist/server/assets/cursor-threads._composerId-Ckn6ItHI.js +0 -582
- package/apps/ui/dist/server/assets/cursor-threads._composerId-p9-ARAzc.js +0 -18
- package/apps/ui/dist/server/assets/cursor-transcript-B7tGnqtn.js +0 -125
- package/apps/ui/dist/server/assets/cursor._workspaceKey-CZuohIUL.js +0 -28
- package/apps/ui/dist/server/assets/cursor._workspaceKey-DPp5JSjy.js +0 -401
- package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +0 -11
- package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +0 -11
- package/apps/ui/dist/server/assets/cursor.index-DkWT-mxw.js +0 -189
- package/apps/ui/dist/server/assets/data-table-Cdct823O.js +0 -189
- package/apps/ui/dist/server/assets/delete-confirm-dialog-BcBNCxWB.js +0 -144
- package/apps/ui/dist/server/assets/download-DMmiy1xf.js +0 -92
- package/apps/ui/dist/server/assets/dropdown-menu-Dy_9t6TN.js +0 -36
- package/apps/ui/dist/server/assets/empty-plugin-adapters-B3lHh1La.js +0 -5
- package/apps/ui/dist/server/assets/export-dialog-D88ze9Gy.js +0 -240
- package/apps/ui/dist/server/assets/formatters-FJaGZgJk.js +0 -91
- package/apps/ui/dist/server/assets/kiro-db--fXrED_-.js +0 -552
- package/apps/ui/dist/server/assets/kiro-queries-CzNlM2ok.js +0 -37
- package/apps/ui/dist/server/assets/kiro-server-9WRxg2Au.js +0 -72
- package/apps/ui/dist/server/assets/kiro-sessions._sessionId-CRY2c7YO.js +0 -11
- package/apps/ui/dist/server/assets/kiro-sessions._sessionId-F1UlwxmR.js +0 -449
- package/apps/ui/dist/server/assets/kiro-sessions._sessionId-bvTulT7C.js +0 -18
- package/apps/ui/dist/server/assets/kiro-transcript-DoekQBaH.js +0 -112
- package/apps/ui/dist/server/assets/kiro-transcript-phase-CJG40nQg.js +0 -27
- package/apps/ui/dist/server/assets/kiro._workspaceKey-BDe9sQwo.js +0 -11
- package/apps/ui/dist/server/assets/kiro._workspaceKey-CJsjgNwO.js +0 -28
- package/apps/ui/dist/server/assets/kiro._workspaceKey-D_-4Qb7y.js +0 -193
- package/apps/ui/dist/server/assets/kiro.index-C__-UROk.js +0 -11
- package/apps/ui/dist/server/assets/kiro.index-CmTbqeYj.js +0 -93
- package/apps/ui/dist/server/assets/loading-panel-BGFnWseS.js +0 -27
- package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +0 -23
- package/apps/ui/dist/server/assets/model-label-B1NWGc65.js +0 -13
- package/apps/ui/dist/server/assets/opencode-db-BM7KjOzc.js +0 -397
- package/apps/ui/dist/server/assets/opencode-queries-BeNYXnQv.js +0 -50
- package/apps/ui/dist/server/assets/opencode-server-BpQ_kRze.js +0 -72
- package/apps/ui/dist/server/assets/opencode-sessions._sessionId-CGQ-t0vD.js +0 -518
- package/apps/ui/dist/server/assets/opencode-sessions._sessionId-D8Q7in_Z.js +0 -18
- package/apps/ui/dist/server/assets/opencode-sessions._sessionId-DKOvi0lV.js +0 -11
- package/apps/ui/dist/server/assets/opencode-think-tags-CAoD-EcZ.js +0 -87
- package/apps/ui/dist/server/assets/opencode-transcript-BNTcGNym.js +0 -141
- package/apps/ui/dist/server/assets/opencode-transcript-phase-OqLkiQD0.js +0 -32
- package/apps/ui/dist/server/assets/opencode._workspaceKey-BdqcWHw1.js +0 -11
- package/apps/ui/dist/server/assets/opencode._workspaceKey-CfH96HTT.js +0 -28
- package/apps/ui/dist/server/assets/opencode._workspaceKey-DdbHPDrO.js +0 -207
- package/apps/ui/dist/server/assets/opencode.index-BbVzkJXP.js +0 -11
- package/apps/ui/dist/server/assets/opencode.index-Vh_Gq_1L.js +0 -93
- package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +0 -29
- package/apps/ui/dist/server/assets/path-transforms-DL2IwtYd.js +0 -31
- package/apps/ui/dist/server/assets/projects._project-4io5LO0E.js +0 -20
- package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +0 -12
- package/apps/ui/dist/server/assets/projects._project-D6ZoGhJ8.js +0 -395
- package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +0 -12
- package/apps/ui/dist/server/assets/projects.index-BkLiF2FF.js +0 -182
- package/apps/ui/dist/server/assets/projects.index-DesYXwfi.js +0 -14
- package/apps/ui/dist/server/assets/reload-error-panel-BJMxY3U1.js +0 -25
- package/apps/ui/dist/server/assets/route-search-ts4W9MJ9.js +0 -38
- package/apps/ui/dist/server/assets/router-Sac2DGk6.js +0 -518
- package/apps/ui/dist/server/assets/routes-Bsact1uB.js +0 -184
- package/apps/ui/dist/server/assets/routes-BzkJgq4W.js +0 -34
- package/apps/ui/dist/server/assets/select-GW76p-ld.js +0 -76
- package/apps/ui/dist/server/assets/settings-OayxIYQQ.js +0 -100
- package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +0 -52
- package/apps/ui/dist/server/assets/shared-DyhChtHf.js +0 -137
- package/apps/ui/dist/server/assets/source-session-export-server-DNutCawb.js +0 -38
- package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +0 -13
- package/apps/ui/dist/server/assets/start-B_HFwkkk.js +0 -4
- package/apps/ui/dist/server/assets/tabs-DkaChNVg.js +0 -501
- package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +0 -36
- package/apps/ui/dist/server/assets/thread-transcript-stats-Dh34mt2u.js +0 -45
- package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +0 -26
- package/apps/ui/dist/server/assets/threads._threadId-BeXEc4Lo.js +0 -648
- package/apps/ui/dist/server/assets/threads._threadId-Ci0S4mKU.js +0 -18
- package/apps/ui/dist/server/assets/ui-export-files-BHLX9bhN.js +0 -83
- package/apps/ui/dist/server/assets/utils-C_uf36nf.js +0 -8
- package/apps/ui/dist/server/server.js +0 -5895
- package/bin/codex-chats-claude.js +0 -5
- package/bin/codex-chats.js +0 -5
- package/bin/spiracha.js +0 -5
- package/src/export-chats.ts +0 -120
- package/src/export-claude.ts +0 -36
- package/src/export-cursor.ts +0 -244
- package/src/lib/claude-exporter.ts +0 -864
- package/src/lib/codex-exporter-cli.ts +0 -277
- package/src/lib/codex-exporter-db.ts +0 -319
- package/src/lib/codex-exporter.ts +0 -115
- package/src/lib/cursor-exporter.ts +0 -266
- package/src/lib/interactive-cli.ts +0 -433
- package/src/lib/native-open.ts +0 -54
- package/src/mcp-server.ts +0 -137
- package/src/spiracha.ts +0 -116
- package/src/ui-cli.ts +0 -310
- /package/apps/ui/{dist/client → public}/icon.svg +0 -0
- /package/apps/ui/{dist/client → public}/manifest.json +0 -0
- /package/apps/ui/{dist/client → public}/robots.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { constants, Database } from 'bun:sqlite';
|
|
2
|
-
import { closeSync, openSync, readdirSync, readSync, statSync } from 'node:fs';
|
|
3
|
-
import { rm } from 'node:fs/promises';
|
|
2
|
+
import { closeSync, openSync, readdirSync, readSync, type Stats, statSync } from 'node:fs';
|
|
3
|
+
import { rename, rm } from 'node:fs/promises';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { StringDecoder } from 'node:string_decoder';
|
|
@@ -14,9 +14,9 @@ import type {
|
|
|
14
14
|
ThreadBrowseData,
|
|
15
15
|
ThreadListEntry,
|
|
16
16
|
} from './codex-browser-types';
|
|
17
|
-
import type { ThreadRelations, ThreadRow } from './codex-exporter-types';
|
|
18
|
-
import { DEFAULT_CODEX_DIR, DEFAULT_DB_PATH } from './codex-exporter-types';
|
|
19
17
|
import { getCachedParsedCodexTranscript, getThreadRolloutLoadState } from './codex-thread-cache';
|
|
18
|
+
import type { ThreadRelations, ThreadRow } from './codex-thread-types';
|
|
19
|
+
import { DEFAULT_CODEX_DIR, DEFAULT_DB_PATH } from './codex-thread-types';
|
|
20
20
|
import { mapWithConcurrency } from './concurrency';
|
|
21
21
|
import { cleanInlineTitle, getPortablePathBasename } from './shared';
|
|
22
22
|
import { runWithSqliteRetry } from './sqlite-retry';
|
|
@@ -36,7 +36,12 @@ const THREAD_LIST_IO_CONCURRENCY = 8;
|
|
|
36
36
|
const CODEX_READONLY_DB_OPEN_FLAGS = constants.SQLITE_OPEN_READONLY | constants.SQLITE_OPEN_URI;
|
|
37
37
|
const JSONL_READ_CHUNK_BYTES = 64 * 1024;
|
|
38
38
|
const SESSION_META_READ_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
39
|
+
const FALLBACK_STATS_HEAD_READ_LIMIT_BYTES = 512 * 1024;
|
|
40
|
+
const FALLBACK_STATS_TAIL_READ_LIMIT_BYTES = 512 * 1024;
|
|
41
|
+
const FALLBACK_STATS_RECORD_PATTERN = /"type"\s*:\s*"(?:agent_message|message|token_count|turn_context)"/u;
|
|
39
42
|
const THREAD_ID_PATTERN = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/iu;
|
|
43
|
+
const sessionFileIndexCache = new Map<string, Map<string, string>>();
|
|
44
|
+
let sessionIndexMutationQueue = Promise.resolve();
|
|
40
45
|
|
|
41
46
|
type SessionIndexEntry = {
|
|
42
47
|
id: string;
|
|
@@ -68,10 +73,16 @@ type FallbackRolloutStats = {
|
|
|
68
73
|
tokensUsed: number;
|
|
69
74
|
};
|
|
70
75
|
|
|
76
|
+
type FallbackThreadRowOptions = ReadFallbackThreadRowsOptions & {
|
|
77
|
+
projectName?: string | null;
|
|
78
|
+
};
|
|
79
|
+
|
|
71
80
|
const isSqliteCantOpenError = (error: unknown) => {
|
|
72
81
|
return (error as { code?: unknown }).code === 'SQLITE_CANTOPEN';
|
|
73
82
|
};
|
|
74
83
|
|
|
84
|
+
const uniqueValues = <T>(values: T[]) => [...new Set(values)];
|
|
85
|
+
|
|
75
86
|
const chunkValues = <T>(values: T[], chunkSize: number) => {
|
|
76
87
|
const chunks: T[][] = [];
|
|
77
88
|
|
|
@@ -329,6 +340,31 @@ const collectSessionFilesByThreadId = (sessionsDir: string): Map<string, string>
|
|
|
329
340
|
return sessionFiles;
|
|
330
341
|
};
|
|
331
342
|
|
|
343
|
+
const findSessionFileByThreadId = (sessionsDir: string, threadId: string): string | null => {
|
|
344
|
+
const lookup = (sessionFilesByThreadId: Map<string, string>) => {
|
|
345
|
+
const sessionFile = sessionFilesByThreadId.get(threadId);
|
|
346
|
+
if (!sessionFile) {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
try {
|
|
351
|
+
return statSync(sessionFile).isFile() ? sessionFile : null;
|
|
352
|
+
} catch {
|
|
353
|
+
return null;
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const cached = sessionFileIndexCache.get(sessionsDir);
|
|
358
|
+
const cachedMatch = cached ? lookup(cached) : null;
|
|
359
|
+
if (cachedMatch) {
|
|
360
|
+
return cachedMatch;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const refreshed = collectSessionFilesByThreadId(sessionsDir);
|
|
364
|
+
sessionFileIndexCache.set(sessionsDir, refreshed);
|
|
365
|
+
return lookup(refreshed);
|
|
366
|
+
};
|
|
367
|
+
|
|
332
368
|
const readSessionMetaLine = (sessionFile: string): string | null => {
|
|
333
369
|
let descriptor: number | null = null;
|
|
334
370
|
try {
|
|
@@ -402,40 +438,183 @@ const isFallbackSubagent = (sessionMeta: FallbackSessionMeta) => {
|
|
|
402
438
|
);
|
|
403
439
|
};
|
|
404
440
|
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
441
|
+
const updateFallbackRolloutStatsFromRecord = (record: Record<string, unknown>, stats: FallbackRolloutStats): void => {
|
|
442
|
+
const payload = objectOrNull(record.payload);
|
|
443
|
+
if (!payload) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
408
446
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
447
|
+
if (record.type === 'turn_context') {
|
|
448
|
+
stats.model = stringOrNull(payload.model) ?? stats.model;
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const payloadType = stringOrNull(payload.type);
|
|
453
|
+
if (payloadType === 'message' || payloadType === 'agent_message') {
|
|
454
|
+
stats.model = stringOrNull(payload.model) ?? stats.model;
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (payloadType !== 'token_count') {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const info = objectOrNull(payload.info);
|
|
463
|
+
const totalTokenUsage = objectOrNull(info?.total_token_usage);
|
|
464
|
+
stats.tokensUsed = numberOrNull(totalTokenUsage?.total_tokens) ?? stats.tokensUsed;
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const readFallbackStatsLine = (line: string, stats: FallbackRolloutStats) => {
|
|
468
|
+
const trimmed = line.trim();
|
|
469
|
+
if (!trimmed || !FALLBACK_STATS_RECORD_PATTERN.test(trimmed)) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const record = parseJsonlObject<Record<string, unknown>>(trimmed);
|
|
474
|
+
if (record) {
|
|
475
|
+
updateFallbackRolloutStatsFromRecord(record, stats);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const emitCompleteFallbackStatsLines = (text: string, stats: FallbackRolloutStats): string => {
|
|
480
|
+
const lines = text.split(/\r?\n/u);
|
|
481
|
+
const pending = lines.pop() ?? '';
|
|
482
|
+
for (const line of lines) {
|
|
483
|
+
readFallbackStatsLine(line, stats);
|
|
484
|
+
}
|
|
485
|
+
return pending;
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
const readFallbackRolloutStatsHead = (sessionFile: string, stats: FallbackRolloutStats, fileStats: Stats) => {
|
|
489
|
+
let descriptor: number | null = null;
|
|
490
|
+
try {
|
|
491
|
+
if (!fileStats.isFile()) {
|
|
492
|
+
return 0;
|
|
413
493
|
}
|
|
414
494
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
495
|
+
descriptor = openSync(sessionFile, 'r');
|
|
496
|
+
const buffer = Buffer.alloc(JSONL_READ_CHUNK_BYTES);
|
|
497
|
+
const decoder = new StringDecoder('utf8');
|
|
498
|
+
const readLimitBytes = Math.min(fileStats.size, FALLBACK_STATS_HEAD_READ_LIMIT_BYTES);
|
|
499
|
+
let position = 0;
|
|
500
|
+
let pending = '';
|
|
501
|
+
|
|
502
|
+
while (position < readLimitBytes) {
|
|
503
|
+
const bytesRead = readSync(
|
|
504
|
+
descriptor,
|
|
505
|
+
buffer,
|
|
506
|
+
0,
|
|
507
|
+
Math.min(buffer.length, readLimitBytes - position),
|
|
508
|
+
position,
|
|
509
|
+
);
|
|
510
|
+
if (bytesRead === 0) {
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
position += bytesRead;
|
|
515
|
+
pending += decoder.write(buffer.subarray(0, bytesRead));
|
|
516
|
+
pending = emitCompleteFallbackStatsLines(pending, stats);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (position >= fileStats.size) {
|
|
520
|
+
readFallbackStatsLine(pending + decoder.end(), stats);
|
|
521
|
+
return position;
|
|
418
522
|
}
|
|
419
523
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
524
|
+
decoder.end();
|
|
525
|
+
return position;
|
|
526
|
+
} catch {
|
|
527
|
+
return 0;
|
|
528
|
+
} finally {
|
|
529
|
+
if (descriptor !== null) {
|
|
530
|
+
closeSync(descriptor);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
const trimPartialLeadingJsonlLine = (text: string) => {
|
|
536
|
+
if (text.startsWith('\r\n')) {
|
|
537
|
+
return text.slice(2);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (text.startsWith('\n')) {
|
|
541
|
+
return text.slice(1);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
const match = /\r?\n/u.exec(text);
|
|
545
|
+
return match ? text.slice(match.index + match[0].length) : '';
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
const readFallbackRolloutStatsTail = (
|
|
549
|
+
sessionFile: string,
|
|
550
|
+
stats: FallbackRolloutStats,
|
|
551
|
+
fileStats: Stats,
|
|
552
|
+
coveredPrefixBytes: number,
|
|
553
|
+
) => {
|
|
554
|
+
let descriptor: number | null = null;
|
|
555
|
+
try {
|
|
556
|
+
if (!fileStats.isFile() || fileStats.size === 0) {
|
|
423
557
|
return;
|
|
424
558
|
}
|
|
425
559
|
|
|
426
|
-
|
|
560
|
+
const suffixStart = Math.max(coveredPrefixBytes, fileStats.size - FALLBACK_STATS_TAIL_READ_LIMIT_BYTES);
|
|
561
|
+
if (suffixStart >= fileStats.size) {
|
|
427
562
|
return;
|
|
428
563
|
}
|
|
429
564
|
|
|
430
|
-
const
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
565
|
+
const readStart = suffixStart > 0 ? suffixStart - 1 : 0;
|
|
566
|
+
const readLimitBytes = fileStats.size - readStart;
|
|
567
|
+
descriptor = openSync(sessionFile, 'r');
|
|
568
|
+
const buffer = Buffer.alloc(JSONL_READ_CHUNK_BYTES);
|
|
569
|
+
const decoder = new StringDecoder('utf8');
|
|
570
|
+
let position = readStart;
|
|
571
|
+
let remainingBytes = readLimitBytes;
|
|
572
|
+
let text = '';
|
|
434
573
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
574
|
+
while (remainingBytes > 0) {
|
|
575
|
+
const bytesRead = readSync(descriptor, buffer, 0, Math.min(buffer.length, remainingBytes), position);
|
|
576
|
+
if (bytesRead === 0) {
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
position += bytesRead;
|
|
581
|
+
remainingBytes -= bytesRead;
|
|
582
|
+
text += decoder.write(buffer.subarray(0, bytesRead));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
text += decoder.end();
|
|
586
|
+
const completeText = readStart > 0 ? trimPartialLeadingJsonlLine(text) : text;
|
|
587
|
+
for (const line of completeText.split(/\r?\n/u)) {
|
|
588
|
+
readFallbackStatsLine(line, stats);
|
|
589
|
+
}
|
|
590
|
+
} catch {
|
|
591
|
+
return;
|
|
592
|
+
} finally {
|
|
593
|
+
if (descriptor !== null) {
|
|
594
|
+
closeSync(descriptor);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
const readFallbackRolloutStats = (sessionFile: string): FallbackRolloutStats => {
|
|
600
|
+
const stats: FallbackRolloutStats = {
|
|
601
|
+
model: null,
|
|
602
|
+
tokensUsed: 0,
|
|
438
603
|
};
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
const fileStats = statSync(sessionFile);
|
|
607
|
+
if (!fileStats.isFile()) {
|
|
608
|
+
return stats;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const coveredPrefixBytes = readFallbackRolloutStatsHead(sessionFile, stats, fileStats);
|
|
612
|
+
readFallbackRolloutStatsTail(sessionFile, stats, fileStats, coveredPrefixBytes);
|
|
613
|
+
} catch {
|
|
614
|
+
return stats;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
return stats;
|
|
439
618
|
};
|
|
440
619
|
|
|
441
620
|
const buildFallbackThreadRow = (
|
|
@@ -492,6 +671,28 @@ const buildFallbackThreadRow = (
|
|
|
492
671
|
};
|
|
493
672
|
};
|
|
494
673
|
|
|
674
|
+
const readFallbackThreadRow = (
|
|
675
|
+
entry: SessionIndexEntry,
|
|
676
|
+
sessionFile: string,
|
|
677
|
+
options: FallbackThreadRowOptions = {},
|
|
678
|
+
): ThreadRow | null => {
|
|
679
|
+
const sessionMeta = readFallbackSessionMeta(sessionFile);
|
|
680
|
+
if (!sessionMeta) {
|
|
681
|
+
return null;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
if (!options.includeSubagents && isFallbackSubagent(sessionMeta)) {
|
|
685
|
+
return null;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const cwd = stringOrNull(sessionMeta.cwd);
|
|
689
|
+
if (!cwd || (options.projectName && getPortablePathBasename(cwd) !== options.projectName)) {
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return buildFallbackThreadRow(entry, sessionFile, sessionMeta, readFallbackRolloutStats(sessionFile));
|
|
694
|
+
};
|
|
695
|
+
|
|
495
696
|
const readFallbackThreadRows = (
|
|
496
697
|
dbPath: string,
|
|
497
698
|
existingThreadIds: Set<string>,
|
|
@@ -512,22 +713,11 @@ const readFallbackThreadRows = (
|
|
|
512
713
|
continue;
|
|
513
714
|
}
|
|
514
715
|
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
if (!options.includeSubagents && isFallbackSubagent(sessionMeta)) {
|
|
521
|
-
continue;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
const fallbackThread = buildFallbackThreadRow(
|
|
525
|
-
entry,
|
|
526
|
-
sessionFile,
|
|
527
|
-
sessionMeta,
|
|
528
|
-
readFallbackRolloutStats(sessionFile),
|
|
529
|
-
);
|
|
530
|
-
if (!fallbackThread || (projectName && getPortablePathBasename(fallbackThread.cwd) !== projectName)) {
|
|
716
|
+
const fallbackThread = readFallbackThreadRow(entry, sessionFile, {
|
|
717
|
+
...options,
|
|
718
|
+
projectName,
|
|
719
|
+
});
|
|
720
|
+
if (!fallbackThread) {
|
|
531
721
|
continue;
|
|
532
722
|
}
|
|
533
723
|
|
|
@@ -537,6 +727,25 @@ const readFallbackThreadRows = (
|
|
|
537
727
|
return fallbackThreads;
|
|
538
728
|
};
|
|
539
729
|
|
|
730
|
+
const readFallbackThreadRowById = (
|
|
731
|
+
dbPath: string,
|
|
732
|
+
threadId: string,
|
|
733
|
+
options: ReadFallbackThreadRowsOptions = {},
|
|
734
|
+
): ThreadRow | null => {
|
|
735
|
+
const codexDir = resolveCodexDirFromDbPath(dbPath);
|
|
736
|
+
const entry = readSessionIndexEntries(codexDir).find((candidate) => candidate.id === threadId);
|
|
737
|
+
if (!entry) {
|
|
738
|
+
return null;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const sessionFile = findSessionFileByThreadId(path.join(codexDir, 'sessions'), threadId);
|
|
742
|
+
if (!sessionFile) {
|
|
743
|
+
return null;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
return readFallbackThreadRow(entry, sessionFile, options);
|
|
747
|
+
};
|
|
748
|
+
|
|
540
749
|
const mergeFallbackThreadRows = (dbPath: string, threads: ThreadRow[], projectName: string | null = null) => {
|
|
541
750
|
const threadIds = new Set(threads.map((thread) => thread.id));
|
|
542
751
|
return [...threads, ...readFallbackThreadRows(dbPath, threadIds, projectName)].sort((left, right) => {
|
|
@@ -803,6 +1012,132 @@ const deleteThreadSessionFiles = async (sessionFiles: string[]) => {
|
|
|
803
1012
|
return uniqueSessionFiles;
|
|
804
1013
|
};
|
|
805
1014
|
|
|
1015
|
+
const getSessionFilesForThreadIds = (dbPath: string, threadIds: string[]) => {
|
|
1016
|
+
if (threadIds.length === 0) {
|
|
1017
|
+
return [];
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
const codexDir = resolveCodexDirFromDbPath(dbPath);
|
|
1021
|
+
if (threadIds.length === 1) {
|
|
1022
|
+
const sessionFile = findSessionFileByThreadId(path.join(codexDir, 'sessions'), threadIds[0]!);
|
|
1023
|
+
return sessionFile ? [sessionFile] : [];
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
const sessionFilesByThreadId = collectSessionFilesByThreadId(path.join(codexDir, 'sessions'));
|
|
1027
|
+
return threadIds
|
|
1028
|
+
.map((threadId) => sessionFilesByThreadId.get(threadId))
|
|
1029
|
+
.filter((value): value is string => Boolean(value));
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1032
|
+
const filterSessionIndexLines = (lines: string[], threadIds: Set<string>) => {
|
|
1033
|
+
const removedThreadIds: string[] = [];
|
|
1034
|
+
const retainedLines: string[] = [];
|
|
1035
|
+
|
|
1036
|
+
for (const line of lines) {
|
|
1037
|
+
const trimmed = line.trim();
|
|
1038
|
+
if (!trimmed) {
|
|
1039
|
+
continue;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
const entry = parseJsonlObject<SessionIndexEntry>(trimmed);
|
|
1043
|
+
if (entry?.id && threadIds.has(entry.id)) {
|
|
1044
|
+
removedThreadIds.push(entry.id);
|
|
1045
|
+
continue;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
retainedLines.push(trimmed);
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
return { removedThreadIds, retainedLines };
|
|
1052
|
+
};
|
|
1053
|
+
|
|
1054
|
+
const writeSessionIndexLines = async (sessionIndexPath: string, codexDir: string, retainedLines: string[]) => {
|
|
1055
|
+
const tempSessionIndexPath = path.join(
|
|
1056
|
+
codexDir,
|
|
1057
|
+
`.session_index.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`,
|
|
1058
|
+
);
|
|
1059
|
+
try {
|
|
1060
|
+
await Bun.write(tempSessionIndexPath, retainedLines.length > 0 ? `${retainedLines.join('\n')}\n` : '');
|
|
1061
|
+
await rename(tempSessionIndexPath, sessionIndexPath);
|
|
1062
|
+
} catch (error) {
|
|
1063
|
+
await rm(tempSessionIndexPath, { force: true });
|
|
1064
|
+
throw error;
|
|
1065
|
+
}
|
|
1066
|
+
};
|
|
1067
|
+
|
|
1068
|
+
const removeSessionIndexEntries = async (codexDir: string, threadIds: string[]) => {
|
|
1069
|
+
const runMutation = async () => {
|
|
1070
|
+
const uniqueThreadIds = new Set(threadIds);
|
|
1071
|
+
if (uniqueThreadIds.size === 0) {
|
|
1072
|
+
return [];
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
const sessionIndexPath = path.join(codexDir, 'session_index.jsonl');
|
|
1076
|
+
if (!(await Bun.file(sessionIndexPath).exists())) {
|
|
1077
|
+
return [];
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const lines = (await Bun.file(sessionIndexPath).text()).split(/\r?\n/u);
|
|
1081
|
+
const { removedThreadIds, retainedLines } = filterSessionIndexLines(lines, uniqueThreadIds);
|
|
1082
|
+
|
|
1083
|
+
if (removedThreadIds.length === 0) {
|
|
1084
|
+
return [];
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
await writeSessionIndexLines(sessionIndexPath, codexDir, retainedLines);
|
|
1088
|
+
return uniqueValues(removedThreadIds);
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1091
|
+
const mutation = sessionIndexMutationQueue.then(runMutation, runMutation);
|
|
1092
|
+
sessionIndexMutationQueue = mutation.then(
|
|
1093
|
+
() => undefined,
|
|
1094
|
+
() => undefined,
|
|
1095
|
+
);
|
|
1096
|
+
return mutation;
|
|
1097
|
+
};
|
|
1098
|
+
|
|
1099
|
+
const listFallbackThreadIdsForProject = (dbPath: string, existingThreadIds: Set<string>, projectName: string) => {
|
|
1100
|
+
const codexDir = resolveCodexDirFromDbPath(dbPath);
|
|
1101
|
+
const sessionFilesByThreadId = collectSessionFilesByThreadId(path.join(codexDir, 'sessions'));
|
|
1102
|
+
const fallbackThreadIds: string[] = [];
|
|
1103
|
+
|
|
1104
|
+
for (const entry of readSessionIndexEntries(codexDir)) {
|
|
1105
|
+
if (existingThreadIds.has(entry.id) || !sessionFilesByThreadId.has(entry.id)) {
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
const sessionMeta = readFallbackSessionMeta(sessionFilesByThreadId.get(entry.id)!);
|
|
1110
|
+
if (!sessionMeta || isFallbackSubagent(sessionMeta)) {
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
const cwd = stringOrNull(sessionMeta.cwd);
|
|
1115
|
+
if (cwd && getPortablePathBasename(cwd) === projectName) {
|
|
1116
|
+
fallbackThreadIds.push(entry.id);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
return fallbackThreadIds;
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
const deleteSessionIndexEntriesForThreads = async (
|
|
1124
|
+
dbPath: string,
|
|
1125
|
+
threadIds: string[],
|
|
1126
|
+
dbDeletedSessionFiles: string[],
|
|
1127
|
+
deleteSessionFiles: boolean,
|
|
1128
|
+
) => {
|
|
1129
|
+
const codexDir = resolveCodexDirFromDbPath(dbPath);
|
|
1130
|
+
const removedThreadIds = await removeSessionIndexEntries(codexDir, threadIds);
|
|
1131
|
+
const fallbackSessionFiles = deleteSessionFiles ? getSessionFilesForThreadIds(dbPath, removedThreadIds) : [];
|
|
1132
|
+
|
|
1133
|
+
return {
|
|
1134
|
+
deletedSessionFiles: deleteSessionFiles
|
|
1135
|
+
? await deleteThreadSessionFiles([...dbDeletedSessionFiles, ...fallbackSessionFiles])
|
|
1136
|
+
: [],
|
|
1137
|
+
deletedThreadIds: removedThreadIds,
|
|
1138
|
+
};
|
|
1139
|
+
};
|
|
1140
|
+
|
|
806
1141
|
export const listCodexProjects = (dbPath: string): ProjectSummary[] => {
|
|
807
1142
|
return mapProjectSummaries(
|
|
808
1143
|
buildProjectSummaryMap(applyRolloutActivityTimestamps(mergeFallbackThreadRows(dbPath, readAllThreads(dbPath)))),
|
|
@@ -810,6 +1145,7 @@ export const listCodexProjects = (dbPath: string): ProjectSummary[] => {
|
|
|
810
1145
|
};
|
|
811
1146
|
|
|
812
1147
|
type ListProjectThreadsOptions = {
|
|
1148
|
+
includeTranscriptStats?: boolean;
|
|
813
1149
|
largeTranscriptThresholdBytes?: number;
|
|
814
1150
|
};
|
|
815
1151
|
|
|
@@ -849,7 +1185,7 @@ export const listProjectThreads = async (
|
|
|
849
1185
|
};
|
|
850
1186
|
}
|
|
851
1187
|
|
|
852
|
-
if (rollout.shouldDeferTranscriptLoad) {
|
|
1188
|
+
if (rollout.shouldDeferTranscriptLoad || options.includeTranscriptStats === false) {
|
|
853
1189
|
return {
|
|
854
1190
|
project: projectName,
|
|
855
1191
|
rolloutSizeBytes: rollout.fileSizeBytes,
|
|
@@ -885,12 +1221,7 @@ export const getThreadBrowseData = (dbPath: string, threadId: string): ThreadBro
|
|
|
885
1221
|
return withReadonlyDb(dbPath, (db) => {
|
|
886
1222
|
const existingTableNames = getExistingTableNames(db);
|
|
887
1223
|
const dbThread = db.query('SELECT * FROM threads WHERE id = ? LIMIT 1').get(threadId) as ThreadRow | null;
|
|
888
|
-
const thread =
|
|
889
|
-
dbThread ??
|
|
890
|
-
readFallbackThreadRows(dbPath, new Set(), null, { includeSubagents: true }).find(
|
|
891
|
-
(fallbackThread) => fallbackThread.id === threadId,
|
|
892
|
-
) ??
|
|
893
|
-
null;
|
|
1224
|
+
const thread = dbThread ?? readFallbackThreadRowById(dbPath, threadId, { includeSubagents: true }) ?? null;
|
|
894
1225
|
if (!thread) {
|
|
895
1226
|
throw new Error(`Thread not found: ${threadId}`);
|
|
896
1227
|
}
|
|
@@ -955,21 +1286,22 @@ export const deleteCodexThread = async (
|
|
|
955
1286
|
threadId: string,
|
|
956
1287
|
options: DeleteThreadOptions = {},
|
|
957
1288
|
): Promise<DeleteThreadsResult> => {
|
|
1289
|
+
const threadIds = [threadId];
|
|
958
1290
|
const result = withWritableDb(dbPath, (db) => {
|
|
959
|
-
return deleteThreadIds(db,
|
|
1291
|
+
return deleteThreadIds(db, threadIds);
|
|
960
1292
|
});
|
|
961
1293
|
|
|
962
1294
|
try {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1295
|
+
const sessionIndexResult = await deleteSessionIndexEntriesForThreads(
|
|
1296
|
+
dbPath,
|
|
1297
|
+
threadIds,
|
|
1298
|
+
result.deletedSessionFiles,
|
|
1299
|
+
Boolean(options.deleteSessionFiles),
|
|
1300
|
+
);
|
|
969
1301
|
|
|
970
1302
|
return {
|
|
971
|
-
|
|
972
|
-
|
|
1303
|
+
deletedSessionFiles: sessionIndexResult.deletedSessionFiles,
|
|
1304
|
+
deletedThreadIds: uniqueValues([...result.deletedThreadIds, ...sessionIndexResult.deletedThreadIds]),
|
|
973
1305
|
};
|
|
974
1306
|
} finally {
|
|
975
1307
|
await invalidateCodexUiCaches();
|
|
@@ -981,21 +1313,22 @@ export const deleteCodexThreads = async (
|
|
|
981
1313
|
threadIds: string[],
|
|
982
1314
|
options: DeleteThreadOptions = {},
|
|
983
1315
|
): Promise<DeleteThreadsResult> => {
|
|
1316
|
+
const uniqueThreadIds = uniqueValues(threadIds);
|
|
984
1317
|
const result = withWritableDb(dbPath, (db) => {
|
|
985
|
-
return deleteThreadIds(db,
|
|
1318
|
+
return deleteThreadIds(db, uniqueThreadIds);
|
|
986
1319
|
});
|
|
987
1320
|
|
|
988
1321
|
try {
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1322
|
+
const sessionIndexResult = await deleteSessionIndexEntriesForThreads(
|
|
1323
|
+
dbPath,
|
|
1324
|
+
uniqueThreadIds,
|
|
1325
|
+
result.deletedSessionFiles,
|
|
1326
|
+
Boolean(options.deleteSessionFiles),
|
|
1327
|
+
);
|
|
995
1328
|
|
|
996
1329
|
return {
|
|
997
|
-
|
|
998
|
-
|
|
1330
|
+
deletedSessionFiles: sessionIndexResult.deletedSessionFiles,
|
|
1331
|
+
deletedThreadIds: uniqueValues([...result.deletedThreadIds, ...sessionIndexResult.deletedThreadIds]),
|
|
999
1332
|
};
|
|
1000
1333
|
} finally {
|
|
1001
1334
|
await invalidateCodexUiCaches();
|
|
@@ -1007,6 +1340,8 @@ export const deleteCodexProject = async (
|
|
|
1007
1340
|
projectName: string,
|
|
1008
1341
|
options: DeleteProjectOptions = {},
|
|
1009
1342
|
): Promise<DeleteProjectResult> => {
|
|
1343
|
+
const existingThreadIds = new Set(readAllThreads(dbPath).map((thread) => thread.id));
|
|
1344
|
+
const fallbackThreadIds = listFallbackThreadIdsForProject(dbPath, existingThreadIds, projectName);
|
|
1010
1345
|
const result = withWritableDb(dbPath, (db) => {
|
|
1011
1346
|
const threads = db.query('SELECT id, cwd FROM threads').all() as Array<{ cwd: string; id: string }>;
|
|
1012
1347
|
const threadIds = threads
|
|
@@ -1021,16 +1356,17 @@ export const deleteCodexProject = async (
|
|
|
1021
1356
|
});
|
|
1022
1357
|
|
|
1023
1358
|
try {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1359
|
+
const sessionIndexResult = await deleteSessionIndexEntriesForThreads(
|
|
1360
|
+
dbPath,
|
|
1361
|
+
[...result.deletedThreadIds, ...fallbackThreadIds],
|
|
1362
|
+
result.deletedSessionFiles,
|
|
1363
|
+
Boolean(options.deleteSessionFiles),
|
|
1364
|
+
);
|
|
1030
1365
|
|
|
1031
1366
|
return {
|
|
1032
1367
|
...result,
|
|
1033
|
-
deletedSessionFiles:
|
|
1368
|
+
deletedSessionFiles: sessionIndexResult.deletedSessionFiles,
|
|
1369
|
+
deletedThreadIds: uniqueValues([...result.deletedThreadIds, ...sessionIndexResult.deletedThreadIds]),
|
|
1034
1370
|
};
|
|
1035
1371
|
} finally {
|
|
1036
1372
|
await invalidateCodexUiCaches();
|
|
@@ -1042,5 +1378,5 @@ export const listScopedThreads = (dbPath: string, projectName: string | null): T
|
|
|
1042
1378
|
};
|
|
1043
1379
|
|
|
1044
1380
|
export const invalidateCodexUiCaches = async () => {
|
|
1045
|
-
await invalidateCacheByPrefix('analytics-', 'thread-');
|
|
1381
|
+
await invalidateCacheByPrefix('analytics-', 'thread-', 'thread-preview-');
|
|
1046
1382
|
};
|