@hienlh/ppm 0.23.8 → 0.23.10
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/CHANGELOG.md +16 -0
- package/CLAUDE.md +4 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/accounts-settings-section-BOBJbG7i.js +1 -0
- package/dist/web/assets/accounts-settings-section-BOBJbG7i.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-BOBJbG7i.js.gz +0 -0
- package/dist/web/assets/agent-session-sheet-CjD4hBZV.js +2 -0
- package/dist/web/assets/agent-session-sheet-CjD4hBZV.js.br +0 -0
- package/dist/web/assets/agent-session-sheet-CjD4hBZV.js.gz +0 -0
- package/dist/web/assets/agent-session-sheet-store-BcQbnaV2.js +1 -0
- package/dist/web/assets/agent-session-window-content-Drm1HsSn.js +1 -0
- package/dist/web/assets/agent-session-window-content-Drm1HsSn.js.br +0 -0
- package/dist/web/assets/agent-session-window-content-Drm1HsSn.js.gz +0 -0
- package/dist/web/assets/{ai-resource-editor-DfVRMUHS.js → ai-resource-editor-M1Eax2Hc.js} +1 -1
- package/dist/web/assets/ai-resource-editor-M1Eax2Hc.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-M1Eax2Hc.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-B73t9SXm.js +1 -0
- package/dist/web/assets/{ai-settings-section-Ezhw4Fef.js → ai-settings-section-H173dm1k.js} +1 -1
- package/dist/web/assets/ai-settings-section-H173dm1k.js.br +0 -0
- package/dist/web/assets/ai-settings-section-H173dm1k.js.gz +0 -0
- package/dist/web/assets/{api-settings-tYKJ5Fqk.js → api-settings-BA_n8cPt.js} +1 -1
- package/dist/web/assets/{appearance-settings-section-CPOAp0fY.js → appearance-settings-section-Dqu20pt8.js} +1 -1
- package/dist/web/assets/appearance-settings-section-Dqu20pt8.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-Dqu20pt8.js.gz +0 -0
- package/dist/web/assets/{apps-panel-Cz7_o-M4.js → apps-panel-mkrzY7K0.js} +1 -1
- package/dist/web/assets/apps-panel-mkrzY7K0.js.br +0 -0
- package/dist/web/assets/apps-panel-mkrzY7K0.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-Dw3bNixU.js +1 -0
- package/dist/web/assets/branch-review-tab-Dw3bNixU.js.br +0 -0
- package/dist/web/assets/branch-review-tab-Dw3bNixU.js.gz +0 -0
- package/dist/web/assets/chat-tab-BAbcVFzD.js +15 -0
- package/dist/web/assets/chat-tab-BAbcVFzD.js.br +0 -0
- package/dist/web/assets/chat-tab-BAbcVFzD.js.gz +0 -0
- package/dist/web/assets/chat-tab-BaXGaBEC.js +1 -0
- package/dist/web/assets/chat-tab-BaXGaBEC.js.br +4 -0
- package/dist/web/assets/chat-tab-BaXGaBEC.js.gz +0 -0
- package/dist/web/assets/code-editor-CXLANXnI.js +7 -0
- package/dist/web/assets/code-editor-CXLANXnI.js.br +0 -0
- package/dist/web/assets/code-editor-CXLANXnI.js.gz +0 -0
- package/dist/web/assets/{codex-reset-credit-button-D2hal4bG.js → codex-reset-credit-button-CB8Dfhki.js} +1 -1
- package/dist/web/assets/codex-reset-credit-button-CB8Dfhki.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-CB8Dfhki.js.gz +0 -0
- package/dist/web/assets/{conflict-editor-Cj_gUncw.js → conflict-editor-CKsxIw3v.js} +2 -2
- package/dist/web/assets/conflict-editor-CKsxIw3v.js.br +0 -0
- package/dist/web/assets/conflict-editor-CKsxIw3v.js.gz +0 -0
- package/dist/web/assets/{csv-preview-Be3ODNj0.js → csv-preview-U0v_r_-7.js} +1 -1
- package/dist/web/assets/csv-preview-U0v_r_-7.js.br +0 -0
- package/dist/web/assets/csv-preview-U0v_r_-7.js.gz +0 -0
- package/dist/web/assets/{database-viewer-B1b--4y8.js → database-viewer-xQyUcBoL.js} +1 -1
- package/dist/web/assets/database-viewer-xQyUcBoL.js.br +0 -0
- package/dist/web/assets/database-viewer-xQyUcBoL.js.gz +0 -0
- package/dist/web/assets/{design-tab-8wi0IHss.js → design-tab-aaAt2_QE.js} +4 -4
- package/dist/web/assets/design-tab-aaAt2_QE.js.br +0 -0
- package/dist/web/assets/design-tab-aaAt2_QE.js.gz +0 -0
- package/dist/web/assets/{designs-sidebar-panel-D5-1Q8zQ.js → designs-sidebar-panel-CTzO4Thu.js} +1 -1
- package/dist/web/assets/designs-sidebar-panel-CTzO4Thu.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-CTzO4Thu.js.gz +0 -0
- package/dist/web/assets/{diff-viewer-Dcxk6UTG.js → diff-viewer-CSE2-OE7.js} +1 -1
- package/dist/web/assets/diff-viewer-CSE2-OE7.js.br +0 -0
- package/dist/web/assets/diff-viewer-CSE2-OE7.js.gz +0 -0
- package/dist/web/assets/{edit-diff-preview-DxDAtYhi.js → edit-diff-preview-gH6pRk4S.js} +1 -1
- package/dist/web/assets/edit-diff-preview-gH6pRk4S.js.br +0 -0
- package/dist/web/assets/{edit-diff-preview-DxDAtYhi.js.gz → edit-diff-preview-gH6pRk4S.js.gz} +0 -0
- package/dist/web/assets/{editor-language-service-BVJQnTSV.js → editor-language-service-CYl04pUy.js} +1 -1
- package/dist/web/assets/editor-language-service-CYl04pUy.js.br +0 -0
- package/dist/web/assets/editor-language-service-CYl04pUy.js.gz +0 -0
- package/dist/web/assets/explorer-body-BBOcvwmV.js +2 -0
- package/dist/web/assets/explorer-body-BBOcvwmV.js.br +0 -0
- package/dist/web/assets/explorer-body-BBOcvwmV.js.gz +0 -0
- package/dist/web/assets/{explorer-window-content-DH5AD3Ng.js → explorer-window-content-juCGcrkc.js} +1 -1
- package/dist/web/assets/explorer-window-content-juCGcrkc.js.br +0 -0
- package/dist/web/assets/explorer-window-content-juCGcrkc.js.gz +0 -0
- package/dist/web/assets/{extension-manager-section-BJr6ccWw.js → extension-manager-section-poMRmwvg.js} +1 -1
- package/dist/web/assets/extension-manager-section-poMRmwvg.js.br +0 -0
- package/dist/web/assets/extension-manager-section-poMRmwvg.js.gz +0 -0
- package/dist/web/assets/{extension-webview-CYNXHd8D.js → extension-webview-0QfzTI6s.js} +1 -1
- package/dist/web/assets/extension-webview-0QfzTI6s.js.br +0 -0
- package/dist/web/assets/extension-webview-0QfzTI6s.js.gz +0 -0
- package/dist/web/assets/{files-settings-section-JX7o4lex.js → files-settings-section-DJptxRgH.js} +1 -1
- package/dist/web/assets/files-settings-section-DJptxRgH.js.br +0 -0
- package/dist/web/assets/files-settings-section-DJptxRgH.js.gz +0 -0
- package/dist/web/assets/{general-settings-section-kF94Mz5q.js → general-settings-section-BFNbdDNv.js} +1 -1
- package/dist/web/assets/general-settings-section-BFNbdDNv.js.br +0 -0
- package/dist/web/assets/general-settings-section-BFNbdDNv.js.gz +0 -0
- package/dist/web/assets/{git-log-panel-Crlp9ofM.js → git-log-panel-SMMIbjSe.js} +1 -1
- package/dist/web/assets/git-log-panel-SMMIbjSe.js.br +0 -0
- package/dist/web/assets/git-log-panel-SMMIbjSe.js.gz +0 -0
- package/dist/web/assets/{glide-data-grid-O6MO5dKU.js → glide-data-grid-DZVmgu0T.js} +3 -3
- package/dist/web/assets/glide-data-grid-DZVmgu0T.js.br +0 -0
- package/dist/web/assets/glide-data-grid-DZVmgu0T.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-d_aaYuK_.js +1 -0
- package/dist/web/assets/group-chat-tab-d_aaYuK_.js.br +0 -0
- package/dist/web/assets/group-chat-tab-d_aaYuK_.js.gz +0 -0
- package/dist/web/assets/{index-DQCw6d-2.js → index-CIscPw4g.js} +6 -6
- package/dist/web/assets/index-CIscPw4g.js.br +0 -0
- package/dist/web/assets/index-CIscPw4g.js.gz +0 -0
- package/dist/web/assets/{jira-watcher-section-DwM7gqHT.js → jira-watcher-section-CsbhnLLn.js} +1 -1
- package/dist/web/assets/keybindings-store-BPs0pM0r.js +1 -0
- package/dist/web/assets/{keyboard-shortcuts-section-CewWGwiF.js → keyboard-shortcuts-section-CXqc2OtM.js} +1 -1
- package/dist/web/assets/keyboard-shortcuts-section-CXqc2OtM.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-CXqc2OtM.js.gz +0 -0
- package/dist/web/assets/{language-servers-section-nricdxke.js → language-servers-section-B4FsBVvZ.js} +2 -2
- package/dist/web/assets/language-servers-section-B4FsBVvZ.js.br +0 -0
- package/dist/web/assets/language-servers-section-B4FsBVvZ.js.gz +0 -0
- package/dist/web/assets/{lsp-client-DRMEWb-z.js → lsp-client-MQ4mjDfT.js} +1 -1
- package/dist/web/assets/lsp-client-MQ4mjDfT.js.br +0 -0
- package/dist/web/assets/lsp-client-MQ4mjDfT.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-BvCZZlue.js +1 -0
- package/dist/web/assets/{markdown-renderer-Dab9Us6u.js → markdown-renderer-CjPb5pns.js} +3 -3
- package/dist/web/assets/markdown-renderer-CjPb5pns.js.br +0 -0
- package/dist/web/assets/markdown-renderer-CjPb5pns.js.gz +0 -0
- package/dist/web/assets/{mobile-explorer-sheet-DtgdpvJ9.js → mobile-explorer-sheet-0aGhVQtI.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-0aGhVQtI.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-0aGhVQtI.js.gz +0 -0
- package/dist/web/assets/{new-design-dialog-Dd5KDB_p.js → new-design-dialog-2oT2oc_F.js} +1 -1
- package/dist/web/assets/new-design-dialog-2oT2oc_F.js.br +0 -0
- package/dist/web/assets/new-design-dialog-2oT2oc_F.js.gz +0 -0
- package/dist/web/assets/notification-store-Dd25PMPQ.js +1 -0
- package/dist/web/assets/{panel-store-DrSH3Nhp.js → panel-store-1X6yM3XZ.js} +1 -1
- package/dist/web/assets/panel-store-1X6yM3XZ.js.br +0 -0
- package/dist/web/assets/panel-store-1X6yM3XZ.js.gz +0 -0
- package/dist/web/assets/performance-panel-Ub96qrEH.js +3 -0
- package/dist/web/assets/performance-panel-Ub96qrEH.js.br +0 -0
- package/dist/web/assets/performance-panel-Ub96qrEH.js.gz +0 -0
- package/dist/web/assets/{ppmbot-settings-section-D67u6gPi.js → ppmbot-settings-section-CPMGP66g.js} +1 -1
- package/dist/web/assets/ppmbot-settings-section-CPMGP66g.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-CPMGP66g.js.gz +0 -0
- package/dist/web/assets/{problems-panel-DKgIw4uZ.js → problems-panel-CWwzZIP3.js} +1 -1
- package/dist/web/assets/problems-panel-CWwzZIP3.js.br +0 -0
- package/dist/web/assets/problems-panel-CWwzZIP3.js.gz +0 -0
- package/dist/web/assets/process-table-BwPws3zS.js +1 -0
- package/dist/web/assets/process-table-BwPws3zS.js.br +0 -0
- package/dist/web/assets/process-table-BwPws3zS.js.gz +0 -0
- package/dist/web/assets/{proxy-settings-section-CFiYcTBA.js → proxy-settings-section-nS8VbxI_.js} +1 -1
- package/dist/web/assets/proxy-settings-section-nS8VbxI_.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-nS8VbxI_.js.gz +0 -0
- package/dist/web/assets/{query-audit-section-BybgiPsc.js → query-audit-section-Dv5Pxn-w.js} +1 -1
- package/dist/web/assets/query-audit-section-Dv5Pxn-w.js.br +0 -0
- package/dist/web/assets/query-audit-section-Dv5Pxn-w.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-clipboard-notice-Bs3fZSRw.js → remote-desktop-clipboard-notice-DEbdu0hC.js} +1 -1
- package/dist/web/assets/remote-desktop-clipboard-notice-DEbdu0hC.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-DEbdu0hC.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BJm-akVY.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BJm-akVY.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-BJm-akVY.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-mobile-view-DgGOfPVY.js → remote-desktop-mobile-view-DPdGFD6C.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-view-DPdGFD6C.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DPdGFD6C.js.gz +0 -0
- package/dist/web/assets/{remote-desktop-readiness-gate-DOWryrQx.js → remote-desktop-readiness-gate-DV7YgSpP.js} +1 -1
- package/dist/web/assets/remote-desktop-readiness-gate-DV7YgSpP.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-DV7YgSpP.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-BktcWMjD.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-BktcWMjD.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-BktcWMjD.js.gz +0 -0
- package/dist/web/assets/{run-in-terminal-Cdn9PaAl.js → run-in-terminal-B_PCeBqG.js} +1 -1
- package/dist/web/assets/{schedules-settings-section-DGhG-b5O.js → schedules-settings-section-B3HYKSVh.js} +1 -1
- package/dist/web/assets/schedules-settings-section-B3HYKSVh.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-B3HYKSVh.js.gz +0 -0
- package/dist/web/assets/{send-to-chat-B09VjsB5.js → send-to-chat-Bjg6c8Ld.js} +1 -1
- package/dist/web/assets/send-to-chat-Bjg6c8Ld.js.br +0 -0
- package/dist/web/assets/send-to-chat-Bjg6c8Ld.js.gz +0 -0
- package/dist/web/assets/{services-panel-0klE3O4g.js → services-panel-D6k6AVS4.js} +1 -1
- package/dist/web/assets/services-panel-D6k6AVS4.js.br +0 -0
- package/dist/web/assets/services-panel-D6k6AVS4.js.gz +0 -0
- package/dist/web/assets/{settings-body-CfqpqFfq.js → settings-body-Cu0mNA5x.js} +2 -2
- package/dist/web/assets/settings-body-Cu0mNA5x.js.br +0 -0
- package/dist/web/assets/settings-body-Cu0mNA5x.js.gz +0 -0
- package/dist/web/assets/{settings-store-3jIBB8gx.js → settings-store-DIV25PM_.js} +2 -2
- package/dist/web/assets/settings-store-DIV25PM_.js.br +0 -0
- package/dist/web/assets/settings-store-DIV25PM_.js.gz +0 -0
- package/dist/web/assets/{settings-tab-CHweH5Nh.js → settings-tab-C-A6RNQ3.js} +1 -1
- package/dist/web/assets/{settings-window-content-C6Od3qV7.js → settings-window-content-48e5FJAq.js} +1 -1
- package/dist/web/assets/{sql-query-editor-ALQ5_X0j.js → sql-query-editor-CgGWYu9K.js} +1 -1
- package/dist/web/assets/sql-query-editor-CgGWYu9K.js.br +0 -0
- package/dist/web/assets/sql-query-editor-CgGWYu9K.js.gz +0 -0
- package/dist/web/assets/{sqlite-viewer-DKTty_jR.js → sqlite-viewer-Co1Oi3dv.js} +1 -1
- package/dist/web/assets/sqlite-viewer-Co1Oi3dv.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-Co1Oi3dv.js.gz +0 -0
- package/dist/web/assets/{system-monitor-body-D6J6lq7-.js → system-monitor-body-DxPKVa-W.js} +2 -2
- package/dist/web/assets/system-monitor-body-DxPKVa-W.js.br +0 -0
- package/dist/web/assets/system-monitor-body-DxPKVa-W.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-4miOZuQQ.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-D1t30f32.js → system-monitor-window-content-B-A7DdML.js} +1 -1
- package/dist/web/assets/{tab-host-window-content-DTcx2D0O.js → tab-host-window-content-CChcpg1v.js} +1 -1
- package/dist/web/assets/tab-host-window-content-CChcpg1v.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-CChcpg1v.js.gz +0 -0
- package/dist/web/assets/{tab-store-CUPgQIQz.js → tab-store-D33icgdA.js} +1 -1
- package/dist/web/assets/{terminal-tab-DgTfQKBI.js → terminal-tab-BDqlyBLK.js} +2 -2
- package/dist/web/assets/terminal-tab-BDqlyBLK.js.br +0 -0
- package/dist/web/assets/terminal-tab-BDqlyBLK.js.gz +0 -0
- package/dist/web/assets/tool-cards-iJ8tyrLq.js +9 -0
- package/dist/web/assets/tool-cards-iJ8tyrLq.js.br +0 -0
- package/dist/web/assets/tool-cards-iJ8tyrLq.js.gz +0 -0
- package/dist/web/assets/{use-inline-blame-Dv111BKY.js → use-inline-blame-D9js570a.js} +4 -4
- package/dist/web/assets/use-inline-blame-D9js570a.js.br +0 -0
- package/dist/web/assets/use-inline-blame-D9js570a.js.gz +0 -0
- package/dist/web/assets/{use-lsp-CZTFJIXX.js → use-lsp-BYtylZId.js} +1 -1
- package/dist/web/assets/use-lsp-BYtylZId.js.br +0 -0
- package/dist/web/assets/use-lsp-BYtylZId.js.gz +0 -0
- package/dist/web/assets/{use-monaco-theme-DL2dIG5L.js → use-monaco-theme-DJ8y_7IZ.js} +1 -1
- package/dist/web/assets/{use-process-kill-D7D9QvJG.js → use-process-kill-BS84S-kD.js} +1 -1
- package/dist/web/assets/use-process-kill-BS84S-kD.js.br +0 -0
- package/dist/web/assets/use-process-kill-BS84S-kD.js.gz +0 -0
- package/dist/web/assets/{use-websocket-ziY-Gz_B.js → use-websocket-Mqj27umG.js} +1 -1
- package/dist/web/assets/{video-preview-DzwY3q9W.js → video-preview-BuzUAIma.js} +1 -1
- package/dist/web/assets/video-preview-BuzUAIma.js.br +0 -0
- package/dist/web/assets/video-preview-BuzUAIma.js.gz +0 -0
- package/dist/web/assets/{voice-settings-section-B7zMHsuz.js → voice-settings-section-DnwQjBbw.js} +1 -1
- package/dist/web/assets/voice-settings-section-DnwQjBbw.js.br +0 -0
- package/dist/web/assets/voice-settings-section-DnwQjBbw.js.gz +0 -0
- package/dist/web/assets/{window-pip-registry-dxrBFfkP.js → window-pip-registry-Bl--fK8-.js} +1 -1
- package/dist/web/assets/window-store-vo1N70nK.js +1 -0
- package/dist/web/assets/window-store-vo1N70nK.js.br +0 -0
- package/dist/web/assets/window-store-vo1N70nK.js.gz +0 -0
- package/dist/web/index.html +6 -6
- package/dist/web/index.html.br +0 -0
- package/dist/web/index.html.gz +0 -0
- package/dist/web/sw.js +1 -1
- package/dist/web/sw.js.br +0 -0
- package/dist/web/sw.js.gz +0 -0
- package/docs/architecture/ai-chat-and-providers.md +66 -0
- package/docs/architecture/workspace-and-ui.md +15 -3
- package/docs/design-guidelines.md +6 -1
- package/package.json +1 -1
- package/src/providers/codex-app-server/codex-history.ts +4 -4
- package/src/providers/codex-app-server/codex-provider.ts +1 -1
- package/src/providers/codex-app-server/codex-rollout-tail-parser.ts +203 -0
- package/src/providers/codex-app-server/codex-subagent-thread.ts +7 -1
- package/src/server/index.ts +7 -2
- package/src/server/routes/chat.ts +12 -4
- package/src/server/ws/global.ts +19 -3
- package/src/services/agent-transcript/agent-transcript-activity.ts +72 -0
- package/src/services/agent-transcript/agent-transcript-codex-activity.ts +161 -0
- package/src/services/agent-transcript/agent-transcript-codex-tail-cache.ts +85 -0
- package/src/services/agent-transcript/agent-transcript-envelope.ts +86 -0
- package/src/services/agent-transcript/agent-transcript-error-map.ts +33 -0
- package/src/services/agent-transcript/agent-transcript-file-tail-feed.ts +180 -0
- package/src/services/agent-transcript/agent-transcript-file-tail-state.ts +100 -0
- package/src/services/agent-transcript/agent-transcript-fs-io.ts +79 -0
- package/src/services/agent-transcript/agent-transcript-hub-clock.ts +37 -0
- package/src/services/agent-transcript/agent-transcript-hub-registry.ts +153 -0
- package/src/services/agent-transcript/agent-transcript-hub.ts +103 -0
- package/src/services/agent-transcript/agent-transcript-index-cache.ts +85 -0
- package/src/services/agent-transcript/agent-transcript-session-hub-activity.ts +103 -0
- package/src/services/agent-transcript/agent-transcript-session-hub-read.ts +194 -0
- package/src/services/agent-transcript/agent-transcript-session-hub-types.ts +81 -0
- package/src/services/agent-transcript/agent-transcript-session-hub.ts +196 -0
- package/src/services/agent-transcript/agent-transcript-sources.ts +199 -0
- package/src/services/agent-transcript/agent-transcript-ws-like.ts +19 -0
- package/src/services/agent-transcript/claude-projects-root.ts +21 -0
- package/src/services/agent-transcript/session-ownership.ts +152 -0
- package/src/services/nested-subagent-spy.ts +3 -3
- package/src/services/subagent-transcript-merger.ts +21 -7
- package/src/shared/agent-transcript-protocol.ts +158 -0
- package/src/types/chat.ts +27 -3
- package/src/web/app.tsx +5 -5
- package/src/web/components/chat/agent-card-summary.tsx +73 -0
- package/src/web/components/chat/agent-session-context.ts +34 -0
- package/src/web/components/chat/agent-session-fallback-store.ts +60 -0
- package/src/web/components/chat/agent-session-sheet-store.ts +23 -0
- package/src/web/components/chat/{team-member-sheet.tsx → agent-session-sheet.tsx} +12 -12
- package/src/web/components/chat/agent-session-window-content.tsx +133 -0
- package/src/web/components/chat/chat-history-bar.tsx +1 -0
- package/src/web/components/chat/chat-tab.tsx +21 -4
- package/src/web/components/chat/codex-usage-panel.tsx +26 -8
- package/src/web/components/chat/running-agents-bar.tsx +93 -0
- package/src/web/components/chat/team-activity-panel.tsx +19 -5
- package/src/web/components/chat/tool-cards.tsx +73 -4
- package/src/web/components/chat/use-open-agent-session.ts +83 -0
- package/src/web/components/floating-window/window-content-registry.ts +4 -5
- package/src/web/components/floating-window/window-geometry.ts +18 -0
- package/src/web/components/floating-window/window-persistence.ts +5 -4
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/settings/resolve-open-settings-action.ts +1 -1
- package/src/web/components/system/resolve-open-system-monitor-action.ts +1 -1
- package/src/web/hooks/use-agent-activity.ts +65 -0
- package/src/web/hooks/use-agent-session-stream.ts +134 -0
- package/src/web/hooks/use-chat.ts +12 -18
- package/src/web/hooks/use-global-events.ts +35 -2
- package/src/web/lib/agent-session-stream-merge.ts +48 -0
- package/src/web/lib/agent-step-summary.ts +331 -0
- package/src/web/lib/global-ws-channel.ts +41 -0
- package/src/web/lib/running-agent-rows.ts +115 -0
- package/dist/web/assets/accounts-settings-section-BNcPvEq1.js +0 -1
- package/dist/web/assets/accounts-settings-section-BNcPvEq1.js.br +0 -0
- package/dist/web/assets/accounts-settings-section-BNcPvEq1.js.gz +0 -0
- package/dist/web/assets/ai-resource-editor-DfVRMUHS.js.br +0 -0
- package/dist/web/assets/ai-resource-editor-DfVRMUHS.js.gz +0 -0
- package/dist/web/assets/ai-settings-section-B_0-P8jx.js +0 -1
- package/dist/web/assets/ai-settings-section-Ezhw4Fef.js.br +0 -0
- package/dist/web/assets/ai-settings-section-Ezhw4Fef.js.gz +0 -0
- package/dist/web/assets/appearance-settings-section-CPOAp0fY.js.br +0 -0
- package/dist/web/assets/appearance-settings-section-CPOAp0fY.js.gz +0 -0
- package/dist/web/assets/apps-panel-Cz7_o-M4.js.br +0 -0
- package/dist/web/assets/apps-panel-Cz7_o-M4.js.gz +0 -0
- package/dist/web/assets/branch-review-tab-BPx3kHrM.js +0 -1
- package/dist/web/assets/branch-review-tab-BPx3kHrM.js.br +0 -0
- package/dist/web/assets/branch-review-tab-BPx3kHrM.js.gz +0 -0
- package/dist/web/assets/chat-tab-BadDM_j8.js +0 -1
- package/dist/web/assets/chat-tab-BadDM_j8.js.br +0 -0
- package/dist/web/assets/chat-tab-BadDM_j8.js.gz +0 -0
- package/dist/web/assets/chat-tab-IqAY4c7p.js +0 -15
- package/dist/web/assets/chat-tab-IqAY4c7p.js.br +0 -0
- package/dist/web/assets/chat-tab-IqAY4c7p.js.gz +0 -0
- package/dist/web/assets/code-editor-Dmitw9QS.js +0 -7
- package/dist/web/assets/code-editor-Dmitw9QS.js.br +0 -0
- package/dist/web/assets/code-editor-Dmitw9QS.js.gz +0 -0
- package/dist/web/assets/codex-reset-credit-button-D2hal4bG.js.br +0 -0
- package/dist/web/assets/codex-reset-credit-button-D2hal4bG.js.gz +0 -0
- package/dist/web/assets/conflict-editor-Cj_gUncw.js.br +0 -0
- package/dist/web/assets/conflict-editor-Cj_gUncw.js.gz +0 -0
- package/dist/web/assets/csv-preview-Be3ODNj0.js.br +0 -0
- package/dist/web/assets/csv-preview-Be3ODNj0.js.gz +0 -0
- package/dist/web/assets/database-viewer-B1b--4y8.js.br +0 -0
- package/dist/web/assets/database-viewer-B1b--4y8.js.gz +0 -0
- package/dist/web/assets/design-tab-8wi0IHss.js.br +0 -0
- package/dist/web/assets/design-tab-8wi0IHss.js.gz +0 -0
- package/dist/web/assets/designs-sidebar-panel-D5-1Q8zQ.js.br +0 -0
- package/dist/web/assets/designs-sidebar-panel-D5-1Q8zQ.js.gz +0 -0
- package/dist/web/assets/diff-viewer-Dcxk6UTG.js.br +0 -0
- package/dist/web/assets/diff-viewer-Dcxk6UTG.js.gz +0 -0
- package/dist/web/assets/edit-diff-preview-DxDAtYhi.js.br +0 -0
- package/dist/web/assets/editor-language-service-BVJQnTSV.js.br +0 -0
- package/dist/web/assets/editor-language-service-BVJQnTSV.js.gz +0 -0
- package/dist/web/assets/explorer-body-CTkrlrI3.js +0 -2
- package/dist/web/assets/explorer-body-CTkrlrI3.js.br +0 -0
- package/dist/web/assets/explorer-body-CTkrlrI3.js.gz +0 -0
- package/dist/web/assets/explorer-window-content-DH5AD3Ng.js.br +0 -0
- package/dist/web/assets/explorer-window-content-DH5AD3Ng.js.gz +0 -0
- package/dist/web/assets/extension-manager-section-BJr6ccWw.js.br +0 -0
- package/dist/web/assets/extension-manager-section-BJr6ccWw.js.gz +0 -0
- package/dist/web/assets/extension-webview-CYNXHd8D.js.br +0 -0
- package/dist/web/assets/extension-webview-CYNXHd8D.js.gz +0 -0
- package/dist/web/assets/files-settings-section-JX7o4lex.js.br +0 -0
- package/dist/web/assets/files-settings-section-JX7o4lex.js.gz +0 -0
- package/dist/web/assets/general-settings-section-kF94Mz5q.js.br +0 -0
- package/dist/web/assets/general-settings-section-kF94Mz5q.js.gz +0 -0
- package/dist/web/assets/git-log-panel-Crlp9ofM.js.br +0 -0
- package/dist/web/assets/git-log-panel-Crlp9ofM.js.gz +0 -0
- package/dist/web/assets/glide-data-grid-O6MO5dKU.js.br +0 -0
- package/dist/web/assets/glide-data-grid-O6MO5dKU.js.gz +0 -0
- package/dist/web/assets/group-chat-tab-DGLSGf37.js +0 -1
- package/dist/web/assets/group-chat-tab-DGLSGf37.js.br +0 -0
- package/dist/web/assets/group-chat-tab-DGLSGf37.js.gz +0 -0
- package/dist/web/assets/index-DQCw6d-2.js.br +0 -0
- package/dist/web/assets/index-DQCw6d-2.js.gz +0 -0
- package/dist/web/assets/keybindings-store-CJtEHFIQ.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-CewWGwiF.js.br +0 -0
- package/dist/web/assets/keyboard-shortcuts-section-CewWGwiF.js.gz +0 -0
- package/dist/web/assets/language-servers-section-nricdxke.js.br +0 -0
- package/dist/web/assets/language-servers-section-nricdxke.js.gz +0 -0
- package/dist/web/assets/lsp-client-DRMEWb-z.js.br +0 -0
- package/dist/web/assets/lsp-client-DRMEWb-z.js.gz +0 -0
- package/dist/web/assets/markdown-renderer-D5-xliE9.js +0 -1
- package/dist/web/assets/markdown-renderer-Dab9Us6u.js.br +0 -0
- package/dist/web/assets/markdown-renderer-Dab9Us6u.js.gz +0 -0
- package/dist/web/assets/mobile-explorer-sheet-DtgdpvJ9.js.br +0 -0
- package/dist/web/assets/mobile-explorer-sheet-DtgdpvJ9.js.gz +0 -0
- package/dist/web/assets/new-design-dialog-Dd5KDB_p.js.br +0 -0
- package/dist/web/assets/new-design-dialog-Dd5KDB_p.js.gz +0 -0
- package/dist/web/assets/notification-store-D2vTyp_Q.js +0 -1
- package/dist/web/assets/panel-store-DrSH3Nhp.js.br +0 -0
- package/dist/web/assets/panel-store-DrSH3Nhp.js.gz +0 -0
- package/dist/web/assets/performance-panel-LMGefOQ2.js +0 -3
- package/dist/web/assets/performance-panel-LMGefOQ2.js.br +0 -0
- package/dist/web/assets/performance-panel-LMGefOQ2.js.gz +0 -0
- package/dist/web/assets/ppmbot-settings-section-D67u6gPi.js.br +0 -0
- package/dist/web/assets/ppmbot-settings-section-D67u6gPi.js.gz +0 -0
- package/dist/web/assets/problems-panel-DKgIw4uZ.js.br +0 -0
- package/dist/web/assets/problems-panel-DKgIw4uZ.js.gz +0 -0
- package/dist/web/assets/process-table-BIAgC_jG.js +0 -1
- package/dist/web/assets/process-table-BIAgC_jG.js.br +0 -0
- package/dist/web/assets/process-table-BIAgC_jG.js.gz +0 -0
- package/dist/web/assets/proxy-settings-section-CFiYcTBA.js.br +0 -0
- package/dist/web/assets/proxy-settings-section-CFiYcTBA.js.gz +0 -0
- package/dist/web/assets/query-audit-section-BybgiPsc.js.br +0 -0
- package/dist/web/assets/query-audit-section-BybgiPsc.js.gz +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Bs3fZSRw.js.br +0 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Bs3fZSRw.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DgxTdWMh.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-sheet-DgxTdWMh.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-DgxTdWMh.js.gz +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DgGOfPVY.js.br +0 -0
- package/dist/web/assets/remote-desktop-mobile-view-DgGOfPVY.js.gz +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-DOWryrQx.js.br +0 -0
- package/dist/web/assets/remote-desktop-readiness-gate-DOWryrQx.js.gz +0 -0
- package/dist/web/assets/remote-desktop-window-content-7t0wQsHx.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-7t0wQsHx.js.br +0 -0
- package/dist/web/assets/remote-desktop-window-content-7t0wQsHx.js.gz +0 -0
- package/dist/web/assets/schedules-settings-section-DGhG-b5O.js.br +0 -0
- package/dist/web/assets/schedules-settings-section-DGhG-b5O.js.gz +0 -0
- package/dist/web/assets/send-to-chat-B09VjsB5.js.br +0 -0
- package/dist/web/assets/send-to-chat-B09VjsB5.js.gz +0 -0
- package/dist/web/assets/services-panel-0klE3O4g.js.br +0 -0
- package/dist/web/assets/services-panel-0klE3O4g.js.gz +0 -0
- package/dist/web/assets/settings-body-CfqpqFfq.js.br +0 -0
- package/dist/web/assets/settings-body-CfqpqFfq.js.gz +0 -0
- package/dist/web/assets/settings-store-3jIBB8gx.js.br +0 -0
- package/dist/web/assets/settings-store-3jIBB8gx.js.gz +0 -0
- package/dist/web/assets/sql-query-editor-ALQ5_X0j.js.br +0 -0
- package/dist/web/assets/sql-query-editor-ALQ5_X0j.js.gz +0 -0
- package/dist/web/assets/sqlite-viewer-DKTty_jR.js.br +0 -0
- package/dist/web/assets/sqlite-viewer-DKTty_jR.js.gz +0 -0
- package/dist/web/assets/system-monitor-body-D6J6lq7-.js.br +0 -0
- package/dist/web/assets/system-monitor-body-D6J6lq7-.js.gz +0 -0
- package/dist/web/assets/system-monitor-tab-Di18zNNS.js +0 -1
- package/dist/web/assets/tab-host-window-content-DTcx2D0O.js.br +0 -0
- package/dist/web/assets/tab-host-window-content-DTcx2D0O.js.gz +0 -0
- package/dist/web/assets/team-member-sheet-CFSbPG6n.js +0 -2
- package/dist/web/assets/team-member-sheet-CFSbPG6n.js.br +0 -0
- package/dist/web/assets/team-member-sheet-CFSbPG6n.js.gz +0 -0
- package/dist/web/assets/team-member-window-content-VeI6DGeM.js +0 -1
- package/dist/web/assets/team-member-window-content-VeI6DGeM.js.br +0 -0
- package/dist/web/assets/team-member-window-content-VeI6DGeM.js.gz +0 -0
- package/dist/web/assets/terminal-tab-DgTfQKBI.js.br +0 -0
- package/dist/web/assets/terminal-tab-DgTfQKBI.js.gz +0 -0
- package/dist/web/assets/tool-cards-_fpYI1hB.js +0 -9
- package/dist/web/assets/tool-cards-_fpYI1hB.js.br +0 -0
- package/dist/web/assets/tool-cards-_fpYI1hB.js.gz +0 -0
- package/dist/web/assets/use-inline-blame-Dv111BKY.js.br +0 -0
- package/dist/web/assets/use-inline-blame-Dv111BKY.js.gz +0 -0
- package/dist/web/assets/use-lsp-CZTFJIXX.js.br +0 -0
- package/dist/web/assets/use-lsp-CZTFJIXX.js.gz +0 -0
- package/dist/web/assets/use-open-team-member-ElN3KmCI.js +0 -1
- package/dist/web/assets/use-process-kill-D7D9QvJG.js.br +0 -0
- package/dist/web/assets/use-process-kill-D7D9QvJG.js.gz +0 -0
- package/dist/web/assets/video-preview-DzwY3q9W.js.br +0 -0
- package/dist/web/assets/video-preview-DzwY3q9W.js.gz +0 -0
- package/dist/web/assets/voice-settings-section-B7zMHsuz.js.br +0 -0
- package/dist/web/assets/voice-settings-section-B7zMHsuz.js.gz +0 -0
- package/dist/web/assets/window-store-B4cbZ5rr.js +0 -1
- package/dist/web/assets/window-store-B4cbZ5rr.js.br +0 -0
- package/dist/web/assets/window-store-B4cbZ5rr.js.gz +0 -0
- package/src/web/components/chat/team-member-window-content.tsx +0 -66
- package/src/web/components/chat/team-working-bar.tsx +0 -62
- package/src/web/components/chat/use-open-team-member.ts +0 -41
- package/src/web/hooks/use-member-transcript-tail.ts +0 -95
- /package/dist/web/assets/{api-settings-BeINN5Dy.js → api-settings-BWgfXl7o.js} +0 -0
- /package/dist/web/assets/{api-settings-BeINN5Dy.js.br → api-settings-BWgfXl7o.js.br} +0 -0
- /package/dist/web/assets/{api-settings-BeINN5Dy.js.gz → api-settings-BWgfXl7o.js.gz} +0 -0
- /package/dist/web/assets/{libesm-CxeQSM3t.js → libesm-DAF5_F99.js} +0 -0
- /package/dist/web/assets/{libesm-CxeQSM3t.js.br → libesm-DAF5_F99.js.br} +0 -0
- /package/dist/web/assets/{libesm-CxeQSM3t.js.gz → libesm-DAF5_F99.js.gz} +0 -0
- /package/dist/web/assets/{onboarding-entry-DD3QSDiz.js → onboarding-entry-Bh-WE3vq.js} +0 -0
- /package/dist/web/assets/{onboarding-entry-DD3QSDiz.js.br → onboarding-entry-Bh-WE3vq.js.br} +0 -0
- /package/dist/web/assets/{onboarding-entry-DD3QSDiz.js.gz → onboarding-entry-Bh-WE3vq.js.gz} +0 -0
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
18
|
-
import { homedir } from "node:os";
|
|
19
18
|
import { join } from "node:path";
|
|
20
19
|
import type { ChatEvent } from "../types/chat.ts";
|
|
21
20
|
import { parseSessionMessage } from "./jsonl-transcript-parser.ts";
|
|
22
21
|
import { groupSubagentsByCard } from "./team-member-activity/subagent-transcript-index.ts";
|
|
22
|
+
import { claudeProjectsRoot } from "./agent-transcript/claude-projects-root.ts";
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Locate the per-session directory (…/projects/<slug>/<sessionId>) that holds
|
|
@@ -29,8 +29,7 @@ import { groupSubagentsByCard } from "./team-member-activity/subagent-transcript
|
|
|
29
29
|
* the session's main JSONL.
|
|
30
30
|
*/
|
|
31
31
|
export function resolveSessionDir(sessionId: string, projectPath: string | null | undefined): string | null {
|
|
32
|
-
const
|
|
33
|
-
const projectsRoot = join(home, ".claude", "projects");
|
|
32
|
+
const projectsRoot = claudeProjectsRoot();
|
|
34
33
|
if (projectPath) {
|
|
35
34
|
const encoded = projectPath.replace(/[/\\:.]/g, "-");
|
|
36
35
|
const dir = join(projectsRoot, encoded);
|
|
@@ -67,16 +66,28 @@ export interface TimedChatEvent {
|
|
|
67
66
|
* Incremental parser for one agent transcript. Feed it JSONL lines in file
|
|
68
67
|
* order (whole file at once, or a live tail's new lines) and it returns the
|
|
69
68
|
* child events those lines carry, keeping the skip/limit state across calls.
|
|
69
|
+
*
|
|
70
|
+
* `midFile: true` disables the first-user-record skip: a subscriber resuming
|
|
71
|
+
* a session hub mid-file (e.g. a SendMessage resume prompt lands well after the
|
|
72
|
+
* spawn prompt) must see every user record it is fed, not just the ones after
|
|
73
|
+
* the file's first — there is no "first" from where it joined.
|
|
74
|
+
*
|
|
75
|
+
* `maxEvents` overrides the default history-payload guard (`MAX_CHILDREN_PER_AGENT`).
|
|
76
|
+
* A live session-window subscription reads one file per subscriber rather than
|
|
77
|
+
* one payload for a whole reload, and the client already bounds its own render
|
|
78
|
+
* buffer — so the hub passes `Infinity` here rather than silently freezing a
|
|
79
|
+
* long-running teammate's stream once the reload guard's count is reached.
|
|
70
80
|
*/
|
|
71
|
-
export function createAgentTranscriptLineParser() {
|
|
72
|
-
let isFirstUser =
|
|
81
|
+
export function createAgentTranscriptLineParser(opts?: { midFile?: boolean; maxEvents?: number }) {
|
|
82
|
+
let isFirstUser = !opts?.midFile;
|
|
83
|
+
const maxEvents = opts?.maxEvents ?? MAX_CHILDREN_PER_AGENT;
|
|
73
84
|
let emitted = 0;
|
|
74
85
|
let lastTs = 0;
|
|
75
86
|
return {
|
|
76
87
|
feed(line: string): TimedChatEvent[] {
|
|
77
88
|
const out: TimedChatEvent[] = [];
|
|
78
89
|
const trimmed = line.trim();
|
|
79
|
-
if (!trimmed || emitted >=
|
|
90
|
+
if (!trimmed || emitted >= maxEvents) return out;
|
|
80
91
|
let entry: any;
|
|
81
92
|
try {
|
|
82
93
|
entry = JSON.parse(trimmed);
|
|
@@ -98,7 +109,7 @@ export function createAgentTranscriptLineParser() {
|
|
|
98
109
|
if (!Number.isNaN(parsedTs)) lastTs = parsedTs;
|
|
99
110
|
const parsed = parseSessionMessage(entry);
|
|
100
111
|
for (const ev of parsed.events ?? []) {
|
|
101
|
-
if (emitted >=
|
|
112
|
+
if (emitted >= maxEvents) break;
|
|
102
113
|
// Keep single events from ballooning the history payload (agent files
|
|
103
114
|
// can carry multi-MB tool outputs the live stream also showed in full,
|
|
104
115
|
// but 24 agents × full outputs breaks mobile reloads).
|
|
@@ -151,6 +162,9 @@ export function mergeSubagentChildren(sessionDir: string, messages: MessageLike[
|
|
|
151
162
|
if (ev.type !== "tool_use" || (ev.tool !== "Agent" && ev.tool !== "Task") || !ev.toolUseId) continue;
|
|
152
163
|
const group = groups.get(ev.toolUseId);
|
|
153
164
|
if (!group) continue;
|
|
165
|
+
// A group was found on disk regardless of what it parsed to — the client can slim this
|
|
166
|
+
// card's children because a session window can always stream the rest from here.
|
|
167
|
+
(ev as { transcriptAvailable?: boolean }).transcriptAvailable = true;
|
|
154
168
|
const timed: TimedChatEvent[] = [];
|
|
155
169
|
for (const agent of group) timed.push(...parseAgentTranscriptTimed(agent.transcriptPath));
|
|
156
170
|
// Stable sort: same-timestamp events keep transcript order.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire protocol for the Agent card session window, carried entirely over
|
|
3
|
+
* `/ws/global`. One hub per `(providerId, sessionId)` on the server streams a
|
|
4
|
+
* card's (or teammate's) transcript from disk, from whatever byte offset the
|
|
5
|
+
* client already has, and keeps pushing new steps live as they are written.
|
|
6
|
+
*
|
|
7
|
+
* Contract the server holds to (see `agent-transcript-hub.ts`):
|
|
8
|
+
* - The client never names a file or a byte range directly — only a `source`
|
|
9
|
+
* (a card id or a teammate handle) the server resolves itself, and a
|
|
10
|
+
* `cursor` of offsets keyed by file keys the server handed out earlier.
|
|
11
|
+
* Offsets for keys the server never derived are ignored; a stale offset
|
|
12
|
+
* past the current file size is clamped down rather than rejected.
|
|
13
|
+
* - Every error the client can see is one of the four codes below — never an
|
|
14
|
+
* exception message, a path, or a code from an internal module.
|
|
15
|
+
*/
|
|
16
|
+
import type { ChatEvent } from "../types/chat.ts";
|
|
17
|
+
|
|
18
|
+
export type AgentTranscriptProviderId = "claude" | "codex";
|
|
19
|
+
|
|
20
|
+
export type AgentTranscriptSourceKind =
|
|
21
|
+
| { kind: "card"; cardId: string }
|
|
22
|
+
| { kind: "member"; teamName: string; memberName: string };
|
|
23
|
+
|
|
24
|
+
/** Byte offset already consumed, per file key the server previously derived. */
|
|
25
|
+
export interface AgentTranscriptCursor {
|
|
26
|
+
[fileKey: string]: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* One step on the wire. `k` is a stable de-dupe key, normally
|
|
31
|
+
* `"<fileKey>:<byteOffset>:<i>"` where `byteOffset` is a file position before
|
|
32
|
+
* the read that produced it, so a page re-sent after a dropped connection
|
|
33
|
+
* carries the same keys as before. `replace: true` (Codex only) means the
|
|
34
|
+
* client should update the step already shown for this `ev`'s `toolUseId` in
|
|
35
|
+
* place, not append a new one — the usual case is a tool_result answering an
|
|
36
|
+
* earlier tool_use. A `replace` envelope's `k` is the ORIGINAL key issued for
|
|
37
|
+
* that `toolUseId`, reused rather than freshly minted, precisely so a
|
|
38
|
+
* same-`k` upsert on the client has something to match.
|
|
39
|
+
*/
|
|
40
|
+
export interface AgentTranscriptEnvelope {
|
|
41
|
+
ev: ChatEvent;
|
|
42
|
+
ts: number;
|
|
43
|
+
k: string;
|
|
44
|
+
replace?: true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type AgentTranscriptErrorCode = "not_found" | "forbidden" | "limit" | "bad_request";
|
|
48
|
+
|
|
49
|
+
/** One entry of the running-agents bar. Exactly one of `cardId`/`memberName` is set. */
|
|
50
|
+
export interface AgentTranscriptRunningEntry {
|
|
51
|
+
cardId?: string;
|
|
52
|
+
memberName?: string;
|
|
53
|
+
/** Epoch ms the underlying transcript file was last written. */
|
|
54
|
+
lastWriteAt: number;
|
|
55
|
+
/** Short label for the agent's most recent step, when one could be read cheaply. */
|
|
56
|
+
lastStep?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---- Client → server ----
|
|
60
|
+
|
|
61
|
+
export interface AgentTranscriptSubscribeMsg {
|
|
62
|
+
type: "agent-transcript:subscribe";
|
|
63
|
+
subId: string;
|
|
64
|
+
projectName: string;
|
|
65
|
+
providerId: AgentTranscriptProviderId;
|
|
66
|
+
sessionId: string;
|
|
67
|
+
source: AgentTranscriptSourceKind;
|
|
68
|
+
cursor?: AgentTranscriptCursor;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface AgentTranscriptUnsubscribeMsg {
|
|
72
|
+
type: "agent-transcript:unsubscribe";
|
|
73
|
+
subId: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface AgentActivitySubscribeMsg {
|
|
77
|
+
type: "agent-activity:subscribe";
|
|
78
|
+
subId: string;
|
|
79
|
+
projectName: string;
|
|
80
|
+
providerId: AgentTranscriptProviderId;
|
|
81
|
+
sessionId: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface AgentActivityUnsubscribeMsg {
|
|
85
|
+
type: "agent-activity:unsubscribe";
|
|
86
|
+
subId: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface PingMsg {
|
|
90
|
+
type: "ping";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export type AgentTranscriptClientMsg =
|
|
94
|
+
| AgentTranscriptSubscribeMsg
|
|
95
|
+
| AgentTranscriptUnsubscribeMsg
|
|
96
|
+
| AgentActivitySubscribeMsg
|
|
97
|
+
| AgentActivityUnsubscribeMsg
|
|
98
|
+
| PingMsg;
|
|
99
|
+
|
|
100
|
+
// ---- Server → client ----
|
|
101
|
+
|
|
102
|
+
export interface AgentTranscriptEventsMsg {
|
|
103
|
+
type: "agent-transcript:events";
|
|
104
|
+
subId: string;
|
|
105
|
+
events: AgentTranscriptEnvelope[];
|
|
106
|
+
/** Current per-file consumed offsets for this subscription — the next `cursor` to resume from. */
|
|
107
|
+
cursor: AgentTranscriptCursor;
|
|
108
|
+
/** More pages are coming right behind this one (a backlog being drained on subscribe). */
|
|
109
|
+
more?: true;
|
|
110
|
+
/**
|
|
111
|
+
* The client must discard everything it has for this subscription and
|
|
112
|
+
* replace it with `events` — a truncated/rotated Claude transcript file, or
|
|
113
|
+
* a Codex compaction/rollback record, rewrote history rather than appending
|
|
114
|
+
* to it. Set only on the first page of the replacement; later pages of the
|
|
115
|
+
* same catch-up carry `more` instead.
|
|
116
|
+
*/
|
|
117
|
+
reset?: true;
|
|
118
|
+
/** The source resolved to at least one readable file (as opposed to the error path). */
|
|
119
|
+
available: boolean;
|
|
120
|
+
/** Whether the underlying agent still looks active (see hub's idle heuristic). */
|
|
121
|
+
running: boolean;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface AgentTranscriptErrorMsg {
|
|
125
|
+
type: "agent-transcript:error";
|
|
126
|
+
subId: string;
|
|
127
|
+
code: AgentTranscriptErrorCode;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export interface AgentActivityMsg {
|
|
131
|
+
type: "agent-activity";
|
|
132
|
+
subId: string;
|
|
133
|
+
running: AgentTranscriptRunningEntry[];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface PongMsg {
|
|
137
|
+
type: "pong";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export type AgentTranscriptServerMsg =
|
|
141
|
+
| AgentTranscriptEventsMsg
|
|
142
|
+
| AgentTranscriptErrorMsg
|
|
143
|
+
| AgentActivityMsg
|
|
144
|
+
| PongMsg;
|
|
145
|
+
|
|
146
|
+
// ---- Tuning constants, shared so client and server agree ----
|
|
147
|
+
|
|
148
|
+
export const MAX_TRANSCRIPT_SUBS_PER_CLIENT = 8;
|
|
149
|
+
export const MAX_TRANSCRIPT_SUBS_PER_SERVER = 64;
|
|
150
|
+
export const CATCH_UP_MAX_BYTES = 512 * 1024;
|
|
151
|
+
export const CATCH_UP_MAX_EVENTS = 500;
|
|
152
|
+
export const TOOL_OUTPUT_MAX_CHARS = 20_000;
|
|
153
|
+
export const LIVE_TICK_MS = 250;
|
|
154
|
+
export const IDLE_TICK_MS = 2_000;
|
|
155
|
+
export const IDLE_AFTER_MS = 30_000;
|
|
156
|
+
export const ACTIVITY_TICK_MS = 3_000;
|
|
157
|
+
export const ACTIVITY_WINDOW_MS = 90_000;
|
|
158
|
+
export const INDEX_REFRESH_MS = 2_000;
|
package/src/types/chat.ts
CHANGED
|
@@ -243,15 +243,39 @@ export type ResultSubtype =
|
|
|
243
243
|
| "error_auth";
|
|
244
244
|
|
|
245
245
|
export type ChatEvent =
|
|
246
|
-
| { type: "text"; content: string; parentToolUseId?: string }
|
|
247
|
-
| { type: "thinking"; content: string; parentToolUseId?: string }
|
|
246
|
+
| { type: "text"; content: string; parentToolUseId?: string; arrivalSeq?: number }
|
|
247
|
+
| { type: "thinking"; content: string; parentToolUseId?: string; arrivalSeq?: number }
|
|
248
248
|
| {
|
|
249
249
|
type: "tool_use"; tool: string; input: unknown; toolUseId?: string; parentToolUseId?: string; children?: ChatEvent[];
|
|
250
250
|
/** Terminal state of a backgrounded Agent/Task, once its `<task-notification>` arrives.
|
|
251
251
|
* Absent on a launched-but-unfinished agent — the card renders that as still running. */
|
|
252
252
|
bgStatus?: import("../shared/background-agent-status").BackgroundAgentStatus;
|
|
253
|
+
/** Agent/Task only: distinct child tool_use ids counted as "steps" so far — a Set-like
|
|
254
|
+
* array kept stable under a WS replay redelivering the same id. */
|
|
255
|
+
stepIds?: string[];
|
|
256
|
+
/** stepIds.length, cached alongside it so the one-line card need not measure the array. */
|
|
257
|
+
stepCount?: number;
|
|
258
|
+
/** Plain-text description of the most recent step, for the one-line card. */
|
|
259
|
+
lastStep?: string;
|
|
260
|
+
/** Set by a provider when an on-disk transcript was found for this card — its `children`
|
|
261
|
+
* are safe to reduce to the slimmed set because a session window can stream the rest
|
|
262
|
+
* from disk instead. Never set by the live stream itself. */
|
|
263
|
+
transcriptAvailable?: boolean;
|
|
264
|
+
/** Bounded ring buffer (last 200, or ~256KB serialized) of child events slimming would
|
|
265
|
+
* otherwise drop — the fallback shown in a window when no on-disk transcript exists at
|
|
266
|
+
* all, merged back with `children` in original arrival order via each entry's
|
|
267
|
+
* `arrivalSeq`. */
|
|
268
|
+
recentChildren?: ChatEvent[];
|
|
269
|
+
/** Monotonic counter this Agent/Task card's own `applyChildToParent` routing bumps once
|
|
270
|
+
* per incoming child — the source of `arrivalSeq` stamped onto each routed child. */
|
|
271
|
+
childSeq?: number;
|
|
272
|
+
/** Position among this child's siblings in the order they actually arrived — set when a
|
|
273
|
+
* child is routed by `applyChildToParent`/`pushRecentChild` with a parent's `childSeq`,
|
|
274
|
+
* so `children` and `recentChildren` (split apart by kept-vs-ring-buffer routing) can be
|
|
275
|
+
* merged back into arrival order instead of concatenated. */
|
|
276
|
+
arrivalSeq?: number;
|
|
253
277
|
}
|
|
254
|
-
| { type: "tool_result"; output: string; isError?: boolean; exitCode?: number; toolUseId?: string; parentToolUseId?: string }
|
|
278
|
+
| { type: "tool_result"; output: string; isError?: boolean; exitCode?: number; toolUseId?: string; parentToolUseId?: string; arrivalSeq?: number }
|
|
255
279
|
| { type: "approval_request"; requestId: string; tool: string; input: unknown }
|
|
256
280
|
| { type: "error"; message: string }
|
|
257
281
|
| { type: "done"; sessionId: string; resultSubtype?: ResultSubtype; numTurns?: number; contextWindowPct?: number; costUsd?: number; lastMessageUuid?: string; usage?: import("../shared/turn-usage").TurnUsage }
|
package/src/web/app.tsx
CHANGED
|
@@ -54,8 +54,8 @@ import { OnboardingRoot } from "@/components/onboarding/onboarding-root";
|
|
|
54
54
|
const MobileExplorerSheet = lazy(() =>
|
|
55
55
|
import("@/components/os-explorer/mobile/mobile-explorer-sheet").then((m) => ({ default: m.MobileExplorerSheet })),
|
|
56
56
|
);
|
|
57
|
-
const
|
|
58
|
-
import("@/components/chat/
|
|
57
|
+
const AgentSessionSheet = lazy(() =>
|
|
58
|
+
import("@/components/chat/agent-session-sheet").then((m) => ({ default: m.AgentSessionSheet })),
|
|
59
59
|
);
|
|
60
60
|
const RemoteDesktopMobileSheet = lazy(() =>
|
|
61
61
|
import("@/components/remote-desktop/remote-desktop-mobile-sheet").then((m) => ({ default: m.RemoteDesktopMobileSheet })),
|
|
@@ -390,12 +390,12 @@ export function App() {
|
|
|
390
390
|
<MobileExplorerSheet />
|
|
391
391
|
</Suspense>
|
|
392
392
|
|
|
393
|
-
{/* Mobile stand-in for the
|
|
393
|
+
{/* Mobile stand-in for the agent-session window, which WindowLayer never renders below md */}
|
|
394
394
|
<Suspense fallback={null}>
|
|
395
|
-
<
|
|
395
|
+
<AgentSessionSheet />
|
|
396
396
|
</Suspense>
|
|
397
397
|
|
|
398
|
-
{/* Mobile full-screen remote-desktop viewer — same reason as
|
|
398
|
+
{/* Mobile full-screen remote-desktop viewer — same reason as AgentSessionSheet above */}
|
|
399
399
|
<Suspense fallback={null}>
|
|
400
400
|
<RemoteDesktopMobileSheet />
|
|
401
401
|
</Suspense>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Agent/Task card's one-line row in chat: description (or teammate handle),
|
|
3
|
+
* step count, current step, status icon, and a tap that opens the live session
|
|
4
|
+
* window/sheet — no inline expansion, no long-press menu, tap only.
|
|
5
|
+
*
|
|
6
|
+
* `usePrefersCoarsePointer` (not `useIsMobile`) is what gates the 44 px minimum:
|
|
7
|
+
* a touch-capable desktop/tablet needs the bigger target just as much as a
|
|
8
|
+
* phone, and a mouse on a narrow desktop pane does not.
|
|
9
|
+
*/
|
|
10
|
+
import { Bot, ChevronRight, Loader2, CheckCircle2, XCircle, Users } from "@/lib/icons";
|
|
11
|
+
import { cn } from "@/lib/utils";
|
|
12
|
+
import { usePrefersCoarsePointer } from "@/components/os-explorer/use-coarse-long-press";
|
|
13
|
+
import { formatStepCount } from "@/lib/agent-step-summary";
|
|
14
|
+
|
|
15
|
+
export type AgentCardStatus = "running" | "done" | "error";
|
|
16
|
+
|
|
17
|
+
export interface AgentCardSummaryProps {
|
|
18
|
+
/** Teammate handle, when the card is addressable via SendMessage — leads the row. */
|
|
19
|
+
handle: string | null;
|
|
20
|
+
/** input.description/prompt, shown when there is no handle. */
|
|
21
|
+
description: string;
|
|
22
|
+
stepCount: number;
|
|
23
|
+
lastStep?: string;
|
|
24
|
+
status: AgentCardStatus;
|
|
25
|
+
/** Mirrors the pre-existing "running…" chip for a launched-but-unconfirmed background agent —
|
|
26
|
+
* distinct from `status === "running"`, which also covers an ordinary still-executing call. */
|
|
27
|
+
bgRunning?: boolean;
|
|
28
|
+
onOpen: () => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function AgentCardSummary({
|
|
32
|
+
handle, description, stepCount, lastStep, status, bgRunning, onOpen,
|
|
33
|
+
}: AgentCardSummaryProps) {
|
|
34
|
+
const coarse = usePrefersCoarsePointer();
|
|
35
|
+
const StatusIcon = status === "error" ? XCircle : status === "done" ? CheckCircle2 : Loader2;
|
|
36
|
+
const statusCls = status === "error" ? "text-error" : status === "done" ? "text-success" : "text-primary animate-spin";
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<button
|
|
40
|
+
type="button"
|
|
41
|
+
onClick={onOpen}
|
|
42
|
+
className={cn(
|
|
43
|
+
"flex w-full items-center gap-2.5 rounded-[11px] border border-border bg-panel px-2.5 text-left text-xs",
|
|
44
|
+
"transition-colors hover:bg-panel-2/40",
|
|
45
|
+
coarse ? "min-h-[44px] py-2" : "py-2",
|
|
46
|
+
)}
|
|
47
|
+
title={handle ? `Open ${handle}'s session` : "Open agent session"}
|
|
48
|
+
>
|
|
49
|
+
<span className={cn(
|
|
50
|
+
"inline-flex items-center justify-center size-6 rounded-[7px] shrink-0",
|
|
51
|
+
handle ? "bg-accent-2/15 text-accent-2" : "bg-accent-wash text-primary",
|
|
52
|
+
)}>
|
|
53
|
+
{handle ? <Users className="size-3.5" /> : <Bot className="size-3.5" />}
|
|
54
|
+
</span>
|
|
55
|
+
|
|
56
|
+
<span className="min-w-0 flex-1 truncate">
|
|
57
|
+
{handle
|
|
58
|
+
? <span className="font-medium text-text-primary">{handle}</span>
|
|
59
|
+
: <span className="font-medium text-text">{description || "Agent"}</span>}
|
|
60
|
+
{!!lastStep && (
|
|
61
|
+
<span className="text-text-subtle"> · {lastStep}</span>
|
|
62
|
+
)}
|
|
63
|
+
</span>
|
|
64
|
+
|
|
65
|
+
<span className="ml-auto flex items-center gap-2 shrink-0 text-text-3">
|
|
66
|
+
{bgRunning && <span className="text-[10px] text-primary">running…</span>}
|
|
67
|
+
{stepCount > 0 && <span className="font-mono text-[10px]">{formatStepCount(stepCount)}</span>}
|
|
68
|
+
<StatusIcon className={cn("size-3.5", statusCls)} />
|
|
69
|
+
<ChevronRight className="size-3" />
|
|
70
|
+
</span>
|
|
71
|
+
</button>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which session an Agent/Task card's one-line summary belongs to.
|
|
3
|
+
*
|
|
4
|
+
* `ToolCard`/`AgentCardSummary` need `{projectName, providerId, sessionId}` to
|
|
5
|
+
* build the `openAgentSession` payload, but a card has no such identity of its
|
|
6
|
+
* own — it only ever knows its `toolUseId`. `chat-tab.tsx` provides this once
|
|
7
|
+
* per conversation; a read-only surface with no real session (the group-chat
|
|
8
|
+
* transcript viewer) provides none, and the consumer falls back to a synthetic,
|
|
9
|
+
* never-resolvable identity so the card still opens in memory-only mode instead
|
|
10
|
+
* of doing nothing on tap.
|
|
11
|
+
*/
|
|
12
|
+
import { createContext, createElement, useContext, type ReactNode } from "react";
|
|
13
|
+
import type { AgentTranscriptProviderId } from "../../../shared/agent-transcript-protocol";
|
|
14
|
+
|
|
15
|
+
export interface AgentSessionIdentity {
|
|
16
|
+
projectName: string;
|
|
17
|
+
providerId: AgentTranscriptProviderId;
|
|
18
|
+
sessionId: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Claude and Codex are the only hubs that exist — anything else falls back to Claude. */
|
|
22
|
+
export function normalizeProviderId(id: string | undefined | null): AgentTranscriptProviderId {
|
|
23
|
+
return id === "codex" ? "codex" : "claude";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const AgentSessionContext = createContext<AgentSessionIdentity | null>(null);
|
|
27
|
+
|
|
28
|
+
export function useAgentSessionContext(): AgentSessionIdentity | null {
|
|
29
|
+
return useContext(AgentSessionContext);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function AgentSessionProvider({ value, children }: { value: AgentSessionIdentity; children: ReactNode }) {
|
|
33
|
+
return createElement(AgentSessionContext.Provider, { value }, children);
|
|
34
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Steps already held in chat memory, shown until (or unless) a window/sheet's live hub
|
|
3
|
+
* subscription takes over — seeded by the opener, since the window itself never had the
|
|
4
|
+
* chat's in-memory `children` array to fall back to.
|
|
5
|
+
*
|
|
6
|
+
* Pruned reactively rather than left to grow: every close/focus/open on the window store or
|
|
7
|
+
* the mobile sheet re-derives which keys are still on screen and drops the rest, so a
|
|
8
|
+
* session opened once and closed does not keep its whole event buffer alive for the rest of
|
|
9
|
+
* the page's life.
|
|
10
|
+
*/
|
|
11
|
+
import { create } from "zustand";
|
|
12
|
+
import { useWindowStore } from "@/components/floating-window/window-store";
|
|
13
|
+
import { useAgentSessionSheetStore } from "./agent-session-sheet-store";
|
|
14
|
+
import type { AgentTranscriptSourceKind } from "../../../shared/agent-transcript-protocol";
|
|
15
|
+
import type { ChatEvent } from "../../../types/chat";
|
|
16
|
+
|
|
17
|
+
export function fallbackKey(sessionId: string, source: AgentTranscriptSourceKind): string {
|
|
18
|
+
return source.kind === "card"
|
|
19
|
+
? `${sessionId}:${source.cardId}`
|
|
20
|
+
: `${sessionId}:${source.teamName}:${source.memberName}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface FallbackStoreState {
|
|
24
|
+
entries: Record<string, ChatEvent[]>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const useAgentSessionFallbackStore = create<FallbackStoreState>(() => ({ entries: {} }));
|
|
28
|
+
|
|
29
|
+
/** Called by the opener right before it opens a window/sheet for this key. */
|
|
30
|
+
export function setFallbackEvents(key: string, events: ChatEvent[]): void {
|
|
31
|
+
useAgentSessionFallbackStore.setState((s) => ({ entries: { ...s.entries, [key]: events } }));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function activeKeys(): Set<string> {
|
|
35
|
+
const keys = new Set<string>();
|
|
36
|
+
for (const win of Object.values(useWindowStore.getState().windows)) {
|
|
37
|
+
if (win.kind !== "agent-session") continue;
|
|
38
|
+
const p = win.payload as { sessionId?: unknown; source?: AgentTranscriptSourceKind } | undefined;
|
|
39
|
+
if (typeof p?.sessionId === "string" && p.source) keys.add(fallbackKey(p.sessionId, p.source));
|
|
40
|
+
}
|
|
41
|
+
const sheetPayload = useAgentSessionSheetStore.getState().payload;
|
|
42
|
+
if (sheetPayload) keys.add(fallbackKey(sheetPayload.sessionId, sheetPayload.source));
|
|
43
|
+
return keys;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function prune(): void {
|
|
47
|
+
const keep = activeKeys();
|
|
48
|
+
useAgentSessionFallbackStore.setState((s) => {
|
|
49
|
+
const entries: Record<string, ChatEvent[]> = {};
|
|
50
|
+
let changed = false;
|
|
51
|
+
for (const [key, events] of Object.entries(s.entries)) {
|
|
52
|
+
if (keep.has(key)) entries[key] = events;
|
|
53
|
+
else changed = true;
|
|
54
|
+
}
|
|
55
|
+
return changed ? { entries } : s;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
useWindowStore.subscribe(prune);
|
|
60
|
+
useAgentSessionSheetStore.subscribe(prune);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mobile-only: which agent/teammate session the full-screen sheet is showing, if any.
|
|
3
|
+
*
|
|
4
|
+
* Kept separate from `use-open-agent-session.ts` (unlike the old `team-member` stack, which
|
|
5
|
+
* had it inline) so `agent-session-fallback-store.ts` can read this store to decide what is
|
|
6
|
+
* still on screen without importing the opener — the opener already imports the fallback
|
|
7
|
+
* store to seed it on open, and a two-way import between them would make the eval order of
|
|
8
|
+
* two zustand `create()` calls load-bearing.
|
|
9
|
+
*/
|
|
10
|
+
import { create } from "zustand";
|
|
11
|
+
import type { AgentSessionWindowPayload } from "./agent-session-window-content";
|
|
12
|
+
|
|
13
|
+
interface AgentSessionSheetState {
|
|
14
|
+
payload: AgentSessionWindowPayload | null;
|
|
15
|
+
open: (payload: AgentSessionWindowPayload) => void;
|
|
16
|
+
close: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const useAgentSessionSheetStore = create<AgentSessionSheetState>((set) => ({
|
|
20
|
+
payload: null,
|
|
21
|
+
open: (payload) => set({ payload }),
|
|
22
|
+
close: () => set({ payload: null }),
|
|
23
|
+
}));
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Full-screen mobile presentation of
|
|
2
|
+
* Full-screen mobile presentation of an agent's or teammate's work session.
|
|
3
3
|
*
|
|
4
|
-
* Hosts the same content component the desktop floating window uses, so
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Hosts the same content component the desktop floating window uses, so steps, prompt and
|
|
5
|
+
* status are shared code rather than a parallel mobile build. Self-gated singleton, mounted
|
|
6
|
+
* once at the app root beside the other overlays.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { lazy, Suspense } from "react";
|
|
10
10
|
import { X } from "@/lib/icons";
|
|
11
11
|
import { BottomSheet } from "@/components/ui/mobile-bottom-sheet";
|
|
12
|
-
import {
|
|
12
|
+
import { useAgentSessionSheetStore } from "./agent-session-sheet-store";
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const AgentSessionWindowContent = lazy(() => import("./agent-session-window-content"));
|
|
15
15
|
|
|
16
|
-
export function
|
|
17
|
-
const payload =
|
|
18
|
-
const close =
|
|
16
|
+
export function AgentSessionSheet() {
|
|
17
|
+
const payload = useAgentSessionSheetStore((s) => s.payload);
|
|
18
|
+
const close = useAgentSessionSheetStore((s) => s.close);
|
|
19
19
|
if (!payload) return null;
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
22
|
<BottomSheet open onClose={close} zIndex={45} className="flex h-[var(--sheet-vh)] flex-col p-0">
|
|
23
23
|
<div className="flex items-center gap-2 border-b border-border px-3 py-2 shrink-0">
|
|
24
24
|
<span className="truncate text-sm font-medium text-text-primary">
|
|
25
|
-
|
|
25
|
+
{payload.title ?? "Agent session"}
|
|
26
26
|
</span>
|
|
27
27
|
<button
|
|
28
28
|
type="button"
|
|
@@ -36,8 +36,8 @@ export function TeamMemberSheet() {
|
|
|
36
36
|
<div className="min-h-0 flex-1 overflow-auto">
|
|
37
37
|
<Suspense fallback={<div className="p-4 text-sm text-text-2">Loading…</div>}>
|
|
38
38
|
{/* No floating window backs this sheet, so the id is only an identity for the content. */}
|
|
39
|
-
<
|
|
40
|
-
id={`sheet-${payload.
|
|
39
|
+
<AgentSessionWindowContent
|
|
40
|
+
id={`sheet-${payload.sessionId}`}
|
|
41
41
|
payload={payload as unknown as Record<string, unknown>}
|
|
42
42
|
/>
|
|
43
43
|
</Suspense>
|