@opengeni/react 1.0.1 → 1.0.2-canary.37191796234001
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/README.md +651 -21
- package/dist/accounts.d.ts +64 -0
- package/dist/accounts.js +822 -0
- package/dist/accounts.js.map +1 -0
- package/dist/approvals.d.ts +2 -1
- package/dist/artifacts-document.js +3 -2
- package/dist/artifacts-presentation.js +3 -2
- package/dist/artifacts-spreadsheet.js +2 -2
- package/dist/artifacts.d.ts +4 -1
- package/dist/artifacts.js +518 -42
- package/dist/artifacts.js.map +1 -1
- package/dist/browser-viewer-GTR5XQ7X.js +16 -0
- package/dist/capability-catalog-row.d.ts +20 -0
- package/dist/capability-logo-fallback.d.ts +3 -0
- package/dist/chat-interactive-block-UGBTNB3L.js +11 -0
- package/dist/chat-interactive-block-UGBTNB3L.js.map +1 -0
- package/dist/{chunk-5UQPNLIO.js → chunk-23J2ZNXT.js} +4117 -3896
- package/dist/chunk-23J2ZNXT.js.map +1 -0
- package/dist/chunk-447JLCBU.js +209 -0
- package/dist/chunk-447JLCBU.js.map +1 -0
- package/dist/chunk-4RVYOY4O.js +379 -0
- package/dist/chunk-4RVYOY4O.js.map +1 -0
- package/dist/chunk-5CVXZA3Y.js +292 -0
- package/dist/chunk-5CVXZA3Y.js.map +1 -0
- package/dist/chunk-5J4FOW6Q.js +108 -0
- package/dist/chunk-5J4FOW6Q.js.map +1 -0
- package/dist/chunk-A2PI6UMY.js +41 -0
- package/dist/chunk-A2PI6UMY.js.map +1 -0
- package/dist/{chunk-7WCLAEFV.js → chunk-A4UJB2MM.js} +37 -27
- package/dist/chunk-A4UJB2MM.js.map +1 -0
- package/dist/chunk-B3V6TG77.js +41 -0
- package/dist/chunk-B3V6TG77.js.map +1 -0
- package/dist/chunk-BRM6FVZA.js +302 -0
- package/dist/chunk-BRM6FVZA.js.map +1 -0
- package/dist/chunk-C5X5AJXK.js +182 -0
- package/dist/chunk-C5X5AJXK.js.map +1 -0
- package/dist/chunk-CR7U7HAR.js +453 -0
- package/dist/chunk-CR7U7HAR.js.map +1 -0
- package/dist/{chunk-R3AZOAB5.js → chunk-DYWBUX5Q.js} +29 -123
- package/dist/chunk-DYWBUX5Q.js.map +1 -0
- package/dist/chunk-E3G7SAYZ.js +3124 -0
- package/dist/chunk-E3G7SAYZ.js.map +1 -0
- package/dist/chunk-ELCE5SXV.js +359 -0
- package/dist/chunk-ELCE5SXV.js.map +1 -0
- package/dist/chunk-ERGYJIBB.js +21 -0
- package/dist/chunk-ERGYJIBB.js.map +1 -0
- package/dist/chunk-FFA2OVOV.js +319 -0
- package/dist/chunk-FFA2OVOV.js.map +1 -0
- package/dist/chunk-FZCP527Y.js +116 -0
- package/dist/chunk-FZCP527Y.js.map +1 -0
- package/dist/chunk-GIMRELBW.js +14 -0
- package/dist/chunk-GIMRELBW.js.map +1 -0
- package/dist/{chunk-6KLX2RH5.js → chunk-H2NJQORO.js} +1069 -79
- package/dist/chunk-H2NJQORO.js.map +1 -0
- package/dist/chunk-I7IWRQLN.js +1608 -0
- package/dist/chunk-I7IWRQLN.js.map +1 -0
- package/dist/{chunk-HA46CYQK.js → chunk-IQUCRAT7.js} +792 -537
- package/dist/chunk-IQUCRAT7.js.map +1 -0
- package/dist/chunk-IWIDV7SB.js +1 -0
- package/dist/chunk-IWIDV7SB.js.map +1 -0
- package/dist/chunk-J2QWVSQY.js +312 -0
- package/dist/chunk-J2QWVSQY.js.map +1 -0
- package/dist/chunk-JFNEV4LU.js +2733 -0
- package/dist/chunk-JFNEV4LU.js.map +1 -0
- package/dist/chunk-JT4JW7BC.js +54 -0
- package/dist/chunk-JT4JW7BC.js.map +1 -0
- package/dist/chunk-K3HQAKQX.js +24 -0
- package/dist/chunk-K3HQAKQX.js.map +1 -0
- package/dist/{chunk-C5ZPSSS5.js → chunk-NEXLLTP4.js} +2 -1
- package/dist/{chunk-C5ZPSSS5.js.map → chunk-NEXLLTP4.js.map} +1 -1
- package/dist/chunk-NZUI76EM.js +371 -0
- package/dist/chunk-NZUI76EM.js.map +1 -0
- package/dist/{chunk-PEI6RANI.js → chunk-PNY3JKBJ.js} +309 -74
- package/dist/chunk-PNY3JKBJ.js.map +1 -0
- package/dist/{chunk-IGC6A2ZI.js → chunk-Q5QBEZIQ.js} +777 -246
- package/dist/chunk-Q5QBEZIQ.js.map +1 -0
- package/dist/chunk-RHREZ7BO.js +11 -0
- package/dist/chunk-RHREZ7BO.js.map +1 -0
- package/dist/chunk-SCOTPE2I.js +589 -0
- package/dist/chunk-SCOTPE2I.js.map +1 -0
- package/dist/{chunk-B6WPZSTT.js → chunk-SJZDKVW2.js} +1331 -1163
- package/dist/chunk-SJZDKVW2.js.map +1 -0
- package/dist/chunk-TMJRG4YC.js +12803 -0
- package/dist/chunk-TMJRG4YC.js.map +1 -0
- package/dist/chunk-TMYGL6X5.js +742 -0
- package/dist/chunk-TMYGL6X5.js.map +1 -0
- package/dist/chunk-UGLEYEMP.js +33 -0
- package/dist/chunk-UGLEYEMP.js.map +1 -0
- package/dist/chunk-UK4TINKT.js +27 -0
- package/dist/chunk-UK4TINKT.js.map +1 -0
- package/dist/chunk-UTRTG6LH.js +220 -0
- package/dist/chunk-UTRTG6LH.js.map +1 -0
- package/dist/chunk-WEHMPOXK.js +39 -0
- package/dist/chunk-WEHMPOXK.js.map +1 -0
- package/dist/chunk-WRHIZYZF.js +988 -0
- package/dist/chunk-WRHIZYZF.js.map +1 -0
- package/dist/{chunk-HUIKIDM5.js → chunk-WUISZ3WU.js} +223 -115
- package/dist/chunk-WUISZ3WU.js.map +1 -0
- package/dist/chunk-XCHWDJ22.js +107 -0
- package/dist/chunk-XCHWDJ22.js.map +1 -0
- package/dist/chunk-XOAMRDDK.js +481 -0
- package/dist/chunk-XOAMRDDK.js.map +1 -0
- package/dist/chunk-XUW2UWQM.js +299 -0
- package/dist/chunk-XUW2UWQM.js.map +1 -0
- package/dist/{chunk-KCGXPP5V.js → chunk-Y2PRMYLC.js} +11 -6
- package/dist/chunk-Y2PRMYLC.js.map +1 -0
- package/dist/chunk-YBXQDQFX.js +1772 -0
- package/dist/chunk-YBXQDQFX.js.map +1 -0
- package/dist/{chunk-KZ73RL76.js → chunk-YQEAA6LT.js} +7 -3
- package/dist/chunk-YQEAA6LT.js.map +1 -0
- package/dist/chunk-YV4L3ILF.js +9 -0
- package/dist/chunk-YV4L3ILF.js.map +1 -0
- package/dist/{chunk-LLOLUHVG.js → chunk-YWFG7ZX7.js} +1358 -2746
- package/dist/chunk-YWFG7ZX7.js.map +1 -0
- package/dist/chunk-ZYRGEKWS.js +216 -0
- package/dist/chunk-ZYRGEKWS.js.map +1 -0
- package/dist/client.d.ts +7 -4
- package/dist/clipboard.js +1 -0
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/anthropic-mark.d.ts +3 -0
- package/dist/components/approval-surface.d.ts +15 -0
- package/dist/components/artifacts/artifact-chrome.d.ts +120 -0
- package/dist/components/artifacts/artifact-sandbox.d.ts +27 -0
- package/dist/components/artifacts/artifact-surface.d.ts +3 -1
- package/dist/components/artifacts/chat-interactive-block.d.ts +29 -0
- package/dist/components/artifacts/deferred-chat-media.d.ts +15 -0
- package/dist/components/artifacts/document-editor.d.ts +4 -2
- package/dist/components/artifacts/editable-artifact-ui.d.ts +2 -1
- package/dist/components/artifacts/editable-artifact-view.d.ts +46 -0
- package/dist/components/artifacts/editable-document.d.ts +1 -1
- package/dist/components/artifacts/editable-presentation.d.ts +2 -2
- package/dist/components/artifacts/editable-spreadsheet.d.ts +2 -1
- package/dist/components/artifacts/index.d.ts +8 -1
- package/dist/components/artifacts/inline-html-document.d.ts +2 -0
- package/dist/components/artifacts/latest-task-runner.d.ts +15 -0
- package/dist/components/artifacts/presentation-editor.d.ts +6 -2
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +48 -3
- package/dist/components/artifacts/session-artifact-viewer.d.ts +39 -0
- package/dist/components/artifacts/site-view.d.ts +23 -0
- package/dist/components/artifacts/spreadsheet-general-display.d.ts +24 -0
- package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
- package/dist/components/browser-select-control.d.ts +16 -0
- package/dist/components/browser-viewer.d.ts +10 -1
- package/dist/components/chat-composer.d.ts +21 -3
- package/dist/components/child-session-link.d.ts +5 -0
- package/dist/components/claude-mark.d.ts +3 -0
- package/dist/components/code-editor.d.ts +1 -4
- package/dist/components/composer.d.ts +45 -4
- package/dist/components/computer-viewer.d.ts +4 -1
- package/dist/components/copy-button.d.ts +3 -1
- package/dist/components/desktop-viewer.d.ts +1 -1
- package/dist/components/enrollment-consent.d.ts +6 -3
- package/dist/components/file-browser.d.ts +10 -1
- package/dist/components/fleet-tile.d.ts +2 -2
- package/dist/components/grok-mark.d.ts +26 -0
- package/dist/components/human-input-form.d.ts +21 -2
- package/dist/components/human-input-surface.d.ts +6 -3
- package/dist/components/machine-card.d.ts +4 -1
- package/dist/components/machines/machine-detail.d.ts +4 -1
- package/dist/components/machines/machine-operation-policy.d.ts +11 -0
- package/dist/components/machines-dashboard.d.ts +3 -1
- package/dist/components/markdown-table-layout.d.ts +12 -0
- package/dist/components/markdown.d.ts +47 -3
- package/dist/components/message-timeline.d.ts +72 -9
- package/dist/components/model-mark.d.ts +29 -0
- package/dist/components/model-policy-picker-menu.d.ts +9 -0
- package/dist/components/model-policy-picker.d.ts +62 -13
- package/dist/components/open-geni-chat.d.ts +55 -0
- package/dist/components/open-geni-links.d.ts +68 -0
- package/dist/components/openrouter-mark.d.ts +6 -0
- package/dist/components/pierre-file.d.ts +1 -1
- package/dist/components/preview-loading.d.ts +2 -0
- package/dist/components/queue-item-content.d.ts +9 -0
- package/dist/components/sandbox-files.d.ts +13 -2
- package/dist/components/sandbox-workspace.d.ts +43 -3
- package/dist/components/session-capability-frame.d.ts +35 -0
- package/dist/components/session-chrome.d.ts +66 -8
- package/dist/components/session-commands-panel.d.ts +6 -0
- package/dist/components/session-commands.d.ts +6 -0
- package/dist/components/session-connection-request.d.ts +8 -0
- package/dist/components/session-conversation.d.ts +86 -0
- package/dist/components/session-list.d.ts +36 -0
- package/dist/components/session-mcp-capability-card.d.ts +41 -0
- package/dist/components/timeline-anchor.d.ts +24 -0
- package/dist/components/timeline-annotation-chrome.d.ts +25 -0
- package/dist/components/timeline-annotation-layout.d.ts +42 -0
- package/dist/components/timeline-annotation-markers.d.ts +8 -0
- package/dist/components/timeline-annotation-reveal-context.d.ts +4 -0
- package/dist/components/timeline-annotation-shared.d.ts +31 -0
- package/dist/components/timeline-annotations-dialog.d.ts +3 -2
- package/dist/components/timeline-annotations.d.ts +13 -3
- package/dist/components/timeline-reading-progress.d.ts +11 -0
- package/dist/components/timeline-search.d.ts +34 -0
- package/dist/components/timeline-settlement.d.ts +16 -0
- package/dist/components/tip-follow.d.ts +16 -0
- package/dist/components/usage-limit-notice.d.ts +49 -0
- package/dist/components/usage-member-list.d.ts +91 -0
- package/dist/components/usage-meter.d.ts +73 -0
- package/dist/components/use-viewer-menu-dismiss.d.ts +2 -0
- package/dist/components/user-message-body.d.ts +10 -1
- package/dist/components/workspace-dock.d.ts +6 -2
- package/dist/composer.d.ts +5 -4
- package/dist/composer.js +15 -9
- package/dist/computer-viewer-ENHVAZ2Q.js +19 -0
- package/dist/computer-viewer-ENHVAZ2Q.js.map +1 -0
- package/dist/connect-account-identity.d.ts +8 -0
- package/dist/connect-accounts.d.ts +15 -0
- package/dist/connect-chooser.d.ts +18 -0
- package/dist/connect-panel.d.ts +18 -0
- package/dist/connect-setup.d.ts +16 -0
- package/dist/connect.d.ts +21 -0
- package/dist/connect.js +2129 -0
- package/dist/connect.js.map +1 -0
- package/dist/connection-catalog.d.ts +38 -0
- package/dist/connection-discovery.d.ts +12 -0
- package/dist/connection-installed.d.ts +17 -0
- package/dist/connection-logo.d.ts +9 -0
- package/dist/connection-service-logo.d.ts +8 -0
- package/dist/connection-service-presentation.d.ts +13 -0
- package/dist/connection-skeleton.d.ts +5 -0
- package/dist/connection-type-picker.d.ts +6 -0
- package/dist/conversation-timeline.d.ts +5 -0
- package/dist/desktop.d.ts +7 -0
- package/dist/desktop.js +26 -0
- package/dist/desktop.js.map +1 -0
- package/dist/device-authorization.d.ts +23 -0
- package/dist/diffs.d.ts +8 -0
- package/dist/diffs.js +14 -0
- package/dist/diffs.js.map +1 -0
- package/dist/discovery-cache.d.ts +5 -0
- package/dist/editor.d.ts +7 -0
- package/dist/editor.js +21 -0
- package/dist/editor.js.map +1 -0
- package/dist/embedded-session-client.d.ts +23 -0
- package/dist/file-node-visibility.d.ts +15 -0
- package/dist/{fleet-decision-row-GGCAT4E4.js → fleet-decision-row-YZ3ZKWMM.js} +2 -1
- package/dist/fleet-decision-row-YZ3ZKWMM.js.map +1 -0
- package/dist/hooks/channel-cache.d.ts +23 -0
- package/dist/hooks/latest-question.d.ts +25 -0
- package/dist/hooks/shared-machines-list.d.ts +14 -0
- package/dist/hooks/use-attached-browsers.d.ts +2 -1
- package/dist/hooks/use-browser-frame-stream.d.ts +1 -1
- package/dist/hooks/use-browser-session.d.ts +12 -1
- package/dist/hooks/use-channels.d.ts +1 -0
- package/dist/hooks/use-codex-accounts.d.ts +25 -7
- package/dist/hooks/use-composer.d.ts +45 -9
- package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
- package/dist/hooks/use-computer-input-posture.d.ts +13 -0
- package/dist/hooks/use-computer-session.d.ts +2 -0
- package/dist/hooks/use-connect.d.ts +22 -0
- package/dist/hooks/use-desktop-stream.d.ts +1 -1
- package/dist/hooks/use-file-attachments.d.ts +21 -2
- package/dist/hooks/use-machine-chip.d.ts +3 -3
- package/dist/hooks/use-machines.d.ts +19 -1
- package/dist/hooks/use-sandbox-files.d.ts +5 -1
- package/dist/hooks/use-session-background-commands.d.ts +14 -0
- package/dist/hooks/use-session-events.d.ts +30 -8
- package/dist/hooks/use-session-lineage.d.ts +4 -0
- package/dist/hooks/use-session-mcp-approval-policy.d.ts +2 -2
- package/dist/hooks/use-session.d.ts +6 -0
- package/dist/hooks/use-turn-queue.d.ts +12 -0
- package/dist/hooks/use-usage.d.ts +40 -0
- package/dist/hooks/use-workspace-edit.d.ts +4 -0
- package/dist/hooks/use-workspace-sessions.d.ts +27 -5
- package/dist/human-input.d.ts +3 -1
- package/dist/identity-link-accounts.d.ts +11 -0
- package/dist/identity-link-consent.d.ts +18 -0
- package/dist/index.d.ts +60 -17
- package/dist/index.js +2237 -6200
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +1 -1
- package/dist/interaction.js +35 -184
- package/dist/interaction.js.map +1 -1
- package/dist/latest-question-755OW5DS.js +117 -0
- package/dist/latest-question-755OW5DS.js.map +1 -0
- package/dist/lib/error-message.d.ts +7 -0
- package/dist/lib/format.d.ts +36 -2
- package/dist/lib/host-theme.d.ts +70 -0
- package/dist/lib/interaction-errors.d.ts +6 -0
- package/dist/lib/menu-styles.d.ts +22 -0
- package/dist/lib/pierre-diffs-loader.d.ts +20 -0
- package/dist/lib/workbench-peers.d.ts +36 -0
- package/dist/lib/xterm-theme.d.ts +7 -5
- package/dist/machines.d.ts +4 -2
- package/dist/machines.js +14 -4
- package/dist/markdown-table-layout-QXSLK4BY.js +106 -0
- package/dist/markdown-table-layout-QXSLK4BY.js.map +1 -0
- package/dist/mcp-connection-status.d.ts +14 -0
- package/dist/model-policy-picker-menu-PWRI7R2X.js +14 -0
- package/dist/model-policy-picker-menu-PWRI7R2X.js.map +1 -0
- package/dist/model-policy.d.ts +19 -3
- package/dist/model-policy.js +9 -1
- package/dist/older-history.d.ts +30 -0
- package/dist/platform-activity-row-627BFZ46.js +182 -0
- package/dist/platform-activity-row-627BFZ46.js.map +1 -0
- package/dist/plugin-details.d.ts +14 -0
- package/dist/plugin-discovery.d.ts +25 -0
- package/dist/provider.d.ts +13 -1
- package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-ZHFI5JBP.js} +131 -44
- package/dist/queue-surface-implementation-ZHFI5JBP.js.map +1 -0
- package/dist/realtime/realtime-control.d.ts +6 -3
- package/dist/realtime.js +133 -74
- package/dist/realtime.js.map +1 -1
- package/dist/sandbox-files-BBC47SLD.js +20 -0
- package/dist/sandbox-files-BBC47SLD.js.map +1 -0
- package/dist/session-auth-recommendation.d.ts +5 -0
- package/dist/session-capability-policy.d.ts +12 -0
- package/dist/session-ui.d.ts +30 -2
- package/dist/session-ui.js +85 -7
- package/dist/session-ui.js.map +1 -1
- package/dist/session.d.ts +8 -2
- package/dist/session.js +30 -19
- package/dist/sites-ui.d.ts +34 -0
- package/dist/sites.d.ts +3 -0
- package/dist/sites.js +11 -0
- package/dist/sites.js.map +1 -0
- package/dist/skill-discovery.d.ts +47 -0
- package/dist/terminal.d.ts +8 -0
- package/dist/terminal.js +31 -0
- package/dist/terminal.js.map +1 -0
- package/dist/timeline/activity-rail.d.ts +11 -2
- package/dist/timeline/allowance-exhausted-row.d.ts +24 -0
- package/dist/timeline/compaction-copy.d.ts +10 -0
- package/dist/timeline/entrance.d.ts +13 -1
- package/dist/timeline/genie-loading.d.ts +34 -0
- package/dist/timeline/index.d.ts +6 -2
- package/dist/timeline/knowledge-receipt.d.ts +17 -0
- package/dist/timeline/platform-activity-row.d.ts +14 -0
- package/dist/timeline/presented-image.d.ts +6 -0
- package/dist/timeline/projection.d.ts +31 -2
- package/dist/timeline/registry.d.ts +2 -0
- package/dist/timeline/retained-image.d.ts +18 -0
- package/dist/timeline/rolling-activity.d.ts +11 -0
- package/dist/timeline/screenshot-lightbox.d.ts +16 -1
- package/dist/timeline/shared.d.ts +8 -3
- package/dist/timeline/startup-preference.d.ts +3 -0
- package/dist/timeline/startup-timings.d.ts +4 -0
- package/dist/timeline/tool-display-name.d.ts +2 -1
- package/dist/timeline/turn-summary.d.ts +32 -3
- package/dist/timeline/types.d.ts +141 -7
- package/dist/timeline-annotation-markers-GNDHTGBD.js +165 -0
- package/dist/timeline-annotation-markers-GNDHTGBD.js.map +1 -0
- package/dist/timeline-annotation-selection-DMLMM2TX.js +241 -0
- package/dist/timeline-annotation-selection-DMLMM2TX.js.map +1 -0
- package/dist/timeline-annotations-dialog-ELRDBHTS.js +273 -0
- package/dist/timeline-annotations-dialog-ELRDBHTS.js.map +1 -0
- package/dist/types/machines.d.ts +2 -2
- package/dist/usage/allowance-copy.d.ts +25 -0
- package/dist/usage/summary.d.ts +35 -0
- package/dist/usage.d.ts +13 -0
- package/dist/usage.js +1074 -0
- package/dist/usage.js.map +1 -0
- package/package.json +44 -4
- package/src/accounts.tsx +1072 -0
- package/src/approvals.ts +8 -1
- package/src/artifacts.ts +42 -0
- package/src/assets/README.md +8 -0
- package/src/assets/gmail.ico +0 -0
- package/src/assets/outlook.ico +0 -0
- package/src/capability-catalog-row.tsx +94 -0
- package/src/capability-logo-fallback.ts +22 -0
- package/src/client.ts +22 -13
- package/src/commands/registry.ts +18 -15
- package/src/commands/types.ts +2 -0
- package/src/components/anthropic-mark.tsx +10 -0
- package/src/components/approval-surface.tsx +171 -37
- package/src/components/artifacts/artifact-chrome.tsx +413 -0
- package/src/components/artifacts/artifact-sandbox.tsx +185 -0
- package/src/components/artifacts/artifact-surface.tsx +39 -19
- package/src/components/artifacts/chat-interactive-block.tsx +260 -0
- package/src/components/artifacts/deferred-chat-media.tsx +67 -0
- package/src/components/artifacts/document-editor.tsx +141 -16
- package/src/components/artifacts/editable-artifact-ui.tsx +4 -2
- package/src/components/artifacts/editable-artifact-view.tsx +187 -0
- package/src/components/artifacts/editable-artifact-workbench.tsx +5 -2
- package/src/components/artifacts/editable-document.tsx +37 -36
- package/src/components/artifacts/editable-presentation.tsx +36 -18
- package/src/components/artifacts/editable-spreadsheet.tsx +5 -2
- package/src/components/artifacts/index.ts +44 -0
- package/src/components/artifacts/inline-html-document.ts +24 -0
- package/src/components/artifacts/latest-task-runner.ts +49 -0
- package/src/components/artifacts/presentation-editor.tsx +323 -67
- package/src/components/artifacts/published-html-artifact-frame.tsx +338 -5
- package/src/components/artifacts/session-artifact-viewer.tsx +376 -0
- package/src/components/artifacts/site-view.tsx +116 -0
- package/src/components/artifacts/spreadsheet-canvas.ts +5 -10
- package/src/components/artifacts/spreadsheet-general-display.ts +43 -0
- package/src/components/artifacts/spreadsheet-grid.tsx +12 -13
- package/src/components/artifacts/visualization-assets/base.css +1015 -0
- package/src/components/artifacts/visualization-assets/helpers.html +349 -0
- package/src/components/artifacts/visualization-assets.gen.ts +3 -0
- package/src/components/browser-select-control.tsx +312 -0
- package/src/components/browser-viewer.tsx +1054 -314
- package/src/components/chat-composer.tsx +131 -85
- package/src/components/child-session-link.tsx +27 -0
- package/src/components/claude-mark.tsx +10 -0
- package/src/components/code-editor.tsx +13 -16
- package/src/components/composer-transcription-control.tsx +7 -5
- package/src/components/composer.tsx +376 -49
- package/src/components/computer-viewer.tsx +1041 -329
- package/src/components/copy-button.tsx +13 -5
- package/src/components/desktop-viewer.tsx +1 -1
- package/src/components/enrollment-consent.tsx +65 -7
- package/src/components/enrollment-device-flow.tsx +1 -1
- package/src/components/file-browser.tsx +158 -34
- package/src/components/fleet-tile.tsx +8 -16
- package/src/components/generated-video-player.tsx +4 -2
- package/src/components/grok-mark.tsx +33 -0
- package/src/components/human-input-form.tsx +455 -114
- package/src/components/human-input-surface.tsx +18 -7
- package/src/components/interaction-intervention-banner.tsx +2 -2
- package/src/components/machine-card.tsx +119 -4
- package/src/components/machine-dock-bar.tsx +1 -1
- package/src/components/machine-input-display.ts +23 -2
- package/src/components/machines/machine-detail.tsx +52 -2
- package/src/components/machines/machine-operation-policy.tsx +179 -0
- package/src/components/machines-dashboard.tsx +8 -17
- package/src/components/markdown-table-layout.ts +132 -0
- package/src/components/markdown.tsx +473 -44
- package/src/components/message-timeline.tsx +2498 -663
- package/src/components/model-mark.tsx +90 -0
- package/src/components/model-picker.tsx +15 -4
- package/src/components/model-policy-picker-menu.tsx +424 -0
- package/src/components/model-policy-picker.tsx +337 -381
- package/src/components/open-geni-chat.tsx +319 -0
- package/src/components/open-geni-links.tsx +179 -0
- package/src/components/openrouter-mark.tsx +13 -0
- package/src/components/pierre-diff.tsx +41 -16
- package/src/components/pierre-file.tsx +36 -11
- package/src/components/preview-loading.tsx +154 -0
- package/src/components/queue-item-content.ts +14 -0
- package/src/components/queue-surface-implementation.tsx +132 -42
- package/src/components/queue-surface-state.tsx +3 -1
- package/src/components/sandbox-files.tsx +267 -35
- package/src/components/sandbox-terminal.tsx +48 -11
- package/src/components/sandbox-workspace.tsx +337 -135
- package/src/components/session-capability-frame.tsx +192 -0
- package/src/components/session-chrome.tsx +1027 -328
- package/src/components/session-commands-panel.tsx +126 -0
- package/src/components/session-commands.tsx +18 -0
- package/src/components/session-connection-request.tsx +97 -0
- package/src/components/session-conversation.tsx +512 -0
- package/src/components/session-list.tsx +250 -0
- package/src/components/session-mcp-capability-card.tsx +680 -0
- package/src/components/session-status.tsx +1 -1
- package/src/components/timeline-anchor.tsx +119 -0
- package/src/components/timeline-annotation-chrome.tsx +196 -0
- package/src/components/timeline-annotation-layout.ts +268 -0
- package/src/components/timeline-annotation-markers.tsx +185 -0
- package/src/components/timeline-annotation-reveal-context.ts +9 -0
- package/src/components/timeline-annotation-selection.tsx +106 -54
- package/src/components/timeline-annotation-shared.ts +245 -0
- package/src/components/timeline-annotations-dialog.tsx +185 -128
- package/src/components/timeline-annotations.tsx +189 -45
- package/src/components/timeline-reading-progress.ts +80 -0
- package/src/components/timeline-search.tsx +168 -0
- package/src/components/timeline-settlement.ts +60 -0
- package/src/components/tip-follow.ts +70 -7
- package/src/components/tooltip.tsx +38 -5
- package/src/components/usage-limit-notice.tsx +179 -0
- package/src/components/usage-member-list.tsx +792 -0
- package/src/components/usage-meter.tsx +382 -0
- package/src/components/use-viewer-menu-dismiss.ts +33 -0
- package/src/components/user-message-body.tsx +194 -49
- package/src/components/workspace-dock.tsx +141 -175
- package/src/composer.ts +6 -1
- package/src/connect-account-identity.tsx +34 -0
- package/src/connect-accounts.tsx +233 -0
- package/src/connect-chooser.tsx +336 -0
- package/src/connect-panel.tsx +99 -0
- package/src/connect-setup.tsx +307 -0
- package/src/connect.ts +60 -0
- package/src/connection-assets.d.ts +4 -0
- package/src/connection-catalog.tsx +162 -0
- package/src/connection-discovery.tsx +235 -0
- package/src/connection-installed.tsx +51 -0
- package/src/connection-logo.tsx +37 -0
- package/src/connection-service-logo.tsx +55 -0
- package/src/connection-service-presentation.ts +46 -0
- package/src/connection-skeleton.tsx +16 -0
- package/src/connection-type-picker.tsx +36 -0
- package/src/conversation-timeline.ts +92 -0
- package/src/desktop.ts +24 -0
- package/src/device-authorization.tsx +98 -0
- package/src/diffs.ts +16 -0
- package/src/discovery-cache.ts +42 -0
- package/src/editor.ts +13 -0
- package/src/embedded-session-client.ts +104 -0
- package/src/file-node-visibility.ts +66 -0
- package/src/hooks/channel-cache.ts +104 -0
- package/src/hooks/internal.ts +3 -2
- package/src/hooks/latest-question.ts +164 -0
- package/src/hooks/shared-machines-list.ts +239 -0
- package/src/hooks/use-attached-browsers.ts +5 -1
- package/src/hooks/use-available-models.ts +20 -14
- package/src/hooks/use-browser-frame-stream.ts +25 -3
- package/src/hooks/use-browser-session.ts +271 -71
- package/src/hooks/use-browser-sessions.ts +7 -1
- package/src/hooks/use-channels.ts +32 -10
- package/src/hooks/use-codex-accounts.ts +78 -21
- package/src/hooks/use-composer.ts +1034 -320
- package/src/hooks/use-computer-frame-stream.ts +39 -16
- package/src/hooks/use-computer-input-posture.ts +94 -0
- package/src/hooks/use-computer-session.ts +110 -32
- package/src/hooks/use-computer-sessions.ts +8 -1
- package/src/hooks/use-connect.ts +23 -0
- package/src/hooks/use-desktop-stream.ts +19 -28
- package/src/hooks/use-file-attachments.ts +118 -10
- package/src/hooks/use-goal.ts +36 -9
- package/src/hooks/use-human-input.ts +31 -4
- package/src/hooks/use-last-started-turn-policy.ts +15 -13
- package/src/hooks/use-machine-chip.ts +23 -6
- package/src/hooks/use-machines.ts +104 -6
- package/src/hooks/use-sandbox-files.ts +253 -150
- package/src/hooks/use-sandbox-git.ts +58 -29
- package/src/hooks/use-session-background-commands.ts +67 -0
- package/src/hooks/use-session-capabilities.ts +21 -2
- package/src/hooks/use-session-events.ts +759 -433
- package/src/hooks/use-session-lineage.ts +28 -6
- package/src/hooks/use-session-mcp-approval-policy.ts +13 -5
- package/src/hooks/use-session.ts +75 -16
- package/src/hooks/use-slash-commands.ts +6 -11
- package/src/hooks/use-turn-queue.ts +113 -13
- package/src/hooks/use-usage.ts +100 -0
- package/src/hooks/use-voice-input.ts +12 -1
- package/src/hooks/use-workspace-capture.ts +3 -2
- package/src/hooks/use-workspace-edit.ts +23 -5
- package/src/hooks/use-workspace-sessions.ts +99 -11
- package/src/human-input.ts +12 -1
- package/src/identity-link-accounts.tsx +148 -0
- package/src/identity-link-consent.tsx +192 -0
- package/src/index.ts +157 -12
- package/src/interaction.ts +1 -0
- package/src/lib/error-message.ts +37 -0
- package/src/lib/format.ts +150 -14
- package/src/lib/host-theme.ts +511 -0
- package/src/lib/interaction-errors.ts +33 -0
- package/src/lib/menu-styles.ts +44 -0
- package/src/lib/pierre-diffs-loader.ts +53 -0
- package/src/lib/workbench-peers.ts +62 -0
- package/src/lib/xterm-theme.ts +23 -21
- package/src/machines.ts +9 -1
- package/src/mcp-connection-status.ts +35 -0
- package/src/model-policy.ts +223 -69
- package/src/older-history.ts +87 -0
- package/src/plugin-details.tsx +185 -0
- package/src/plugin-discovery.tsx +196 -0
- package/src/provider.tsx +55 -14
- package/src/realtime/dropdown-menu.tsx +19 -12
- package/src/realtime/realtime-control.tsx +133 -46
- package/src/session-auth-recommendation.ts +48 -0
- package/src/session-capability-policy.ts +83 -0
- package/src/session-context.ts +1 -0
- package/src/session-ui.ts +66 -2
- package/src/session.ts +18 -1
- package/src/sites-ui.tsx +402 -0
- package/src/sites.ts +3 -0
- package/src/skill-discovery.tsx +208 -0
- package/src/terminal.ts +26 -0
- package/src/timeline/activity-rail.tsx +171 -80
- package/src/timeline/allowance-exhausted-row.tsx +86 -0
- package/src/timeline/compaction-copy.ts +42 -0
- package/src/timeline/entrance.tsx +28 -3
- package/src/timeline/fleet-decision-projection.ts +2 -1
- package/src/timeline/fleet-decision-row.tsx +1 -0
- package/src/timeline/genie-loading.tsx +136 -0
- package/src/timeline/index.ts +11 -0
- package/src/timeline/knowledge-receipt.tsx +100 -0
- package/src/timeline/parsers.ts +2 -2
- package/src/timeline/platform-activity-row.tsx +216 -0
- package/src/timeline/presented-image.ts +49 -0
- package/src/timeline/projection.ts +1600 -84
- package/src/timeline/registry.ts +15 -3
- package/src/timeline/retained-image.ts +97 -0
- package/src/timeline/rolling-activity.tsx +92 -0
- package/src/timeline/screenshot-lightbox.tsx +115 -17
- package/src/timeline/shared.tsx +47 -15
- package/src/timeline/startup-preference.ts +33 -0
- package/src/timeline/startup-timings.tsx +145 -0
- package/src/timeline/tool-display-name.ts +8 -6
- package/src/timeline/tool-renderers.tsx +497 -128
- package/src/timeline/turn-summary.tsx +208 -44
- package/src/timeline/types.ts +186 -7
- package/src/types/machines.ts +10 -0
- package/src/usage/allowance-copy.ts +64 -0
- package/src/usage/summary.ts +93 -0
- package/src/usage.ts +50 -0
- package/styles/compiled.css +2098 -757
- package/styles/connect.css +284 -0
- package/styles/connect.d.ts +1 -0
- package/styles/effective-tokens.css +1 -0
- package/styles/index.css +201 -9
- package/styles/responsive.css +27 -1
- package/styles/session-capability.css +44 -0
- package/styles/tokens.css +135 -65
- package/dist/chunk-5UQPNLIO.js.map +0 -1
- package/dist/chunk-6KLX2RH5.js.map +0 -1
- package/dist/chunk-7WCLAEFV.js.map +0 -1
- package/dist/chunk-B6WPZSTT.js.map +0 -1
- package/dist/chunk-FK6VG4LL.js +0 -90
- package/dist/chunk-FK6VG4LL.js.map +0 -1
- package/dist/chunk-HA46CYQK.js.map +0 -1
- package/dist/chunk-HUIKIDM5.js.map +0 -1
- package/dist/chunk-IGC6A2ZI.js.map +0 -1
- package/dist/chunk-KCGXPP5V.js.map +0 -1
- package/dist/chunk-KZ73RL76.js.map +0 -1
- package/dist/chunk-LAKLF4PA.js +0 -141
- package/dist/chunk-LAKLF4PA.js.map +0 -1
- package/dist/chunk-LLOLUHVG.js.map +0 -1
- package/dist/chunk-MKPIAGVL.js +0 -465
- package/dist/chunk-MKPIAGVL.js.map +0 -1
- package/dist/chunk-PEI6RANI.js.map +0 -1
- package/dist/chunk-R3AZOAB5.js.map +0 -1
- package/dist/chunk-WSK7G5LE.js +0 -170
- package/dist/chunk-WSK7G5LE.js.map +0 -1
- package/dist/chunk-XBZWOM2K.js +0 -218
- package/dist/chunk-XBZWOM2K.js.map +0 -1
- package/dist/chunk-Y7OEDUJ5.js +0 -8810
- package/dist/chunk-Y7OEDUJ5.js.map +0 -1
- package/dist/fleet-decision-row-GGCAT4E4.js.map +0 -1
- package/dist/hooks/use-packs.d.ts +0 -32
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
- package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
- package/dist/timeline-annotation-selection-3L7LHGG2.js +0 -187
- package/dist/timeline-annotation-selection-3L7LHGG2.js.map +0 -1
- package/dist/timeline-annotations-dialog-U7EVLR75.js +0 -196
- package/dist/timeline-annotations-dialog-U7EVLR75.js.map +0 -1
- package/src/hooks/use-packs.ts +0 -157
- /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-GTR5XQ7X.js.map} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
FileSystemRouteIdentity,
|
|
2
3
|
FsChangedPayload,
|
|
3
4
|
FsReadResponse,
|
|
4
5
|
FsTreeNode,
|
|
@@ -65,7 +66,8 @@ export type SandboxWriteFileOptions = {
|
|
|
65
66
|
/** A node in the Pierre file tree. `children === undefined` ⇒ an unexpanded dir
|
|
66
67
|
* (lazy treeMode); `children: []` ⇒ an expanded-but-empty dir. */
|
|
67
68
|
export type FileTreeNode = {
|
|
68
|
-
path
|
|
69
|
+
/** Opaque path returned by the selected target's FileSystem boundary. */
|
|
70
|
+
path: string;
|
|
69
71
|
name: string;
|
|
70
72
|
kind: "file" | "dir";
|
|
71
73
|
children?: FileTreeNode[] | undefined;
|
|
@@ -83,6 +85,9 @@ export type UseSandboxFilesOptions = ClientOverride & {
|
|
|
83
85
|
events?: SessionEvent[] | undefined;
|
|
84
86
|
/** Initial path to list (workspace root by default). */
|
|
85
87
|
rootPath?: string | undefined;
|
|
88
|
+
/** Exact capability identity for the selected filesystem route. A route/root
|
|
89
|
+
* change resets this hook and makes stale provider requests fail retryably. */
|
|
90
|
+
route?: FileSystemRouteIdentity | undefined;
|
|
86
91
|
/** Hold off the initial list (e.g. panel collapsed). Default true. */
|
|
87
92
|
enabled?: boolean | undefined;
|
|
88
93
|
/** Pause live reads/invalidation while preserving the last rendered result. */
|
|
@@ -162,16 +167,25 @@ export type SandboxFilesGitSummary = {
|
|
|
162
167
|
};
|
|
163
168
|
|
|
164
169
|
function normalizeRoot(root: string): string {
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
.replace(/\/+$/, "");
|
|
170
|
+
const slashNormalized = root.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
171
|
+
if (slashNormalized === "/") return "/";
|
|
172
|
+
const normalized = slashNormalized.replace(/\/+$/, "");
|
|
169
173
|
return normalized === "." ? "" : normalized;
|
|
170
174
|
}
|
|
171
175
|
|
|
172
|
-
function
|
|
176
|
+
function isAbsoluteTreePath(path: string): boolean {
|
|
177
|
+
return path.startsWith("/") || /^[A-Za-z]:\//u.test(path);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function joinTreeRoot(root: string, path: string): string {
|
|
181
|
+
if (!root || isAbsoluteTreePath(path)) return path;
|
|
182
|
+
return root === "/" ? `/${path}` : `${root}/${path}`;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function qualifyStatusPath(root: string, path: string, treeRoot: string): string {
|
|
173
186
|
const normalized = normalizeRoot(root);
|
|
174
|
-
|
|
187
|
+
const workspaceRelative = joinTreeRoot(normalized, path);
|
|
188
|
+
return joinTreeRoot(normalizeRoot(treeRoot), workspaceRelative);
|
|
175
189
|
}
|
|
176
190
|
|
|
177
191
|
function summarizeStatuses(
|
|
@@ -194,6 +208,11 @@ function parentOf(path: string): string {
|
|
|
194
208
|
return i <= 0 ? "" : path.slice(0, i);
|
|
195
209
|
}
|
|
196
210
|
|
|
211
|
+
function parentWithinTree(path: string, rootPath: string): string {
|
|
212
|
+
const parent = parentOf(path);
|
|
213
|
+
return parent === "" && normalizeRoot(rootPath) === "/" && path.startsWith("/") ? "/" : parent;
|
|
214
|
+
}
|
|
215
|
+
|
|
197
216
|
/** The leaf name of a POSIX path. */
|
|
198
217
|
function leafOf(path: string): string {
|
|
199
218
|
const i = path.lastIndexOf("/");
|
|
@@ -282,33 +301,23 @@ function findNodeByPath(nodes: FileTreeNode[], path: string): FileTreeNode | und
|
|
|
282
301
|
return undefined;
|
|
283
302
|
}
|
|
284
303
|
|
|
285
|
-
|
|
286
|
-
* this small visible frontier refreshes agent shell edits without expanding or
|
|
287
|
-
* traversing hidden directories. */
|
|
288
|
-
function loadedDirectoryPaths(nodes: FileTreeNode[]): string[] {
|
|
289
|
-
const paths = [""];
|
|
290
|
-
const walk = (list: FileTreeNode[]) => {
|
|
291
|
-
for (const node of list) {
|
|
292
|
-
if (node.kind !== "dir" || node.children === undefined) continue;
|
|
293
|
-
paths.push(node.path);
|
|
294
|
-
walk(node.children);
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
walk(nodes);
|
|
298
|
-
return paths;
|
|
299
|
-
}
|
|
304
|
+
const FS_LIST_BATCH_REQUEST_LIMIT = 16;
|
|
300
305
|
|
|
301
306
|
/** Repository paths are capability-advertised and therefore safe to use as a
|
|
302
307
|
* bounded initial lazy-tree frontier. Listing their ancestors concurrently with
|
|
303
308
|
* the root avoids a root → repositories → repo remote waterfall. */
|
|
304
309
|
function initialDirectoryFrontier(rootPath: string, repoPaths: readonly string[]): string[] {
|
|
305
|
-
const
|
|
310
|
+
const root = normalizeRoot(rootPath);
|
|
311
|
+
const rootParts = root.split("/").filter(Boolean);
|
|
312
|
+
const rootPrefix = root.startsWith("//") ? "//" : root.startsWith("/") ? "/" : "";
|
|
306
313
|
const paths = new Set<string>();
|
|
307
314
|
for (const repoPath of repoPaths) {
|
|
308
|
-
const
|
|
315
|
+
const canonicalRepoPath = joinTreeRoot(root, normalizeRoot(repoPath));
|
|
316
|
+
const parts = canonicalRepoPath.split("/").filter(Boolean);
|
|
309
317
|
if (rootParts.some((part, index) => parts[index] !== part)) continue;
|
|
310
318
|
for (let depth = rootParts.length + 1; depth <= parts.length; depth += 1) {
|
|
311
|
-
|
|
319
|
+
const path = parts.slice(0, depth).join("/");
|
|
320
|
+
paths.add(`${rootPrefix}${path}`);
|
|
312
321
|
}
|
|
313
322
|
}
|
|
314
323
|
// A workspace with hundreds of repositories should remain lazy. This still
|
|
@@ -333,8 +342,8 @@ function initialDirectoryFrontier(rootPath: string, repoPaths: readonly string[]
|
|
|
333
342
|
|
|
334
343
|
/** True when `parent` is the root ("") or a dir node that is actually present in
|
|
335
344
|
* the loaded tree (so an insert/remove there would be visible). */
|
|
336
|
-
function parentIsLoaded(nodes: FileTreeNode[], parent: string): boolean {
|
|
337
|
-
if (parent ===
|
|
345
|
+
function parentIsLoaded(nodes: FileTreeNode[], parent: string, rootPath = ""): boolean {
|
|
346
|
+
if (parent === normalizeRoot(rootPath)) return true;
|
|
338
347
|
const node = findNodeByPath(nodes, parent);
|
|
339
348
|
return Boolean(node && node.kind === "dir" && node.children !== undefined);
|
|
340
349
|
}
|
|
@@ -342,8 +351,13 @@ function parentIsLoaded(nodes: FileTreeNode[], parent: string): boolean {
|
|
|
342
351
|
/** Insert `child` under `parent` (immutably), keeping siblings sorted. A no-op
|
|
343
352
|
* (returns the same array) when the parent isn't a loaded dir or the child
|
|
344
353
|
* already exists. */
|
|
345
|
-
function insertNode(
|
|
346
|
-
|
|
354
|
+
function insertNode(
|
|
355
|
+
nodes: FileTreeNode[],
|
|
356
|
+
parent: string,
|
|
357
|
+
child: FileTreeNode,
|
|
358
|
+
rootPath = "",
|
|
359
|
+
): FileTreeNode[] {
|
|
360
|
+
if (parent === normalizeRoot(rootPath)) {
|
|
347
361
|
if (nodes.some((n) => n.path === child.path)) return nodes;
|
|
348
362
|
return sortNodes([...nodes, child]);
|
|
349
363
|
}
|
|
@@ -354,16 +368,16 @@ function insertNode(nodes: FileTreeNode[], parent: string, child: FileTreeNode):
|
|
|
354
368
|
return { ...node, children: sortNodes([...node.children, child]) };
|
|
355
369
|
}
|
|
356
370
|
if (node.kind === "dir" && node.children && parent.startsWith(`${node.path}/`)) {
|
|
357
|
-
return { ...node, children: insertNode(node.children, parent, child) };
|
|
371
|
+
return { ...node, children: insertNode(node.children, parent, child, rootPath) };
|
|
358
372
|
}
|
|
359
373
|
return node;
|
|
360
374
|
});
|
|
361
375
|
}
|
|
362
376
|
|
|
363
377
|
/** Remove the node at `path` (immutably). No-op when it isn't in the tree. */
|
|
364
|
-
function removeNode(nodes: FileTreeNode[], path: string): FileTreeNode[] {
|
|
365
|
-
const parent =
|
|
366
|
-
if (parent ===
|
|
378
|
+
function removeNode(nodes: FileTreeNode[], path: string, rootPath = ""): FileTreeNode[] {
|
|
379
|
+
const parent = parentWithinTree(path, rootPath);
|
|
380
|
+
if (parent === normalizeRoot(rootPath)) {
|
|
367
381
|
if (!nodes.some((n) => n.path === path)) return nodes;
|
|
368
382
|
return nodes.filter((n) => n.path !== path);
|
|
369
383
|
}
|
|
@@ -376,7 +390,7 @@ function removeNode(nodes: FileTreeNode[], path: string): FileTreeNode[] {
|
|
|
376
390
|
};
|
|
377
391
|
}
|
|
378
392
|
if (node.kind === "dir" && node.children && parent.startsWith(`${node.path}/`)) {
|
|
379
|
-
return { ...node, children: removeNode(node.children, path) };
|
|
393
|
+
return { ...node, children: removeNode(node.children, path, rootPath) };
|
|
380
394
|
}
|
|
381
395
|
return node;
|
|
382
396
|
});
|
|
@@ -486,6 +500,15 @@ export function useSandboxFiles(
|
|
|
486
500
|
const enabled = (options.enabled ?? true) && Boolean(sessionId);
|
|
487
501
|
const active = options.active ?? true;
|
|
488
502
|
const rootPath = options.rootPath ?? "";
|
|
503
|
+
const routeEpoch = options.route?.epoch ?? null;
|
|
504
|
+
const routeRoot = options.route?.root ?? null;
|
|
505
|
+
const route = useMemo<FileSystemRouteIdentity | undefined>(
|
|
506
|
+
() =>
|
|
507
|
+
routeEpoch !== null && routeRoot !== null
|
|
508
|
+
? { epoch: routeEpoch, root: routeRoot }
|
|
509
|
+
: undefined,
|
|
510
|
+
[routeEpoch, routeRoot],
|
|
511
|
+
);
|
|
489
512
|
const repoPathsKey = [
|
|
490
513
|
...new Set((options.repoPaths?.length ? options.repoPaths : [rootPath]).map(normalizeRoot)),
|
|
491
514
|
].join("\u0000");
|
|
@@ -498,7 +521,7 @@ export function useSandboxFiles(
|
|
|
498
521
|
const acceptsEventReadsRef = useRef(acceptsEventReads);
|
|
499
522
|
acceptsEventReadsRef.current = acceptsEventReads;
|
|
500
523
|
const hasLiveIoFence = options.liveness !== undefined;
|
|
501
|
-
const identityKey = `${workspaceId}\u0000${sessionId ?? ""}\u0000${rootPath}\u0000${repoPathsKey}`;
|
|
524
|
+
const identityKey = `${workspaceId}\u0000${sessionId ?? ""}\u0000${rootPath}\u0000${repoPathsKey}\u0000${routeEpoch ?? ""}\u0000${routeRoot ?? ""}`;
|
|
502
525
|
|
|
503
526
|
const [tree, setTree] = useState<FileTreeNode[]>([]);
|
|
504
527
|
// A ref mirror of the current tree — lets the optimistic path snapshot the
|
|
@@ -527,9 +550,9 @@ export function useSandboxFiles(
|
|
|
527
550
|
const lastSeqRef = useRef(0);
|
|
528
551
|
const pendingParentsRef = useRef<Set<string>>(new Set());
|
|
529
552
|
const pendingGitRef = useRef(false);
|
|
530
|
-
const
|
|
553
|
+
const eventReconcileInFlightRef = useRef<Promise<void> | null>(null);
|
|
554
|
+
const eventReconcilePendingRef = useRef(false);
|
|
531
555
|
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
532
|
-
const lastCommandRefreshAtRef = useRef(0);
|
|
533
556
|
|
|
534
557
|
// ── Self-emitted fs.changed de-dupe ───────────────────────────────────────
|
|
535
558
|
// Every one of OUR mutations emits an `fs.changed` event back on the live log
|
|
@@ -584,34 +607,16 @@ export function useSandboxFiles(
|
|
|
584
607
|
setGitLoading(true);
|
|
585
608
|
setError(null);
|
|
586
609
|
try {
|
|
587
|
-
//
|
|
588
|
-
//
|
|
610
|
+
// Paint the useful file tree before the optional Git tint. Separate remote
|
|
611
|
+
// requests for one Modal box are deliberately serialized by the API; firing
|
|
612
|
+
// both here only made the Git request contend with the file request during
|
|
613
|
+
// cold starts.
|
|
589
614
|
const frontierPaths = initialDirectoryFrontier(rootPath, repoPaths);
|
|
590
615
|
const listRequests = [rootPath, ...frontierPaths].map((path) => ({
|
|
591
616
|
path,
|
|
592
617
|
depth: 1,
|
|
618
|
+
...(route ? { route } : {}),
|
|
593
619
|
}));
|
|
594
|
-
const statusPromise =
|
|
595
|
-
repoPaths.length > 0
|
|
596
|
-
? client
|
|
597
|
-
.gitReadBatch(
|
|
598
|
-
workspaceId,
|
|
599
|
-
sessionId,
|
|
600
|
-
{
|
|
601
|
-
requests: repoPaths.map((root) => ({
|
|
602
|
-
status: { path: root },
|
|
603
|
-
})),
|
|
604
|
-
},
|
|
605
|
-
{ signal: refreshAbort.signal },
|
|
606
|
-
)
|
|
607
|
-
.then((batch) =>
|
|
608
|
-
batch.results.map((result, index) => ({
|
|
609
|
-
root: repoPaths[index] ?? "",
|
|
610
|
-
status: result.status,
|
|
611
|
-
})),
|
|
612
|
-
)
|
|
613
|
-
.catch(() => null)
|
|
614
|
-
: Promise.resolve([]);
|
|
615
620
|
// Root plus the bounded repository frontier share one API request, one
|
|
616
621
|
// direct holder, and one provider attach. The old per-directory fan-out
|
|
617
622
|
// paid that fixed control-plane cost up to nine times on every Files open.
|
|
@@ -644,7 +649,27 @@ export function useSandboxFiles(
|
|
|
644
649
|
setSource("live");
|
|
645
650
|
setLoading(false);
|
|
646
651
|
|
|
647
|
-
const statuses =
|
|
652
|
+
const statuses =
|
|
653
|
+
repoPaths.length > 0
|
|
654
|
+
? await client
|
|
655
|
+
.gitReadBatch(
|
|
656
|
+
workspaceId,
|
|
657
|
+
sessionId,
|
|
658
|
+
{
|
|
659
|
+
requests: repoPaths.map((root) => ({
|
|
660
|
+
status: { path: root },
|
|
661
|
+
})),
|
|
662
|
+
},
|
|
663
|
+
{ signal: refreshAbort.signal },
|
|
664
|
+
)
|
|
665
|
+
.then((batch) =>
|
|
666
|
+
batch.results.map((result, index) => ({
|
|
667
|
+
root: repoPaths[index] ?? "",
|
|
668
|
+
status: result.status,
|
|
669
|
+
})),
|
|
670
|
+
)
|
|
671
|
+
.catch(() => null)
|
|
672
|
+
: [];
|
|
648
673
|
if (refreshGenerationRef.current !== generation) return;
|
|
649
674
|
if (statuses) {
|
|
650
675
|
const overlay = new Map<string, FileTreeStatus>();
|
|
@@ -652,7 +677,7 @@ export function useSandboxFiles(
|
|
|
652
677
|
for (const file of status.files) {
|
|
653
678
|
const code = file.worktree ?? file.index;
|
|
654
679
|
const mapped = code ? GIT_STATUS_TO_TREE[code] : undefined;
|
|
655
|
-
if (mapped) overlay.set(qualifyStatusPath(root, file.path), mapped);
|
|
680
|
+
if (mapped) overlay.set(qualifyStatusPath(root, file.path, rootPath), mapped);
|
|
656
681
|
}
|
|
657
682
|
}
|
|
658
683
|
statusRef.current = overlay;
|
|
@@ -671,7 +696,7 @@ export function useSandboxFiles(
|
|
|
671
696
|
if (refreshGenerationRef.current === generation) setGitLoading(false);
|
|
672
697
|
if (refreshAbortRef.current === refreshAbort) refreshAbortRef.current = null;
|
|
673
698
|
}
|
|
674
|
-
}, [client, workspaceId, sessionId, rootPath, repoPaths, applyStatus]);
|
|
699
|
+
}, [client, workspaceId, sessionId, rootPath, repoPaths, route, applyStatus]);
|
|
675
700
|
|
|
676
701
|
// Seed (or re-seed) the tree from a turn-end capture — the COLD/offline paint,
|
|
677
702
|
// zero Channel-A calls. The tree index is workspace-relative (`treeIndex`); the
|
|
@@ -731,7 +756,7 @@ export function useSandboxFiles(
|
|
|
731
756
|
const listed = await client.fsList(
|
|
732
757
|
workspaceId,
|
|
733
758
|
sessionId,
|
|
734
|
-
{ path, depth: 1 },
|
|
759
|
+
{ path, depth: 1, ...(route ? { route } : {}) },
|
|
735
760
|
{ signal: identitySignal },
|
|
736
761
|
);
|
|
737
762
|
if (identityGenerationRef.current !== identityGeneration) return;
|
|
@@ -751,7 +776,7 @@ export function useSandboxFiles(
|
|
|
751
776
|
}
|
|
752
777
|
}
|
|
753
778
|
},
|
|
754
|
-
[client, workspaceId, sessionId, capture, source, applyStatus],
|
|
779
|
+
[client, workspaceId, sessionId, capture, source, route, applyStatus],
|
|
755
780
|
);
|
|
756
781
|
|
|
757
782
|
const readFile = useCallback(
|
|
@@ -844,9 +869,14 @@ export function useSandboxFiles(
|
|
|
844
869
|
}
|
|
845
870
|
throw new Error("Captured file download failed after refreshing its URL.");
|
|
846
871
|
}
|
|
847
|
-
return await client.fsRead(
|
|
872
|
+
return await client.fsRead(
|
|
873
|
+
workspaceId,
|
|
874
|
+
sessionId,
|
|
875
|
+
{ path, ...(route ? { route } : {}) },
|
|
876
|
+
{ signal },
|
|
877
|
+
);
|
|
848
878
|
},
|
|
849
|
-
[client, workspaceId, sessionId, capture, source],
|
|
879
|
+
[client, workspaceId, sessionId, capture, source, route],
|
|
850
880
|
);
|
|
851
881
|
|
|
852
882
|
// TARGETED reconcile of a single directory — re-list ONE parent at depth 1 and
|
|
@@ -866,13 +896,19 @@ export function useSandboxFiles(
|
|
|
866
896
|
: identitySignal;
|
|
867
897
|
// Skip parents that aren't currently loaded/expanded in the tree (nothing
|
|
868
898
|
// visible to update; they re-list fresh on the next expand).
|
|
869
|
-
if (!parentIsLoaded(treeRef.current, path)) return;
|
|
899
|
+
if (!parentIsLoaded(treeRef.current, path, rootPath)) return;
|
|
870
900
|
try {
|
|
871
|
-
const listed = await client.fsList(
|
|
901
|
+
const listed = await client.fsList(
|
|
902
|
+
workspaceId,
|
|
903
|
+
sessionId,
|
|
904
|
+
{ path, depth: 1, ...(route ? { route } : {}) },
|
|
905
|
+
{ signal },
|
|
906
|
+
);
|
|
872
907
|
if (identityGenerationRef.current !== identityGeneration) return;
|
|
873
908
|
const children = (listed.root.children ?? []).map((node) => fsNodeToTree(node));
|
|
874
|
-
if (path ===
|
|
875
|
-
|
|
909
|
+
if (path === normalizeRoot(rootPath)) {
|
|
910
|
+
setTree((prev) => applyStatus(mergeRootChildren(prev, children)));
|
|
911
|
+
} else
|
|
876
912
|
setTree((prev) => {
|
|
877
913
|
const existing = findNodeByPath(prev, path);
|
|
878
914
|
const merged = existing?.children
|
|
@@ -885,7 +921,64 @@ export function useSandboxFiles(
|
|
|
885
921
|
// root-refresh here (that would collapse the tree the user is working in).
|
|
886
922
|
}
|
|
887
923
|
},
|
|
888
|
-
[client, workspaceId, sessionId, applyStatus],
|
|
924
|
+
[client, workspaceId, sessionId, rootPath, route, applyStatus],
|
|
925
|
+
);
|
|
926
|
+
|
|
927
|
+
// Reconcile the visible directory frontier through bounded batch requests.
|
|
928
|
+
// One tool completion can affect several expanded directories; issuing one
|
|
929
|
+
// provider request per directory created a self-inflicted lock convoy.
|
|
930
|
+
const reconcilePaths = useCallback(
|
|
931
|
+
async (requestedPaths: readonly string[], requestSignal?: AbortSignal) => {
|
|
932
|
+
if (!sessionId) return;
|
|
933
|
+
const identityGeneration = identityGenerationRef.current;
|
|
934
|
+
const identitySignal = identityAbortRef.current.signal;
|
|
935
|
+
const signal = requestSignal
|
|
936
|
+
? AbortSignal.any([identitySignal, requestSignal])
|
|
937
|
+
: identitySignal;
|
|
938
|
+
const paths = [...new Set(requestedPaths)].filter((path) =>
|
|
939
|
+
parentIsLoaded(treeRef.current, path, rootPath),
|
|
940
|
+
);
|
|
941
|
+
for (let offset = 0; offset < paths.length; offset += FS_LIST_BATCH_REQUEST_LIMIT) {
|
|
942
|
+
const chunk = paths.slice(offset, offset + FS_LIST_BATCH_REQUEST_LIMIT);
|
|
943
|
+
try {
|
|
944
|
+
const listed = await client.fsListBatch(
|
|
945
|
+
workspaceId,
|
|
946
|
+
sessionId,
|
|
947
|
+
{
|
|
948
|
+
requests: chunk.map((path) => ({
|
|
949
|
+
path,
|
|
950
|
+
depth: 1,
|
|
951
|
+
...(route ? { route } : {}),
|
|
952
|
+
})),
|
|
953
|
+
},
|
|
954
|
+
{ signal },
|
|
955
|
+
);
|
|
956
|
+
if (identityGenerationRef.current !== identityGeneration) return;
|
|
957
|
+
setTree((previous) => {
|
|
958
|
+
let next = previous;
|
|
959
|
+
for (const [index, path] of chunk.entries()) {
|
|
960
|
+
const result = listed.results[index];
|
|
961
|
+
if (!result) continue;
|
|
962
|
+
const children = (result.root.children ?? []).map((node) => fsNodeToTree(node));
|
|
963
|
+
if (path === normalizeRoot(rootPath)) {
|
|
964
|
+
next = mergeRootChildren(next, children);
|
|
965
|
+
} else {
|
|
966
|
+
const existing = findNodeByPath(next, path);
|
|
967
|
+
const merged = existing?.children
|
|
968
|
+
? mergeChildren(existing.children, children)
|
|
969
|
+
: children;
|
|
970
|
+
next = replaceChildren(next, path, merged);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
return applyStatus(next);
|
|
974
|
+
});
|
|
975
|
+
} catch {
|
|
976
|
+
// Reconciliation is best-effort. Preserve the current visible tree and
|
|
977
|
+
// let the next real event or explicit refresh reconcile it.
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
[client, workspaceId, sessionId, rootPath, route, applyStatus],
|
|
889
982
|
);
|
|
890
983
|
|
|
891
984
|
// Run a Channel-A op behind an OPTIMISTIC tree edit. `apply` splices the change
|
|
@@ -950,7 +1043,7 @@ export function useSandboxFiles(
|
|
|
950
1043
|
if (!sessionId) throw new Error("no session");
|
|
951
1044
|
const identityGeneration = identityGenerationRef.current;
|
|
952
1045
|
const identitySignal = identityAbortRef.current.signal;
|
|
953
|
-
const parent =
|
|
1046
|
+
const parent = parentWithinTree(path, rootPath);
|
|
954
1047
|
// Splice a new file node in immediately ONLY when the path doesn't already
|
|
955
1048
|
// exist in a loaded parent (an editor SAVE to an existing file mutates no
|
|
956
1049
|
// tree shape — just content — so it needs no optimistic node, no reconcile).
|
|
@@ -963,13 +1056,13 @@ export function useSandboxFiles(
|
|
|
963
1056
|
};
|
|
964
1057
|
return await runOptimistic(
|
|
965
1058
|
"write",
|
|
966
|
-
(nodes) => (exists ? nodes : insertNode(nodes, parent, node)),
|
|
1059
|
+
(nodes) => (exists ? nodes : insertNode(nodes, parent, node, rootPath)),
|
|
967
1060
|
async () => {
|
|
968
1061
|
if (!writeOptions.force && writeOptions.expectedContent !== undefined) {
|
|
969
1062
|
const live = await client.fsRead(
|
|
970
1063
|
workspaceId,
|
|
971
1064
|
sessionId,
|
|
972
|
-
{ path },
|
|
1065
|
+
{ path, ...(route ? { route } : {}) },
|
|
973
1066
|
{ signal: identitySignal },
|
|
974
1067
|
);
|
|
975
1068
|
if (identityGenerationRef.current !== identityGeneration) {
|
|
@@ -988,18 +1081,19 @@ export function useSandboxFiles(
|
|
|
988
1081
|
path,
|
|
989
1082
|
content,
|
|
990
1083
|
overwrite: true,
|
|
1084
|
+
...(route ? { route } : {}),
|
|
991
1085
|
});
|
|
992
1086
|
},
|
|
993
1087
|
exists ? [] : [parent],
|
|
994
1088
|
);
|
|
995
1089
|
},
|
|
996
|
-
[client, workspaceId, sessionId, tree, runOptimistic],
|
|
1090
|
+
[client, workspaceId, sessionId, tree, rootPath, route, runOptimistic],
|
|
997
1091
|
);
|
|
998
1092
|
|
|
999
1093
|
const createFile = useCallback(
|
|
1000
1094
|
async (path: string): Promise<void> => {
|
|
1001
1095
|
if (!sessionId) throw new Error("no session");
|
|
1002
|
-
const parent =
|
|
1096
|
+
const parent = parentWithinTree(path, rootPath);
|
|
1003
1097
|
const node: FileTreeNode = {
|
|
1004
1098
|
path,
|
|
1005
1099
|
name: leafOf(path),
|
|
@@ -1008,23 +1102,24 @@ export function useSandboxFiles(
|
|
|
1008
1102
|
};
|
|
1009
1103
|
await runOptimistic(
|
|
1010
1104
|
"create file",
|
|
1011
|
-
(nodes) => insertNode(nodes, parent, node),
|
|
1105
|
+
(nodes) => insertNode(nodes, parent, node, rootPath),
|
|
1012
1106
|
() =>
|
|
1013
1107
|
client.fsWrite(workspaceId, sessionId, {
|
|
1014
1108
|
path,
|
|
1015
1109
|
content: "",
|
|
1016
1110
|
overwrite: false,
|
|
1111
|
+
...(route ? { route } : {}),
|
|
1017
1112
|
}),
|
|
1018
1113
|
[parent],
|
|
1019
1114
|
);
|
|
1020
1115
|
},
|
|
1021
|
-
[client, workspaceId, sessionId, runOptimistic],
|
|
1116
|
+
[client, workspaceId, sessionId, rootPath, route, runOptimistic],
|
|
1022
1117
|
);
|
|
1023
1118
|
|
|
1024
1119
|
const createDir = useCallback(
|
|
1025
1120
|
async (path: string): Promise<void> => {
|
|
1026
1121
|
if (!sessionId) throw new Error("no session");
|
|
1027
|
-
const parent =
|
|
1122
|
+
const parent = parentWithinTree(path, rootPath);
|
|
1028
1123
|
// A freshly-created dir is empty + expanded: children:[] (not undefined, so
|
|
1029
1124
|
// it doesn't show the lazy-expand marker over a dir we KNOW is empty).
|
|
1030
1125
|
const node: FileTreeNode = {
|
|
@@ -1035,12 +1130,17 @@ export function useSandboxFiles(
|
|
|
1035
1130
|
};
|
|
1036
1131
|
await runOptimistic(
|
|
1037
1132
|
"create folder",
|
|
1038
|
-
(nodes) => insertNode(nodes, parent, node),
|
|
1039
|
-
() =>
|
|
1133
|
+
(nodes) => insertNode(nodes, parent, node, rootPath),
|
|
1134
|
+
() =>
|
|
1135
|
+
client.fsMkdir(workspaceId, sessionId, {
|
|
1136
|
+
path,
|
|
1137
|
+
recursive: true,
|
|
1138
|
+
...(route ? { route } : {}),
|
|
1139
|
+
}),
|
|
1040
1140
|
[parent],
|
|
1041
1141
|
);
|
|
1042
1142
|
},
|
|
1043
|
-
[client, workspaceId, sessionId, runOptimistic],
|
|
1143
|
+
[client, workspaceId, sessionId, rootPath, route, runOptimistic],
|
|
1044
1144
|
);
|
|
1045
1145
|
|
|
1046
1146
|
const deleteEntry = useCallback(
|
|
@@ -1048,19 +1148,24 @@ export function useSandboxFiles(
|
|
|
1048
1148
|
if (!sessionId) throw new Error("no session");
|
|
1049
1149
|
await runOptimistic(
|
|
1050
1150
|
"delete",
|
|
1051
|
-
(nodes) => removeNode(nodes, path),
|
|
1052
|
-
() =>
|
|
1053
|
-
|
|
1151
|
+
(nodes) => removeNode(nodes, path, rootPath),
|
|
1152
|
+
() =>
|
|
1153
|
+
client.fsDelete(workspaceId, sessionId, {
|
|
1154
|
+
path,
|
|
1155
|
+
recursive,
|
|
1156
|
+
...(route ? { route } : {}),
|
|
1157
|
+
}),
|
|
1158
|
+
[parentWithinTree(path, rootPath)],
|
|
1054
1159
|
);
|
|
1055
1160
|
},
|
|
1056
|
-
[client, workspaceId, sessionId, runOptimistic],
|
|
1161
|
+
[client, workspaceId, sessionId, rootPath, route, runOptimistic],
|
|
1057
1162
|
);
|
|
1058
1163
|
|
|
1059
1164
|
const moveEntry = useCallback(
|
|
1060
1165
|
async (path: string, newPath: string, opts?: { overwrite?: boolean }): Promise<void> => {
|
|
1061
1166
|
if (!sessionId) throw new Error("no session");
|
|
1062
|
-
const from =
|
|
1063
|
-
const to =
|
|
1167
|
+
const from = parentWithinTree(path, rootPath);
|
|
1168
|
+
const to = parentWithinTree(newPath, rootPath);
|
|
1064
1169
|
await runOptimistic(
|
|
1065
1170
|
"move",
|
|
1066
1171
|
(nodes) => {
|
|
@@ -1068,18 +1173,19 @@ export function useSandboxFiles(
|
|
|
1068
1173
|
if (!moving) return nodes; // not loaded — let the reconcile pick it up
|
|
1069
1174
|
// Re-path the moved subtree, drop it from its old parent, splice into new.
|
|
1070
1175
|
const moved = repathNode(moving, path, newPath);
|
|
1071
|
-
return insertNode(removeNode(nodes, path), to, moved);
|
|
1176
|
+
return insertNode(removeNode(nodes, path, rootPath), to, moved, rootPath);
|
|
1072
1177
|
},
|
|
1073
1178
|
() =>
|
|
1074
1179
|
client.fsMove(workspaceId, sessionId, {
|
|
1075
1180
|
path,
|
|
1076
1181
|
newPath,
|
|
1077
1182
|
overwrite: opts?.overwrite ?? false,
|
|
1183
|
+
...(route ? { route } : {}),
|
|
1078
1184
|
}),
|
|
1079
1185
|
to === from ? [from] : [from, to],
|
|
1080
1186
|
);
|
|
1081
1187
|
},
|
|
1082
|
-
[client, workspaceId, sessionId, runOptimistic],
|
|
1188
|
+
[client, workspaceId, sessionId, rootPath, route, runOptimistic],
|
|
1083
1189
|
);
|
|
1084
1190
|
|
|
1085
1191
|
// Initial paint + reset on identity change. Source selection:
|
|
@@ -1107,14 +1213,14 @@ export function useSandboxFiles(
|
|
|
1107
1213
|
const identityChanged = previousIdentityRef.current !== identityKey;
|
|
1108
1214
|
previousIdentityRef.current = identityKey;
|
|
1109
1215
|
if (identityChanged || !enabled) {
|
|
1216
|
+
if (identityChanged) eventReconcileInFlightRef.current = null;
|
|
1110
1217
|
identityAbortRef.current.abort();
|
|
1111
1218
|
identityAbortRef.current = new AbortController();
|
|
1112
1219
|
identityGenerationRef.current += 1;
|
|
1113
1220
|
lastSeqRef.current = 0;
|
|
1114
1221
|
pendingParentsRef.current = new Set();
|
|
1115
1222
|
pendingGitRef.current = false;
|
|
1116
|
-
|
|
1117
|
-
lastCommandRefreshAtRef.current = 0;
|
|
1223
|
+
eventReconcilePendingRef.current = false;
|
|
1118
1224
|
if (debounceRef.current) {
|
|
1119
1225
|
clearTimeout(debounceRef.current);
|
|
1120
1226
|
debounceRef.current = null;
|
|
@@ -1155,6 +1261,7 @@ export function useSandboxFiles(
|
|
|
1155
1261
|
refreshAbortRef.current = null;
|
|
1156
1262
|
refreshGenerationRef.current += 1;
|
|
1157
1263
|
eventReadAbortRef.current.abort();
|
|
1264
|
+
eventReconcilePendingRef.current = false;
|
|
1158
1265
|
};
|
|
1159
1266
|
}, [
|
|
1160
1267
|
enabled,
|
|
@@ -1196,7 +1303,7 @@ export function useSandboxFiles(
|
|
|
1196
1303
|
for (const file of status.files) {
|
|
1197
1304
|
const code = file.worktree ?? file.index;
|
|
1198
1305
|
const mapped = code ? GIT_STATUS_TO_TREE[code] : undefined;
|
|
1199
|
-
if (mapped) overlay.set(qualifyStatusPath(root, file.path), mapped);
|
|
1306
|
+
if (mapped) overlay.set(qualifyStatusPath(root, file.path, rootPath), mapped);
|
|
1200
1307
|
}
|
|
1201
1308
|
}
|
|
1202
1309
|
statusRef.current = overlay;
|
|
@@ -1208,9 +1315,47 @@ export function useSandboxFiles(
|
|
|
1208
1315
|
if (identityGenerationRef.current === identityGeneration) setGitLoading(false);
|
|
1209
1316
|
}
|
|
1210
1317
|
},
|
|
1211
|
-
[client, workspaceId, sessionId, repoPaths, applyStatus],
|
|
1318
|
+
[client, workspaceId, sessionId, repoPaths, rootPath, applyStatus],
|
|
1212
1319
|
);
|
|
1213
1320
|
|
|
1321
|
+
const performEventReconcile = useCallback(async () => {
|
|
1322
|
+
const parents = pendingParentsRef.current;
|
|
1323
|
+
pendingParentsRef.current = new Set();
|
|
1324
|
+
const wantGit = pendingGitRef.current;
|
|
1325
|
+
pendingGitRef.current = false;
|
|
1326
|
+
const signal = eventReadAbortRef.current.signal;
|
|
1327
|
+
const paths = [...parents];
|
|
1328
|
+
|
|
1329
|
+
// File content is the primary Files-tab result. Reconcile it first, then add
|
|
1330
|
+
// the optional Git tint through a second serial request. This matches the
|
|
1331
|
+
// API's exact-provider serialization instead of making the two reads contend.
|
|
1332
|
+
await reconcilePaths(paths, signal);
|
|
1333
|
+
if (wantGit) await refreshGitOverlay(signal);
|
|
1334
|
+
}, [reconcilePaths, refreshGitOverlay]);
|
|
1335
|
+
const performEventReconcileRef = useRef(performEventReconcile);
|
|
1336
|
+
performEventReconcileRef.current = performEventReconcile;
|
|
1337
|
+
const reconcilePendingEvents = useCallback(async () => {
|
|
1338
|
+
eventReconcilePendingRef.current = true;
|
|
1339
|
+
const existing = eventReconcileInFlightRef.current;
|
|
1340
|
+
if (existing) return await existing;
|
|
1341
|
+
const identityGeneration = identityGenerationRef.current;
|
|
1342
|
+
const run = (async () => {
|
|
1343
|
+
while (
|
|
1344
|
+
eventReconcilePendingRef.current &&
|
|
1345
|
+
identityGenerationRef.current === identityGeneration
|
|
1346
|
+
) {
|
|
1347
|
+
eventReconcilePendingRef.current = false;
|
|
1348
|
+
await performEventReconcileRef.current();
|
|
1349
|
+
}
|
|
1350
|
+
})();
|
|
1351
|
+
eventReconcileInFlightRef.current = run;
|
|
1352
|
+
try {
|
|
1353
|
+
await run;
|
|
1354
|
+
} finally {
|
|
1355
|
+
if (eventReconcileInFlightRef.current === run) eventReconcileInFlightRef.current = null;
|
|
1356
|
+
}
|
|
1357
|
+
}, []);
|
|
1358
|
+
|
|
1214
1359
|
// Auto-reconcile on fs/git change notifications — TARGETED, never a root
|
|
1215
1360
|
// collapse-reload, and de-duped against our OWN mutations.
|
|
1216
1361
|
//
|
|
@@ -1221,6 +1366,8 @@ export function useSandboxFiles(
|
|
|
1221
1366
|
// reconciles ONLY the affected parent directories (in place, expansion
|
|
1222
1367
|
// preserved). Bursts are debounced into a single reconcile pass.
|
|
1223
1368
|
// • A git.changed just re-tints (refreshes the status overlay) — no fs re-list.
|
|
1369
|
+
// • Generic command/tool output performs no provider reads. The canonical
|
|
1370
|
+
// turn-end capture refreshes the root once after the command burst settles.
|
|
1224
1371
|
const events = options.events;
|
|
1225
1372
|
|
|
1226
1373
|
useEffect(() => {
|
|
@@ -1238,12 +1385,11 @@ export function useSandboxFiles(
|
|
|
1238
1385
|
}
|
|
1239
1386
|
pendingParentsRef.current = new Set();
|
|
1240
1387
|
pendingGitRef.current = false;
|
|
1241
|
-
|
|
1388
|
+
eventReconcilePendingRef.current = false;
|
|
1242
1389
|
return;
|
|
1243
1390
|
}
|
|
1244
1391
|
let sawNew = false;
|
|
1245
1392
|
let contentChanged = false;
|
|
1246
|
-
let sawCommandDelta = false;
|
|
1247
1393
|
for (const event of events) {
|
|
1248
1394
|
if (event.sequence <= lastSeqRef.current) continue;
|
|
1249
1395
|
if (event.type === "fs.changed") {
|
|
@@ -1256,8 +1402,10 @@ export function useSandboxFiles(
|
|
|
1256
1402
|
continue;
|
|
1257
1403
|
contentChanged = true;
|
|
1258
1404
|
for (const change of payload.changes ?? []) {
|
|
1259
|
-
pendingParentsRef.current.add(
|
|
1260
|
-
if (change.oldPath)
|
|
1405
|
+
pendingParentsRef.current.add(parentWithinTree(change.path, rootPath));
|
|
1406
|
+
if (change.oldPath) {
|
|
1407
|
+
pendingParentsRef.current.add(parentWithinTree(change.oldPath, rootPath));
|
|
1408
|
+
}
|
|
1261
1409
|
}
|
|
1262
1410
|
} else if (event.type === "git.changed") {
|
|
1263
1411
|
sawNew = true;
|
|
@@ -1273,73 +1421,27 @@ export function useSandboxFiles(
|
|
|
1273
1421
|
)
|
|
1274
1422
|
continue;
|
|
1275
1423
|
pendingGitRef.current = true;
|
|
1276
|
-
} else if (event.type === "agent.toolCall.output") {
|
|
1277
|
-
// Agent shell/apply-patch writes do not necessarily pass through the
|
|
1278
|
-
// structured FS service, so they may have no fs.changed notification.
|
|
1279
|
-
// A completed tool is a bounded invalidation point: refresh only the
|
|
1280
|
-
// currently-loaded directory frontier, never poll and never traverse a
|
|
1281
|
-
// collapsed subtree.
|
|
1282
|
-
sawNew = true;
|
|
1283
|
-
contentChanged = true;
|
|
1284
|
-
pendingAgentToolRef.current = true;
|
|
1285
|
-
// Shell/apply-patch writes bypass the structured Git service too, so no
|
|
1286
|
-
// git.changed event is guaranteed. Refresh the summary/tints alongside
|
|
1287
|
-
// the visible tree frontier; both remote reads can run concurrently.
|
|
1288
|
-
pendingGitRef.current = true;
|
|
1289
|
-
} else if (event.type === "sandbox.command.output.delta") {
|
|
1290
|
-
// Ordinary shell writes can bypass Channel-A and therefore emit no
|
|
1291
|
-
// fs.changed/git.changed event until the command completes. Reconcile
|
|
1292
|
-
// the visible frontier at most once per second while output streams so
|
|
1293
|
-
// Files and Changes stay useful without turning the dock into polling.
|
|
1294
|
-
sawNew = true;
|
|
1295
|
-
contentChanged = true;
|
|
1296
|
-
sawCommandDelta = true;
|
|
1297
|
-
pendingAgentToolRef.current = true;
|
|
1298
|
-
pendingGitRef.current = true;
|
|
1299
1424
|
}
|
|
1300
1425
|
}
|
|
1301
1426
|
// Advance the high-water mark past everything we've folded.
|
|
1302
1427
|
for (const event of events)
|
|
1303
1428
|
if (event.sequence > lastSeqRef.current) lastSeqRef.current = event.sequence;
|
|
1304
1429
|
if (!sawNew) return;
|
|
1305
|
-
if (contentChanged
|
|
1430
|
+
if (contentChanged) setContentRevision((revision) => revision + 1);
|
|
1306
1431
|
|
|
1307
1432
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
1308
1433
|
const identityGeneration = identityGenerationRef.current;
|
|
1309
|
-
const delay = sawCommandDelta
|
|
1310
|
-
? Math.max(0, 1_000 - (Date.now() - lastCommandRefreshAtRef.current))
|
|
1311
|
-
: 150;
|
|
1312
1434
|
debounceRef.current = setTimeout(() => {
|
|
1313
1435
|
debounceRef.current = null;
|
|
1314
1436
|
if (identityGenerationRef.current !== identityGeneration) return;
|
|
1315
1437
|
if (!acceptsEventReadsRef.current) {
|
|
1316
1438
|
pendingParentsRef.current = new Set();
|
|
1317
1439
|
pendingGitRef.current = false;
|
|
1318
|
-
pendingAgentToolRef.current = false;
|
|
1319
1440
|
return;
|
|
1320
1441
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
}
|
|
1325
|
-
const parents = pendingParentsRef.current;
|
|
1326
|
-
pendingParentsRef.current = new Set();
|
|
1327
|
-
const wantGit = pendingGitRef.current;
|
|
1328
|
-
pendingGitRef.current = false;
|
|
1329
|
-
const wantAgentTool = pendingAgentToolRef.current;
|
|
1330
|
-
pendingAgentToolRef.current = false;
|
|
1331
|
-
// Reconcile the changed directories and Git overlay concurrently. Both are
|
|
1332
|
-
// independent remote reads; applyStatus makes their completion order safe.
|
|
1333
|
-
const eventReadSignal = eventReadAbortRef.current.signal;
|
|
1334
|
-
void (async () => {
|
|
1335
|
-
const paths = wantAgentTool ? loadedDirectoryPaths(treeRef.current) : [...parents];
|
|
1336
|
-
await Promise.all([
|
|
1337
|
-
wantGit ? refreshGitOverlay(eventReadSignal) : Promise.resolve(),
|
|
1338
|
-
Promise.all(paths.map((path) => reconcilePath(path, eventReadSignal))),
|
|
1339
|
-
]);
|
|
1340
|
-
})();
|
|
1341
|
-
}, delay);
|
|
1342
|
-
}, [enabled, active, acceptsEventReads, events, reconcilePath, refreshGitOverlay]);
|
|
1442
|
+
void reconcilePendingEvents();
|
|
1443
|
+
}, 150);
|
|
1444
|
+
}, [enabled, active, acceptsEventReads, events, rootPath, reconcilePendingEvents]);
|
|
1343
1445
|
|
|
1344
1446
|
useEffect(() => {
|
|
1345
1447
|
if (active && acceptsEventReads) return;
|
|
@@ -1349,7 +1451,7 @@ export function useSandboxFiles(
|
|
|
1349
1451
|
}
|
|
1350
1452
|
pendingParentsRef.current = new Set();
|
|
1351
1453
|
pendingGitRef.current = false;
|
|
1352
|
-
|
|
1454
|
+
eventReconcilePendingRef.current = false;
|
|
1353
1455
|
}, [active, acceptsEventReads]);
|
|
1354
1456
|
|
|
1355
1457
|
useEffect(
|
|
@@ -1357,6 +1459,7 @@ export function useSandboxFiles(
|
|
|
1357
1459
|
refreshAbortRef.current?.abort();
|
|
1358
1460
|
identityAbortRef.current.abort();
|
|
1359
1461
|
eventReadAbortRef.current.abort();
|
|
1462
|
+
eventReconcilePendingRef.current = false;
|
|
1360
1463
|
identityGenerationRef.current += 1;
|
|
1361
1464
|
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
1362
1465
|
},
|