@opengeni/react 0.57.0 → 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 +654 -22
- 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 +10 -3
- package/dist/realtime.js +229 -83
- 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 +274 -60
- 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,12 +1,14 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
HumanInputAnswer,
|
|
3
3
|
HumanInputQuestion,
|
|
4
|
+
SkillRecord,
|
|
4
5
|
SessionHumanInputRequest,
|
|
5
6
|
SubmitHumanInputResponseRequest,
|
|
6
7
|
} from "@opengeni/sdk";
|
|
7
8
|
import { ChevronDownIcon, ChevronUpIcon, MessageCircleQuestionIcon } from "lucide-react";
|
|
8
9
|
import { useEffect, useId, useRef, useState, type FormEvent, type ReactNode } from "react";
|
|
9
10
|
import { cn } from "../lib/cn";
|
|
11
|
+
import { useErrorMessage } from "../lib/error-message";
|
|
10
12
|
|
|
11
13
|
export type HumanInputAnswerDraft = {
|
|
12
14
|
values: string[];
|
|
@@ -14,6 +16,8 @@ export type HumanInputAnswerDraft = {
|
|
|
14
16
|
otherSelected: boolean;
|
|
15
17
|
};
|
|
16
18
|
|
|
19
|
+
class SkillReviewVerificationError extends Error {}
|
|
20
|
+
|
|
17
21
|
export type HumanInputFormMessages = {
|
|
18
22
|
title: string;
|
|
19
23
|
description: string;
|
|
@@ -40,7 +44,7 @@ export const defaultHumanInputFormMessages: HumanInputFormMessages = {
|
|
|
40
44
|
title: "Input required",
|
|
41
45
|
/** Multi-question chrome has no default subtitle; hosts may still override. */
|
|
42
46
|
description: "",
|
|
43
|
-
submit: "
|
|
47
|
+
submit: "Send answers",
|
|
44
48
|
skip: "Skip",
|
|
45
49
|
submitting: "Submitting…",
|
|
46
50
|
other: "Other",
|
|
@@ -64,6 +68,10 @@ export const defaultHumanInputFormMessages: HumanInputFormMessages = {
|
|
|
64
68
|
};
|
|
65
69
|
|
|
66
70
|
export type HumanInputFormProps = {
|
|
71
|
+
/** Scoped immutable revision reader. Saving a Skill fails closed without its full preview. */
|
|
72
|
+
loadSkillReview?:
|
|
73
|
+
| ((reference: NonNullable<HumanInputQuestion["skillReview"]>) => Promise<SkillRecord>)
|
|
74
|
+
| undefined;
|
|
67
75
|
request: Pick<SessionHumanInputRequest, "id" | "questions" | "allowSkip" | "expiresAt">;
|
|
68
76
|
onSubmit: (response: SubmitHumanInputResponseRequest) => void | Promise<void>;
|
|
69
77
|
submitting?: boolean | undefined;
|
|
@@ -78,6 +86,12 @@ export type HumanInputFormProps = {
|
|
|
78
86
|
autoFocus?: boolean | undefined;
|
|
79
87
|
/** Start collapsed to a compact bar (drafts still retained). */
|
|
80
88
|
defaultCollapsed?: boolean | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* Answer a yes/no decision (one required choice between an accept and a
|
|
91
|
+
* decline option, without Other) with two buttons instead of a radio list.
|
|
92
|
+
* Off by default; embedded conversations turn it on.
|
|
93
|
+
*/
|
|
94
|
+
decisionButtons?: boolean | undefined;
|
|
81
95
|
className?: string | undefined;
|
|
82
96
|
};
|
|
83
97
|
|
|
@@ -87,9 +101,18 @@ export type HumanInputFormProps = {
|
|
|
87
101
|
* options, sticky ask/submit chrome. Hosts can replace title/description or
|
|
88
102
|
* use `useHumanInputRequests` headlessly.
|
|
89
103
|
*/
|
|
90
|
-
export function HumanInputForm({
|
|
104
|
+
export function HumanInputForm(props: HumanInputFormProps) {
|
|
105
|
+
// The pending-request read model is refreshed after session events and
|
|
106
|
+
// returns newly allocated question arrays for the same durable request.
|
|
107
|
+
// Key the state owner by that request's lifecycle identity so reconciliation
|
|
108
|
+
// cannot erase an answer that the operator is still typing.
|
|
109
|
+
return <HumanInputRequestForm key={props.request.id} {...props} />;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function HumanInputRequestForm({
|
|
91
113
|
request,
|
|
92
114
|
onSubmit,
|
|
115
|
+
loadSkillReview,
|
|
93
116
|
submitting = false,
|
|
94
117
|
error,
|
|
95
118
|
title,
|
|
@@ -100,10 +123,14 @@ export function HumanInputForm({
|
|
|
100
123
|
messages: messageOverrides,
|
|
101
124
|
autoFocus = true,
|
|
102
125
|
defaultCollapsed = false,
|
|
126
|
+
decisionButtons = false,
|
|
103
127
|
className,
|
|
104
128
|
}: HumanInputFormProps) {
|
|
129
|
+
const formatError = useErrorMessage();
|
|
105
130
|
const messages = { ...defaultHumanInputFormMessages, ...messageOverrides };
|
|
106
131
|
const singleQuestion = request.questions.length === 1 ? request.questions[0]! : null;
|
|
132
|
+
const decision = decisionButtons ? binaryDecision(request.questions) : null;
|
|
133
|
+
const [decisionChoice, setDecisionChoice] = useState<string | null>(null);
|
|
107
134
|
const resolvedTitle =
|
|
108
135
|
title === undefined
|
|
109
136
|
? singleQuestion
|
|
@@ -134,16 +161,131 @@ export function HumanInputForm({
|
|
|
134
161
|
const submissionInFlight = useRef(false);
|
|
135
162
|
const submissionGeneration = useRef(0);
|
|
136
163
|
const busy = submitting || submittingInternally;
|
|
137
|
-
|
|
164
|
+
const reviewIdentity = JSON.stringify(
|
|
165
|
+
request.questions
|
|
166
|
+
.filter((question) => question.skillReview)
|
|
167
|
+
.map((question) => ({
|
|
168
|
+
id: question.id,
|
|
169
|
+
reference: {
|
|
170
|
+
sourceOperationId: question.skillReview!.sourceOperationId,
|
|
171
|
+
skillId: question.skillReview!.skillId,
|
|
172
|
+
revisionId: question.skillReview!.revisionId,
|
|
173
|
+
expectedRevisionId: question.skillReview!.expectedRevisionId,
|
|
174
|
+
expectedScopeVersion: question.skillReview!.expectedScopeVersion,
|
|
175
|
+
...(question.skillReview!.removalOperationId
|
|
176
|
+
? { removalOperationId: question.skillReview!.removalOperationId }
|
|
177
|
+
: {}),
|
|
178
|
+
},
|
|
179
|
+
})),
|
|
180
|
+
);
|
|
181
|
+
const [reviewReload, setReviewReload] = useState(0);
|
|
182
|
+
const [reviews, setReviews] = useState<{
|
|
183
|
+
loader: typeof loadSkillReview;
|
|
184
|
+
identity: string;
|
|
185
|
+
records: Record<string, SkillRecord>;
|
|
186
|
+
error: string | null;
|
|
187
|
+
} | null>(null);
|
|
138
188
|
useEffect(() => {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
189
|
+
let current = true;
|
|
190
|
+
const questions = JSON.parse(reviewIdentity) as Array<{
|
|
191
|
+
id: string;
|
|
192
|
+
reference: NonNullable<HumanInputQuestion["skillReview"]>;
|
|
193
|
+
}>;
|
|
194
|
+
if (!questions.length) return;
|
|
195
|
+
setReviews(null);
|
|
196
|
+
void Promise.all(
|
|
197
|
+
questions.map(async (question) => {
|
|
198
|
+
if (!loadSkillReview)
|
|
199
|
+
throw new Error(
|
|
200
|
+
"This client cannot preview Skill files. Ask your administrator for a review-capable client.",
|
|
201
|
+
);
|
|
202
|
+
const reference = question.reference;
|
|
203
|
+
const record = await loadSkillReview(reference);
|
|
204
|
+
if (
|
|
205
|
+
record.id !== reference.skillId ||
|
|
206
|
+
record.revisionId !== reference.revisionId ||
|
|
207
|
+
(record.removalOperationId ?? undefined) !== reference.removalOperationId ||
|
|
208
|
+
!record.files.some((file) => file.path === "SKILL.md")
|
|
209
|
+
) {
|
|
210
|
+
throw new SkillReviewVerificationError(
|
|
211
|
+
"The requested Skill revision could not be verified.",
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return [question.id, record] as const;
|
|
215
|
+
}),
|
|
216
|
+
)
|
|
217
|
+
.then((records) => {
|
|
218
|
+
if (current)
|
|
219
|
+
setReviews({
|
|
220
|
+
loader: loadSkillReview,
|
|
221
|
+
identity: reviewIdentity,
|
|
222
|
+
records: Object.fromEntries(records),
|
|
223
|
+
error: null,
|
|
224
|
+
});
|
|
225
|
+
})
|
|
226
|
+
.catch((cause) => {
|
|
227
|
+
if (current)
|
|
228
|
+
setReviews({
|
|
229
|
+
loader: loadSkillReview,
|
|
230
|
+
identity: reviewIdentity,
|
|
231
|
+
records: {},
|
|
232
|
+
error: formatError(
|
|
233
|
+
cause,
|
|
234
|
+
cause instanceof SkillReviewVerificationError
|
|
235
|
+
? cause.message
|
|
236
|
+
: !loadSkillReview
|
|
237
|
+
? "This client cannot preview Skill files. Ask your administrator for a review-capable client."
|
|
238
|
+
: undefined,
|
|
239
|
+
),
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
return () => {
|
|
243
|
+
current = false;
|
|
244
|
+
};
|
|
245
|
+
}, [loadSkillReview, reviewIdentity, reviewReload, formatError]);
|
|
246
|
+
const visibleReviews =
|
|
247
|
+
reviews?.loader === loadSkillReview && reviews?.identity === reviewIdentity ? reviews : null;
|
|
248
|
+
const preview = (question: HumanInputQuestion) => {
|
|
249
|
+
if (!question.skillReview) return null;
|
|
250
|
+
const record = visibleReviews?.records[question.id];
|
|
251
|
+
return (
|
|
252
|
+
<div className="mb-3 min-w-0 space-y-2" data-skill-review="">
|
|
253
|
+
{record ? (
|
|
254
|
+
<>
|
|
255
|
+
<p className="text-og-sm">
|
|
256
|
+
{record.title ?? "Skill"} · {record.scope} · {record.files.length} files
|
|
257
|
+
</p>
|
|
258
|
+
<p className="text-og-xs text-og-fg-muted">
|
|
259
|
+
{question.skillReview.removalOperationId
|
|
260
|
+
? "Permanently deletes this Skill and all stored revisions. This cannot be undone; conversations remain unchanged."
|
|
261
|
+
: "Saving activates these exact files. No additional review is required."}
|
|
262
|
+
</p>
|
|
263
|
+
{record.files.map((file) => (
|
|
264
|
+
<details key={file.path} open={file.path === "SKILL.md"}>
|
|
265
|
+
<summary className="cursor-pointer break-all text-og-sm">{file.path}</summary>
|
|
266
|
+
<pre className="max-h-64 overflow-auto whitespace-pre-wrap break-words rounded-og-md bg-og-surface-1 p-2 text-og-xs">
|
|
267
|
+
{file.content}
|
|
268
|
+
</pre>
|
|
269
|
+
</details>
|
|
270
|
+
))}
|
|
271
|
+
</>
|
|
272
|
+
) : visibleReviews?.error ? (
|
|
273
|
+
<>
|
|
274
|
+
<p role="alert" className="text-og-sm">
|
|
275
|
+
{visibleReviews.error}
|
|
276
|
+
</p>
|
|
277
|
+
<button type="button" onClick={() => setReviewReload((value) => value + 1)}>
|
|
278
|
+
Retry preview
|
|
279
|
+
</button>
|
|
280
|
+
</>
|
|
281
|
+
) : (
|
|
282
|
+
<p role="status" className="text-og-sm">
|
|
283
|
+
Loading the exact Skill files…
|
|
284
|
+
</p>
|
|
285
|
+
)}
|
|
286
|
+
</div>
|
|
287
|
+
);
|
|
288
|
+
};
|
|
147
289
|
|
|
148
290
|
useEffect(() => {
|
|
149
291
|
if (collapsed) {
|
|
@@ -199,7 +341,7 @@ export function HumanInputForm({
|
|
|
199
341
|
await onSubmit(response);
|
|
200
342
|
} catch (cause) {
|
|
201
343
|
if (generation === submissionGeneration.current) {
|
|
202
|
-
setSubmissionError(
|
|
344
|
+
setSubmissionError(formatError(cause));
|
|
203
345
|
}
|
|
204
346
|
} finally {
|
|
205
347
|
if (generation === submissionGeneration.current) {
|
|
@@ -234,6 +376,22 @@ export function HumanInputForm({
|
|
|
234
376
|
}
|
|
235
377
|
return;
|
|
236
378
|
}
|
|
379
|
+
const unreviewedSave = request.questions.find(
|
|
380
|
+
(question) =>
|
|
381
|
+
question.skillReview &&
|
|
382
|
+
!visibleReviews?.records[question.id] &&
|
|
383
|
+
result.answers.some(
|
|
384
|
+
(answer) => answer.questionId === question.id && answer.values.includes("save"),
|
|
385
|
+
),
|
|
386
|
+
);
|
|
387
|
+
if (unreviewedSave) {
|
|
388
|
+
setValidationErrors({
|
|
389
|
+
[unreviewedSave.id]: unreviewedSave.skillReview?.removalOperationId
|
|
390
|
+
? "Load the exact Skill proposal before approving permanent deletion."
|
|
391
|
+
: "Load the exact Skill files before saving.",
|
|
392
|
+
});
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
237
395
|
await submitResponse({ outcome: "answered", answers: result.answers });
|
|
238
396
|
};
|
|
239
397
|
|
|
@@ -309,7 +467,7 @@ export function HumanInputForm({
|
|
|
309
467
|
<div className="flex flex-wrap items-baseline gap-x-2 gap-y-0.5">
|
|
310
468
|
<h2 id={titleId} className="text-og-md font-semibold text-og-fg">
|
|
311
469
|
{resolvedTitle}
|
|
312
|
-
{singleQuestion?.required && !request.allowSkip ? (
|
|
470
|
+
{singleQuestion?.required && !request.allowSkip && !decision ? (
|
|
313
471
|
<span aria-hidden className="ml-1 text-og-status-failed">
|
|
314
472
|
*
|
|
315
473
|
</span>
|
|
@@ -356,104 +514,245 @@ export function HumanInputForm({
|
|
|
356
514
|
</div>
|
|
357
515
|
</header>
|
|
358
516
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
517
|
+
{decision ? (
|
|
518
|
+
<>
|
|
519
|
+
{decision.question.helpText ||
|
|
520
|
+
decision.accept.description ||
|
|
521
|
+
decision.decline.description ? (
|
|
522
|
+
<div className="shrink-0 space-y-1 px-4 pt-3 text-og-sm text-og-fg-muted">
|
|
523
|
+
{decision.question.label && decision.question.helpText ? (
|
|
524
|
+
<p>{decision.question.helpText}</p>
|
|
525
|
+
) : null}
|
|
526
|
+
{[decision.accept, decision.decline].map((option) =>
|
|
527
|
+
option.description ? (
|
|
528
|
+
<p key={option.id}>
|
|
529
|
+
<span className="font-medium text-og-fg">{option.label}</span>
|
|
530
|
+
{" · "}
|
|
531
|
+
{option.description}
|
|
532
|
+
</p>
|
|
533
|
+
) : null,
|
|
534
|
+
)}
|
|
535
|
+
</div>
|
|
536
|
+
) : null}
|
|
537
|
+
{(error ?? submissionError) ? (
|
|
538
|
+
<p role="alert" className="shrink-0 px-4 pt-3 text-og-sm text-og-status-failed">
|
|
539
|
+
{error ?? submissionError}
|
|
540
|
+
</p>
|
|
541
|
+
) : null}
|
|
542
|
+
<footer
|
|
543
|
+
className="flex shrink-0 flex-wrap items-center justify-end gap-2 px-4 py-3"
|
|
544
|
+
data-human-input-decision=""
|
|
545
|
+
>
|
|
546
|
+
{request.allowSkip ? (
|
|
547
|
+
<button
|
|
548
|
+
type="button"
|
|
549
|
+
disabled={busy}
|
|
550
|
+
onClick={() => void submitResponse({ outcome: "skipped" })}
|
|
551
|
+
className="mr-auto inline-flex min-h-9 items-center rounded-og-md px-2 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-hover hover:text-og-fg disabled:opacity-50 pointer-coarse:min-h-11"
|
|
552
|
+
>
|
|
553
|
+
{resolvedSkipLabel}
|
|
554
|
+
</button>
|
|
555
|
+
) : null}
|
|
556
|
+
{[decision.decline, decision.accept].map((option) => {
|
|
557
|
+
const primary = option === decision.accept;
|
|
386
558
|
return (
|
|
387
|
-
<
|
|
388
|
-
key={
|
|
389
|
-
|
|
390
|
-
|
|
559
|
+
<button
|
|
560
|
+
key={option.id}
|
|
561
|
+
type="button"
|
|
562
|
+
disabled={busy}
|
|
563
|
+
ref={
|
|
564
|
+
!primary && autoFocus
|
|
565
|
+
? (node) => {
|
|
566
|
+
if (node && !node.dataset.ogFocused) {
|
|
567
|
+
node.dataset.ogFocused = "";
|
|
568
|
+
node.focus({ preventScroll: true });
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
: undefined
|
|
572
|
+
}
|
|
573
|
+
data-human-input-choice={option.id}
|
|
574
|
+
onClick={() => {
|
|
575
|
+
setDecisionChoice(option.id);
|
|
576
|
+
void submitResponse({
|
|
577
|
+
outcome: "answered",
|
|
578
|
+
answers: [{ questionId: decision.question.id, values: [option.id] }],
|
|
579
|
+
});
|
|
580
|
+
}}
|
|
581
|
+
className={cn(
|
|
582
|
+
"inline-flex min-h-9 items-center rounded-og-md border px-3.5 py-1.5 text-og-sm font-medium transition disabled:opacity-50 pointer-coarse:min-h-11",
|
|
583
|
+
primary
|
|
584
|
+
? "border-og-primary-border bg-og-primary text-og-primary-fg hover:bg-og-primary-hover"
|
|
585
|
+
: "border-og-border bg-og-surface-1 text-og-fg hover:bg-og-surface-2",
|
|
586
|
+
)}
|
|
391
587
|
>
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
draft={drafts[question.id] ?? emptyDraft()}
|
|
395
|
-
fieldId={`${formId}-${index}`}
|
|
396
|
-
error={validationErrors[question.id]}
|
|
397
|
-
messages={messages}
|
|
398
|
-
autoFocus={autoFocus && index === 0}
|
|
399
|
-
firstOption={index === 0}
|
|
400
|
-
showPromptChrome
|
|
401
|
-
allowSkip={request.allowSkip}
|
|
402
|
-
busy={busy}
|
|
403
|
-
onUpdate={(apply) => update(question.id, apply)}
|
|
404
|
-
/>
|
|
405
|
-
</div>
|
|
588
|
+
{busy && decisionChoice === option.id ? messages.submitting : option.label}
|
|
589
|
+
</button>
|
|
406
590
|
);
|
|
407
591
|
})}
|
|
408
|
-
</
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
{
|
|
418
|
-
|
|
592
|
+
</footer>
|
|
593
|
+
</>
|
|
594
|
+
) : (
|
|
595
|
+
<>
|
|
596
|
+
<div className="relative flex min-h-0 flex-1 flex-col overflow-hidden">
|
|
597
|
+
<div
|
|
598
|
+
ref={scrollRef}
|
|
599
|
+
className="min-h-0 flex-1 overflow-y-auto overscroll-contain [scrollbar-gutter:stable]"
|
|
600
|
+
>
|
|
601
|
+
<fieldset disabled={busy} className="min-w-0 space-y-4 px-4 py-3">
|
|
602
|
+
{request.questions.map((question, index) => {
|
|
603
|
+
if (singleQuestion) {
|
|
604
|
+
// Title already carries the question; only render the control + help extras.
|
|
605
|
+
return (
|
|
606
|
+
<div key={question.id} data-human-input-question={question.id}>
|
|
607
|
+
{preview(question)}
|
|
608
|
+
<QuestionControls
|
|
609
|
+
question={question}
|
|
610
|
+
questionNumber={null}
|
|
611
|
+
labelledBy={titleId}
|
|
612
|
+
draft={drafts[question.id] ?? emptyDraft()}
|
|
613
|
+
fieldId={`${formId}-${index}`}
|
|
614
|
+
error={validationErrors[question.id]}
|
|
615
|
+
messages={messages}
|
|
616
|
+
autoFocus={autoFocus}
|
|
617
|
+
firstOption
|
|
618
|
+
showPromptChrome={false}
|
|
619
|
+
allowSkip={request.allowSkip}
|
|
620
|
+
busy={busy}
|
|
621
|
+
onUpdate={(apply) => update(question.id, apply)}
|
|
622
|
+
/>
|
|
623
|
+
</div>
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
return (
|
|
627
|
+
<div
|
|
628
|
+
key={question.id}
|
|
629
|
+
data-human-input-question={question.id}
|
|
630
|
+
className="flex flex-col gap-1.5"
|
|
631
|
+
>
|
|
632
|
+
{preview(question)}
|
|
633
|
+
<QuestionControls
|
|
634
|
+
question={question}
|
|
635
|
+
questionNumber={index + 1}
|
|
636
|
+
labelledBy={undefined}
|
|
637
|
+
draft={drafts[question.id] ?? emptyDraft()}
|
|
638
|
+
fieldId={`${formId}-${index}`}
|
|
639
|
+
error={validationErrors[question.id]}
|
|
640
|
+
messages={messages}
|
|
641
|
+
autoFocus={autoFocus && index === 0}
|
|
642
|
+
firstOption={index === 0}
|
|
643
|
+
showPromptChrome
|
|
644
|
+
allowSkip={request.allowSkip}
|
|
645
|
+
busy={busy}
|
|
646
|
+
onUpdate={(apply) => update(question.id, apply)}
|
|
647
|
+
/>
|
|
648
|
+
</div>
|
|
649
|
+
);
|
|
650
|
+
})}
|
|
651
|
+
</fieldset>
|
|
652
|
+
</div>
|
|
653
|
+
{overflowBelow ? (
|
|
654
|
+
<div
|
|
655
|
+
className="pointer-events-none absolute inset-x-0 bottom-0 z-[1] flex flex-col items-center"
|
|
656
|
+
aria-hidden="true"
|
|
657
|
+
>
|
|
658
|
+
<div className="h-10 w-full bg-gradient-to-t from-og-surface-1 via-og-surface-1/85 to-transparent" />
|
|
659
|
+
<span className="-mt-5 mb-1 rounded-og-full bg-og-surface-1 px-2.5 py-0.5 text-og-xs font-medium text-og-fg-muted shadow-og-sm ring-1 ring-og-border/60">
|
|
660
|
+
{messages.moreBelow}
|
|
661
|
+
</span>
|
|
662
|
+
</div>
|
|
663
|
+
) : null}
|
|
419
664
|
</div>
|
|
420
|
-
) : null}
|
|
421
|
-
</div>
|
|
422
665
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
666
|
+
{(error ?? submissionError) ? (
|
|
667
|
+
<p
|
|
668
|
+
role="alert"
|
|
669
|
+
className="relative z-10 shrink-0 px-4 pb-1 text-og-sm text-og-status-failed"
|
|
670
|
+
>
|
|
671
|
+
{error ?? submissionError}
|
|
672
|
+
</p>
|
|
673
|
+
) : null}
|
|
431
674
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
675
|
+
<footer className="relative z-10 flex shrink-0 items-center justify-end gap-2 border-t border-og-status-waiting/20 bg-og-surface-1/95 px-4 py-3 backdrop-blur-[2px]">
|
|
676
|
+
{request.allowSkip ? (
|
|
677
|
+
<button
|
|
678
|
+
type="button"
|
|
679
|
+
disabled={busy}
|
|
680
|
+
onClick={() => void submitResponse({ outcome: "skipped" })}
|
|
681
|
+
className="inline-flex min-h-9 items-center rounded-og-md border border-og-border px-3 py-1.5 text-og-sm font-medium text-og-fg-muted transition-colors hover:bg-og-surface-1 hover:text-og-fg disabled:opacity-50"
|
|
682
|
+
>
|
|
683
|
+
{resolvedSkipLabel}
|
|
684
|
+
</button>
|
|
685
|
+
) : null}
|
|
686
|
+
<button
|
|
687
|
+
type="submit"
|
|
688
|
+
disabled={busy}
|
|
689
|
+
className="inline-flex min-h-9 items-center rounded-og-md border border-og-primary-border bg-og-primary text-og-primary-fg px-3 py-1.5 text-og-sm font-medium transition hover:bg-og-primary-hover disabled:opacity-50"
|
|
690
|
+
>
|
|
691
|
+
{busy ? messages.submitting : resolvedSubmitLabel}
|
|
692
|
+
</button>
|
|
693
|
+
</footer>
|
|
694
|
+
</>
|
|
695
|
+
)}
|
|
451
696
|
</form>
|
|
452
697
|
);
|
|
453
698
|
}
|
|
454
699
|
|
|
700
|
+
// Unambiguous approve/decline verbs only: "Continue with A" vs "Keep B" is a
|
|
701
|
+
// real choice between two options, not a yes/no decision.
|
|
702
|
+
const ACCEPT_WORDS = new Set(["approve", "approved", "yes", "confirm", "allow", "accept"]);
|
|
703
|
+
const DECLINE_WORDS = new Set(["cancel", "decline", "reject", "deny", "no", "don't", "dont"]);
|
|
704
|
+
|
|
705
|
+
function firstWord(label: string): string {
|
|
706
|
+
return (
|
|
707
|
+
label
|
|
708
|
+
.trim()
|
|
709
|
+
.toLowerCase()
|
|
710
|
+
.replace(/[’]/g, "'")
|
|
711
|
+
.split(/[\s,.:;!?()]+/)[0] ?? ""
|
|
712
|
+
);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* A yes/no decision (an approval asked as a question): one required
|
|
717
|
+
* single-choice question with exactly an accept and a decline option. It is
|
|
718
|
+
* answered with two buttons; an "Other" free-text answer has no meaning for it,
|
|
719
|
+
* and the composer still accepts a different instruction.
|
|
720
|
+
*/
|
|
721
|
+
export function binaryDecision(questions: readonly HumanInputQuestion[]): {
|
|
722
|
+
question: HumanInputQuestion;
|
|
723
|
+
accept: HumanInputQuestion["options"][number];
|
|
724
|
+
decline: HumanInputQuestion["options"][number];
|
|
725
|
+
} | null {
|
|
726
|
+
if (questions.length !== 1) return null;
|
|
727
|
+
const question = questions[0]!;
|
|
728
|
+
if (
|
|
729
|
+
question.kind !== "single_select" ||
|
|
730
|
+
question.skillReview ||
|
|
731
|
+
// The runtime marks every choice question `allowOther`, so it is not a
|
|
732
|
+
// signal here; a different answer goes through the composer instead.
|
|
733
|
+
!question.required ||
|
|
734
|
+
question.options.length !== 2
|
|
735
|
+
)
|
|
736
|
+
return null;
|
|
737
|
+
const [first, second] = question.options as [
|
|
738
|
+
HumanInputQuestion["options"][number],
|
|
739
|
+
HumanInputQuestion["options"][number],
|
|
740
|
+
];
|
|
741
|
+
const kind = (option: HumanInputQuestion["options"][number]) => {
|
|
742
|
+
const word = firstWord(option.label);
|
|
743
|
+
return ACCEPT_WORDS.has(word) ? "accept" : DECLINE_WORDS.has(word) ? "decline" : null;
|
|
744
|
+
};
|
|
745
|
+
const a = kind(first);
|
|
746
|
+
const b = kind(second);
|
|
747
|
+
if (a === "accept" && b === "decline") return { question, accept: first, decline: second };
|
|
748
|
+
if (a === "decline" && b === "accept") return { question, accept: second, decline: first };
|
|
749
|
+
return null;
|
|
750
|
+
}
|
|
751
|
+
|
|
455
752
|
function QuestionControls({
|
|
456
753
|
question,
|
|
754
|
+
questionNumber,
|
|
755
|
+
labelledBy,
|
|
457
756
|
draft,
|
|
458
757
|
fieldId,
|
|
459
758
|
error,
|
|
@@ -466,6 +765,8 @@ function QuestionControls({
|
|
|
466
765
|
onUpdate,
|
|
467
766
|
}: {
|
|
468
767
|
question: HumanInputQuestion;
|
|
768
|
+
questionNumber: number | null;
|
|
769
|
+
labelledBy: string | undefined;
|
|
469
770
|
draft: HumanInputAnswerDraft;
|
|
470
771
|
fieldId: string;
|
|
471
772
|
error: string | undefined;
|
|
@@ -479,6 +780,13 @@ function QuestionControls({
|
|
|
479
780
|
}) {
|
|
480
781
|
const errorId = `${fieldId}-error`;
|
|
481
782
|
const helpId = `${fieldId}-help`;
|
|
783
|
+
const labelId = `${fieldId}-label`;
|
|
784
|
+
const promptId = `${fieldId}-prompt`;
|
|
785
|
+
const otherChoiceId = `${fieldId}-other-choice`;
|
|
786
|
+
const otherLabelId = `${fieldId}-other-label`;
|
|
787
|
+
const otherTextId = `${fieldId}-other-text`;
|
|
788
|
+
const visibleLabel = question.label ?? question.prompt;
|
|
789
|
+
const controlLabelId = showPromptChrome ? labelId : labelledBy;
|
|
482
790
|
const hint =
|
|
483
791
|
question.kind === "multi_select"
|
|
484
792
|
? messages.selectionHint(
|
|
@@ -488,22 +796,33 @@ function QuestionControls({
|
|
|
488
796
|
: null;
|
|
489
797
|
const describedBy =
|
|
490
798
|
[
|
|
799
|
+
question.label && showPromptChrome ? promptId : null,
|
|
491
800
|
question.helpText && showPromptChrome ? helpId : null,
|
|
492
801
|
hint ? `${fieldId}-hint` : null,
|
|
493
802
|
error ? errorId : null,
|
|
494
803
|
]
|
|
495
804
|
.filter(Boolean)
|
|
496
805
|
.join(" ") || undefined;
|
|
806
|
+
const selectOtherDraft = (current: HumanInputAnswerDraft): HumanInputAnswerDraft => ({
|
|
807
|
+
...current,
|
|
808
|
+
otherSelected: true,
|
|
809
|
+
...(question.kind === "single_select" ? { values: [] } : {}),
|
|
810
|
+
});
|
|
497
811
|
return (
|
|
498
812
|
<>
|
|
499
813
|
{showPromptChrome ? (
|
|
500
814
|
<>
|
|
501
815
|
<div className="flex flex-wrap items-baseline gap-x-2">
|
|
502
816
|
<label
|
|
817
|
+
id={labelId}
|
|
503
818
|
htmlFor={question.kind === "text" ? fieldId : undefined}
|
|
504
819
|
className="text-og-sm font-medium text-og-fg"
|
|
505
820
|
>
|
|
506
|
-
{
|
|
821
|
+
{questionNumber === null ? null : (
|
|
822
|
+
<span className="mr-1.5 tabular-nums text-og-fg-muted">{questionNumber}.</span>
|
|
823
|
+
)}
|
|
824
|
+
{questionNumber === null ? null : " "}
|
|
825
|
+
{visibleLabel}
|
|
507
826
|
{question.required && !allowSkip ? (
|
|
508
827
|
<span aria-hidden className="ml-1 text-og-status-failed">
|
|
509
828
|
*
|
|
@@ -515,7 +834,11 @@ function QuestionControls({
|
|
|
515
834
|
) : null}
|
|
516
835
|
</label>
|
|
517
836
|
</div>
|
|
518
|
-
{question.label ?
|
|
837
|
+
{question.label ? (
|
|
838
|
+
<p id={promptId} className="text-og-sm text-og-fg-muted">
|
|
839
|
+
{question.prompt}
|
|
840
|
+
</p>
|
|
841
|
+
) : null}
|
|
519
842
|
{question.helpText ? (
|
|
520
843
|
<p id={helpId} className="text-og-xs text-og-fg-subtle">
|
|
521
844
|
{question.helpText}
|
|
@@ -556,6 +879,7 @@ function QuestionControls({
|
|
|
556
879
|
}))
|
|
557
880
|
}
|
|
558
881
|
aria-invalid={Boolean(error)}
|
|
882
|
+
aria-labelledby={controlLabelId}
|
|
559
883
|
aria-describedby={describedBy}
|
|
560
884
|
autoFocus={autoFocus}
|
|
561
885
|
rows={2}
|
|
@@ -564,6 +888,7 @@ function QuestionControls({
|
|
|
564
888
|
) : (
|
|
565
889
|
<div
|
|
566
890
|
role={question.kind === "single_select" ? "radiogroup" : "group"}
|
|
891
|
+
aria-labelledby={controlLabelId}
|
|
567
892
|
aria-describedby={describedBy}
|
|
568
893
|
className="flex flex-col gap-0.5"
|
|
569
894
|
>
|
|
@@ -613,8 +938,8 @@ function QuestionControls({
|
|
|
613
938
|
</label>
|
|
614
939
|
);
|
|
615
940
|
})}
|
|
616
|
-
{question.
|
|
617
|
-
<
|
|
941
|
+
{!question.skillReview ? (
|
|
942
|
+
<div
|
|
618
943
|
className={cn(
|
|
619
944
|
"flex items-start gap-2.5 rounded-og-md px-2.5 py-2 transition-colors",
|
|
620
945
|
draft.otherSelected
|
|
@@ -623,8 +948,10 @@ function QuestionControls({
|
|
|
623
948
|
)}
|
|
624
949
|
>
|
|
625
950
|
<input
|
|
951
|
+
id={otherChoiceId}
|
|
626
952
|
type={question.kind === "single_select" ? "radio" : "checkbox"}
|
|
627
953
|
name={question.kind === "single_select" ? fieldId : undefined}
|
|
954
|
+
aria-labelledby={otherLabelId}
|
|
628
955
|
checked={draft.otherSelected}
|
|
629
956
|
autoFocus={autoFocus && firstOption && question.options.length === 0}
|
|
630
957
|
onChange={(event) =>
|
|
@@ -639,22 +966,35 @@ function QuestionControls({
|
|
|
639
966
|
className="mt-2 accent-og-accent"
|
|
640
967
|
/>
|
|
641
968
|
<span className="min-w-0 flex-1">
|
|
642
|
-
<
|
|
969
|
+
<label
|
|
970
|
+
id={otherLabelId}
|
|
971
|
+
htmlFor={otherChoiceId}
|
|
972
|
+
className="block text-og-sm font-medium"
|
|
973
|
+
>
|
|
974
|
+
{messages.other}
|
|
975
|
+
</label>
|
|
976
|
+
<label htmlFor={otherTextId} className="sr-only">
|
|
977
|
+
{messages.other} answer for {visibleLabel}
|
|
978
|
+
</label>
|
|
643
979
|
<input
|
|
980
|
+
id={otherTextId}
|
|
644
981
|
type="text"
|
|
645
982
|
value={draft.other}
|
|
646
|
-
disabled={
|
|
983
|
+
disabled={busy}
|
|
647
984
|
placeholder="Type a value…"
|
|
648
|
-
|
|
985
|
+
onClick={() => onUpdate(selectOtherDraft)}
|
|
986
|
+
onFocus={() => onUpdate(selectOtherDraft)}
|
|
987
|
+
onChange={(event) => {
|
|
988
|
+
const other = event.target.value;
|
|
649
989
|
onUpdate((current) => ({
|
|
650
|
-
...current,
|
|
651
|
-
other
|
|
652
|
-
}))
|
|
653
|
-
}
|
|
990
|
+
...selectOtherDraft(current),
|
|
991
|
+
other,
|
|
992
|
+
}));
|
|
993
|
+
}}
|
|
654
994
|
className="mt-1.5 w-full rounded-og-sm border border-og-border bg-og-surface-1 px-2 py-1.5 text-og-sm text-og-fg outline-hidden focus:border-og-accent disabled:opacity-50"
|
|
655
995
|
/>
|
|
656
996
|
</span>
|
|
657
|
-
</
|
|
997
|
+
</div>
|
|
658
998
|
) : null}
|
|
659
999
|
</div>
|
|
660
1000
|
)}
|
|
@@ -678,12 +1018,13 @@ export function answersFromDrafts(
|
|
|
678
1018
|
for (const question of questions) {
|
|
679
1019
|
const draft = drafts[question.id] ?? emptyDraft();
|
|
680
1020
|
const values = question.kind === "text" ? draft.values.filter(Boolean) : draft.values;
|
|
681
|
-
const other = draft.otherSelected ? draft.other
|
|
682
|
-
const
|
|
1021
|
+
const other = draft.otherSelected ? draft.other : "";
|
|
1022
|
+
const hasOther = Boolean(other.trim());
|
|
1023
|
+
const supplied = values.length + (hasOther ? 1 : 0);
|
|
683
1024
|
|
|
684
1025
|
// Other-selected-but-empty must win over generic "required" — otherwise the
|
|
685
1026
|
// user sees the wrong diagnosis next to a clearly selected control.
|
|
686
|
-
if (question.kind !== "text" && draft.otherSelected && !
|
|
1027
|
+
if (question.kind !== "text" && draft.otherSelected && !hasOther) {
|
|
687
1028
|
errors[question.id] = messages.otherRequired;
|
|
688
1029
|
continue;
|
|
689
1030
|
}
|
|
@@ -708,7 +1049,7 @@ export function answersFromDrafts(
|
|
|
708
1049
|
answers.push({
|
|
709
1050
|
questionId: question.id,
|
|
710
1051
|
values,
|
|
711
|
-
...(
|
|
1052
|
+
...(hasOther ? { other } : {}),
|
|
712
1053
|
});
|
|
713
1054
|
}
|
|
714
1055
|
}
|