@jini-ai/ui 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/core/theme/validation.js +40 -38
- package/dist/features/a2ui/renderer.js +15 -13
- package/dist/features/about/react/components/AboutTab.js +64 -34
- package/dist/features/about/rules.d.ts +2 -2
- package/dist/features/about/rules.js +156 -129
- package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
- package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
- package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
- package/dist/features/admin-widgets/components/InfoTip.js +34 -7
- package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
- package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
- package/dist/features/admin-widgets/components/Select/Select.hooks.d.ts +21 -0
- package/dist/features/admin-widgets/components/Select/Select.hooks.js +24 -2
- package/dist/features/admin-widgets/components/Select/Select.js +4 -3
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
- package/dist/features/admin-widgets/index.d.ts +14 -2
- package/dist/features/admin-widgets/index.js +7 -1
- package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
- package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
- package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
- package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
- package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
- package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
- package/dist/features/asset-tree-browser/rules.js +40 -22
- package/dist/features/browser-chrome/rules.js +74 -70
- package/dist/features/charts/browser.js +11 -5
- package/dist/features/charts/react.js +2 -2
- package/dist/features/charts/table.js +2 -2
- package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
- package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
- package/dist/features/connectors/ConnectorsBrowser.js +26 -14
- package/dist/features/connectors/components/ConnectorCard.js +67 -38
- package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
- package/dist/features/connectors/components/ConnectorGrid.js +11 -6
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
- package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
- package/dist/features/connectors/rules.d.ts +8 -1
- package/dist/features/connectors/rules.js +42 -20
- package/dist/features/connectors/types.d.ts +11 -0
- package/dist/features/execution/constants.d.ts +4 -10
- package/dist/features/execution/constants.js +9 -94
- package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
- package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
- package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
- package/dist/features/execution/react/components/ExecutionTab.js +52 -30
- package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
- package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
- package/dist/features/execution/react/hooks/useReasoningControl.d.ts +1 -1
- package/dist/features/execution/react/hooks/useReasoningControl.js +116 -75
- package/dist/features/execution/rules.d.ts +13 -2
- package/dist/features/execution/rules.js +51 -11
- package/dist/features/execution/types.d.ts +6 -42
- package/dist/features/execution/types.js +0 -17
- package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
- package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
- package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
- package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
- package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
- package/dist/features/html-editor/css.js +76 -69
- package/dist/features/html-editor/editor-blocks.js +47 -33
- package/dist/features/html-editor/editor-serialization.js +6 -5
- package/dist/features/html-editor/protected-elements.js +39 -28
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
- package/dist/features/html-editor/source-splice.js +51 -30
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
- package/dist/features/i18n/locale.js +20 -16
- package/dist/features/iframe-pool/react/dom-sync.js +8 -6
- package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
- package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/native/data-table.manifest.d.ts +6 -6
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
- package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.d.ts +6 -6
- package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
- package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
- package/dist/features/lexical-rich-text-editor/rules.js +87 -74
- package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
- package/dist/features/mcp-ui/secret-card.js +111 -61
- package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
- package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
- package/dist/features/mcp-ui/surfaces/document.js +10 -2
- package/dist/features/mcp-ui/surfaces/fields.js +30 -50
- package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
- package/dist/features/mcp-ui/surfaces/form.js +43 -21
- package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
- package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
- package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
- package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
- package/dist/features/media-providers/constants.d.ts +1 -0
- package/dist/features/media-providers/constants.js +2 -81
- package/dist/features/media-providers/index.d.ts +1 -1
- package/dist/features/media-providers/ports.d.ts +2 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
- package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
- package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
- package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
- package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
- package/dist/features/media-providers/rules.js +17 -10
- package/dist/features/media-providers/types.d.ts +4 -22
- package/dist/features/media-providers/types.js +3 -8
- package/dist/features/memory/formatters.js +127 -92
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
- package/dist/features/memory/react/components/MemoryList.js +37 -18
- package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
- package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
- package/dist/features/observability/long-task.d.ts +0 -12
- package/dist/features/observability/long-task.js +15 -19
- package/dist/features/observability/resource-error.d.ts +0 -10
- package/dist/features/observability/resource-error.js +18 -13
- package/dist/features/observability/stuck-run.js +10 -6
- package/dist/features/observability/telemetry-url.d.ts +6 -0
- package/dist/features/observability/telemetry-url.js +16 -0
- package/dist/features/observability/white-screen.js +12 -24
- package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
- package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
- package/dist/features/progress-card/components/ProgressCard.js +7 -3
- package/dist/features/progress-card/reference-adapters.js +59 -54
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
- package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
- package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
- package/dist/features/resource-dashboard/rules.js +2 -8
- package/dist/features/sketch-editor/dom.js +150 -99
- package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
- package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
- package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
- package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
- package/dist/features/skills/react/components/SkillRow.js +38 -18
- package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
- package/dist/features/skills/react/components/SkillsTab.js +24 -14
- package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
- package/dist/features/skills/rules.js +32 -23
- package/dist/features/source-config-list/agent-handles.js +2 -1
- package/dist/features/source-config-list/dependencies.js +53 -49
- package/dist/features/source-config-list/index.d.ts +3 -3
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
- package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
- package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
- package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
- package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
- package/dist/features/source-config-list/types.d.ts +14 -0
- package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
- package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
- package/dist/features/tab-strip/react/components/TabBar.js +8 -1
- package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
- package/dist/features/version-manager/dependencies.d.ts +3 -1
- package/dist/features/version-manager/dependencies.js +3 -2
- package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
- package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
- package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
- package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
- package/dist/features/viewer-shell/rules.js +19 -23
- package/dist/react/components/CustomSelect.d.ts +38 -1
- package/dist/react/components/CustomSelect.js +94 -38
- package/dist/react/components/OnboardingDropdown.js +20 -8
- package/dist/react/components/RemixIcon.stylesheet.js +3 -1
- package/dist/react/components/Toast.js +13 -2
- package/dist/react/components/TooltipLayer.js +5 -14
- package/dist/react/components/WorkingDirPicker.js +78 -50
- package/dist/react/components/remixicon-font-recovery.js +38 -30
- package/dist/react/components/select-popover.d.ts +8 -6
- package/dist/react/components/select-popover.js +33 -29
- package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
- package/dist/react/mcp-ui/McpUiHost.js +10 -11
- package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
- package/dist/react/mcp-ui/host-message-source.js +15 -5
- package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
- package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
- package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
- package/dist/renderers/preview-modal-shell/react/components/icons.js +4 -1
- package/dist/renderers/react/components/ArtifactView.js +9 -6
- package/dist/renderers/srcdoc/build.d.ts +4 -1
- package/dist/renderers/srcdoc/build.js +62 -48
- package/dist/styles/admin.css +29 -14
- package/dist/styles/lightbox.css +142 -0
- package/dist/styles/variables.css +128 -0
- package/dist/theme/apply.js +9 -5
- package/dist/utils/auto-open-file.d.ts +2 -1
- package/dist/utils/auto-open-file.js +69 -85
- package/dist/utils/markdown-scroll-sync.js +108 -87
- package/dist/utils/polygon-selection.js +25 -26
- package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
- package/dist/utils/smooth-scroll-to-top.js +2 -32
- package/dist/utils/sse.js +26 -26
- package/dist/utils/unit-bezier.d.ts +7 -0
- package/dist/utils/unit-bezier.js +38 -0
- package/package.json +7 -10
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
|
@@ -20,44 +20,9 @@ export function useKeyboardCommands(popoverOpen, onSubmit, onPopoverKey) {
|
|
|
20
20
|
const onPopoverKeyRef = useRef(onPopoverKey);
|
|
21
21
|
onPopoverKeyRef.current = onPopoverKey;
|
|
22
22
|
useEffect(() => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return false;
|
|
27
|
-
if (e?.shiftKey) {
|
|
28
|
-
editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND, false);
|
|
29
|
-
e.preventDefault();
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
// Cmd/Ctrl+Enter force-submits even with a popover open.
|
|
33
|
-
if (e?.metaKey || e?.ctrlKey) {
|
|
34
|
-
e.preventDefault();
|
|
35
|
-
onSubmitRef.current();
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
if (popoverOpenRef.current) {
|
|
39
|
-
e?.preventDefault();
|
|
40
|
-
return onPopoverKeyRef.current('Enter');
|
|
41
|
-
}
|
|
42
|
-
e?.preventDefault();
|
|
43
|
-
onSubmitRef.current();
|
|
44
|
-
return true;
|
|
45
|
-
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_ARROW_DOWN_COMMAND, (e) => {
|
|
46
|
-
if (!popoverOpenRef.current || editor.isComposing())
|
|
47
|
-
return false;
|
|
48
|
-
e?.preventDefault();
|
|
49
|
-
return onPopoverKeyRef.current('ArrowDown');
|
|
50
|
-
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_ARROW_UP_COMMAND, (e) => {
|
|
51
|
-
if (!popoverOpenRef.current || editor.isComposing())
|
|
52
|
-
return false;
|
|
53
|
-
e?.preventDefault();
|
|
54
|
-
return onPopoverKeyRef.current('ArrowUp');
|
|
55
|
-
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_TAB_COMMAND, (e) => {
|
|
56
|
-
if (!popoverOpenRef.current || editor.isComposing())
|
|
57
|
-
return false;
|
|
58
|
-
e?.preventDefault();
|
|
59
|
-
return onPopoverKeyRef.current('Tab');
|
|
60
|
-
}, COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_ESCAPE_COMMAND, () => {
|
|
23
|
+
const routing = { editor, popoverOpenRef, onSubmitRef, onPopoverKeyRef };
|
|
24
|
+
const navKey = (key) => (event) => routeNavKeyToPopover({ ...routing, event, key });
|
|
25
|
+
return mergeRegister(editor.registerCommand(KEY_ENTER_COMMAND, (event) => handleEnter({ ...routing, event }), COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_ARROW_DOWN_COMMAND, navKey('ArrowDown'), COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_ARROW_UP_COMMAND, navKey('ArrowUp'), COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_TAB_COMMAND, navKey('Tab'), COMMAND_PRIORITY_HIGH), editor.registerCommand(KEY_ESCAPE_COMMAND, () => {
|
|
61
26
|
if (!popoverOpenRef.current)
|
|
62
27
|
return false;
|
|
63
28
|
return onPopoverKeyRef.current('Escape');
|
|
@@ -67,4 +32,34 @@ export function useKeyboardCommands(popoverOpen, onSubmit, onPopoverKey) {
|
|
|
67
32
|
}, COMMAND_PRIORITY_HIGH));
|
|
68
33
|
}, [editor]);
|
|
69
34
|
}
|
|
35
|
+
function handleEnter(at) {
|
|
36
|
+
const { editor, event: e } = at;
|
|
37
|
+
// IME confirm Enter — let Lexical commit the composition.
|
|
38
|
+
if (editor.isComposing())
|
|
39
|
+
return false;
|
|
40
|
+
if (e?.shiftKey) {
|
|
41
|
+
editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND, false);
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
// Cmd/Ctrl+Enter force-submits even with a popover open.
|
|
46
|
+
if (e?.metaKey || e?.ctrlKey) {
|
|
47
|
+
e.preventDefault();
|
|
48
|
+
at.onSubmitRef.current();
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
e?.preventDefault();
|
|
52
|
+
if (at.popoverOpenRef.current)
|
|
53
|
+
return at.onPopoverKeyRef.current('Enter');
|
|
54
|
+
at.onSubmitRef.current();
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
/** Arrow-down/up/Tab go to the popover only while it's open and no IME
|
|
58
|
+
* composition is in progress; otherwise Lexical handles them. */
|
|
59
|
+
function routeNavKeyToPopover(at) {
|
|
60
|
+
if (!at.popoverOpenRef.current || at.editor.isComposing())
|
|
61
|
+
return false;
|
|
62
|
+
at.event?.preventDefault();
|
|
63
|
+
return at.onPopoverKeyRef.current(at.key);
|
|
64
|
+
}
|
|
70
65
|
//# sourceMappingURL=useKeyboardCommands.js.map
|
|
@@ -205,6 +205,10 @@ function isUsableRect(r) {
|
|
|
205
205
|
function toCaretRect(r) {
|
|
206
206
|
return { top: r.top, bottom: r.bottom, left: r.left, right: r.right };
|
|
207
207
|
}
|
|
208
|
+
/** A caret rect pinned to a box's left edge (zero width). */
|
|
209
|
+
function leftEdgeRect(r) {
|
|
210
|
+
return { top: r.top, bottom: r.bottom, left: r.left, right: r.left };
|
|
211
|
+
}
|
|
208
212
|
/** Reads the caret's viewport rect via the native selection, with ordered
|
|
209
213
|
* fallbacks for the collapsed-caret 0×0 case: (1) range bounding rect,
|
|
210
214
|
* (2) range client-rects list, (3) a zero-width probe range cloned at the
|
|
@@ -213,99 +217,108 @@ export function readCaretRect(rootEl) {
|
|
|
213
217
|
if (typeof window === 'undefined')
|
|
214
218
|
return null;
|
|
215
219
|
const winSel = window.getSelection();
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
244
|
-
if (typeof probe.getClientRects === 'function') {
|
|
245
|
-
const prList = probe.getClientRects();
|
|
246
|
-
if (prList.length > 0 && isUsableRect(prList[0]))
|
|
247
|
-
return toCaretRect(prList[0]);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
catch {
|
|
251
|
-
/* fall through */
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
const el = anchorNode.nodeType === Node.ELEMENT_NODE
|
|
255
|
-
? anchorNode
|
|
256
|
-
: anchorNode.parentElement;
|
|
257
|
-
if (el) {
|
|
258
|
-
const er = el.getBoundingClientRect();
|
|
259
|
-
if (isUsableRect(er)) {
|
|
260
|
-
return { top: er.top, bottom: er.bottom, left: er.left, right: er.left };
|
|
261
|
-
}
|
|
262
|
-
}
|
|
220
|
+
const fromSelection = winSel && winSel.rangeCount > 0 ? caretRectFromRange(winSel.getRangeAt(0)) : null;
|
|
221
|
+
if (fromSelection)
|
|
222
|
+
return fromSelection;
|
|
223
|
+
return rootEl ? leftEdgeRect(rootEl.getBoundingClientRect()) : null;
|
|
224
|
+
}
|
|
225
|
+
/** Fallbacks (1)–(4) of `readCaretRect` for one live selection range. */
|
|
226
|
+
function caretRectFromRange(range) {
|
|
227
|
+
const fromRange = rangeGeometryRect(range);
|
|
228
|
+
if (fromRange)
|
|
229
|
+
return fromRange;
|
|
230
|
+
const anchorNode = range.startContainer;
|
|
231
|
+
if (anchorNode.nodeType === Node.TEXT_NODE) {
|
|
232
|
+
const probed = probeTextCaretRect({ text: anchorNode, offset: range.startOffset });
|
|
233
|
+
if (probed)
|
|
234
|
+
return probed;
|
|
235
|
+
}
|
|
236
|
+
return anchorElementRect(anchorNode);
|
|
237
|
+
}
|
|
238
|
+
/** Fallbacks (1) and (2): a range's bounding rect, then its first client rect. */
|
|
239
|
+
function rangeGeometryRect(range) {
|
|
240
|
+
// jsdom does not implement Range geometry — guard every native call so a
|
|
241
|
+
// missing method falls through to the element/root box instead of
|
|
242
|
+
// throwing.
|
|
243
|
+
if (typeof range.getBoundingClientRect === 'function') {
|
|
244
|
+
const r = range.getBoundingClientRect();
|
|
245
|
+
if (isUsableRect(r))
|
|
246
|
+
return toCaretRect(r);
|
|
263
247
|
}
|
|
264
|
-
if (
|
|
265
|
-
const
|
|
266
|
-
|
|
248
|
+
if (typeof range.getClientRects === 'function') {
|
|
249
|
+
const rects = range.getClientRects();
|
|
250
|
+
if (rects.length > 0 && isUsableRect(rects[0]))
|
|
251
|
+
return toCaretRect(rects[0]);
|
|
267
252
|
}
|
|
268
253
|
return null;
|
|
269
254
|
}
|
|
255
|
+
/** Fallback (3): geometry of a zero-width probe range at the anchor text offset. */
|
|
256
|
+
function probeTextCaretRect(at) {
|
|
257
|
+
try {
|
|
258
|
+
const probe = document.createRange();
|
|
259
|
+
const off = Math.min(at.offset, at.text.length);
|
|
260
|
+
probe.setStart(at.text, off);
|
|
261
|
+
probe.setEnd(at.text, off);
|
|
262
|
+
return rangeGeometryRect(probe);
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
/* fall through */
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/** Fallback (4): the anchor element's box (or the text anchor's parent's). */
|
|
270
|
+
function anchorElementRect(anchorNode) {
|
|
271
|
+
const el = anchorNode.nodeType === Node.ELEMENT_NODE ? anchorNode : anchorNode.parentElement;
|
|
272
|
+
if (!el)
|
|
273
|
+
return null;
|
|
274
|
+
const er = el.getBoundingClientRect();
|
|
275
|
+
return isUsableRect(er) ? leftEdgeRect(er) : null;
|
|
276
|
+
}
|
|
270
277
|
/** Default ABOVE the caret (a composer typically sits at a panel's bottom,
|
|
271
278
|
* so above never occludes the input line); flip BELOW only when above lacks
|
|
272
279
|
* room. Clamp horizontally into the viewport (or `boundary`, when given).
|
|
273
280
|
* Caps height; the caller's popover scrolls internally. */
|
|
274
281
|
export function computeCaretFloatingLayerPosition(caret, size, boundary, config) {
|
|
275
|
-
const {
|
|
282
|
+
const { margin } = config;
|
|
276
283
|
const vw = window.innerWidth;
|
|
277
|
-
const
|
|
278
|
-
const
|
|
279
|
-
|
|
284
|
+
const width = layerWidth({ vw, boundary, margin, preferredWidth: config.preferredWidth });
|
|
285
|
+
const vertical = verticalPlacement({
|
|
286
|
+
caret,
|
|
287
|
+
vh: window.innerHeight,
|
|
288
|
+
wantedH: size?.height ?? config.hardMaxHeight,
|
|
289
|
+
...config,
|
|
290
|
+
});
|
|
291
|
+
const left = clampLeft({ caretLeft: caret.left, vw, boundary, margin, width });
|
|
292
|
+
return { left, top: vertical.top, width, maxHeight: vertical.maxHeight, placement: vertical.placement };
|
|
293
|
+
}
|
|
294
|
+
function layerWidth(at) {
|
|
295
|
+
const viewportAvailableWidth = at.vw - at.margin * 2;
|
|
296
|
+
const boundaryAvailableWidth = at.boundary
|
|
297
|
+
? at.boundary.width - at.margin * 2
|
|
298
|
+
: viewportAvailableWidth;
|
|
280
299
|
const availableWidth = Math.max(240, Math.min(viewportAvailableWidth, boundaryAvailableWidth));
|
|
281
|
-
|
|
300
|
+
return Math.min(at.preferredWidth, availableWidth);
|
|
301
|
+
}
|
|
302
|
+
function verticalPlacement(at) {
|
|
303
|
+
const { caret, gap, margin, wantedH } = at;
|
|
282
304
|
const spaceAbove = caret.top - gap - margin;
|
|
283
|
-
const spaceBelow = vh - caret.bottom - gap - margin;
|
|
284
|
-
const wantedH = size?.height ?? hardMaxHeight;
|
|
305
|
+
const spaceBelow = at.vh - caret.bottom - gap - margin;
|
|
285
306
|
const aboveFits = spaceAbove >= Math.min(wantedH, 160);
|
|
286
307
|
const placement = aboveFits || spaceAbove >= spaceBelow ? 'above' : 'below';
|
|
287
308
|
const space = placement === 'above' ? spaceAbove : spaceBelow;
|
|
288
|
-
const maxHeight = Math.max(120, Math.min(hardMaxHeight, space));
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
else {
|
|
297
|
-
top = caret.bottom + gap;
|
|
298
|
-
}
|
|
309
|
+
const maxHeight = Math.max(120, Math.min(at.hardMaxHeight, space));
|
|
310
|
+
if (placement === 'below')
|
|
311
|
+
return { top: caret.bottom + gap, maxHeight, placement };
|
|
312
|
+
const h = Math.min(wantedH, maxHeight);
|
|
313
|
+
return { top: Math.max(margin, caret.top - gap - h), maxHeight, placement };
|
|
314
|
+
}
|
|
315
|
+
function clampLeft(at) {
|
|
316
|
+
const { vw, boundary, margin, width } = at;
|
|
299
317
|
const minLeft = boundary ? Math.max(margin, boundary.left + margin) : margin;
|
|
300
318
|
const maxLeft = boundary
|
|
301
319
|
? Math.max(minLeft, Math.min(vw - margin - width, boundary.right - margin - width))
|
|
302
320
|
: vw - margin - width;
|
|
303
|
-
|
|
304
|
-
if (left > maxLeft)
|
|
305
|
-
left = maxLeft;
|
|
306
|
-
if (left < minLeft)
|
|
307
|
-
left = minLeft;
|
|
308
|
-
return { left, top, width, maxHeight, placement };
|
|
321
|
+
return Math.max(minLeft, Math.min(at.caretLeft, maxLeft));
|
|
309
322
|
}
|
|
310
323
|
/** Combines detection + caret-rect reading into the shape `RichTextInput`
|
|
311
324
|
* reports upward on every editor update. */
|
|
@@ -9,32 +9,34 @@ import { $isMentionNode } from './mention-node.js';
|
|
|
9
9
|
export function serializeRichText(state) {
|
|
10
10
|
return state.read(() => {
|
|
11
11
|
const mentions = [];
|
|
12
|
-
const blocks =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
let line = '';
|
|
20
|
-
for (const child of block.getChildren()) {
|
|
21
|
-
if ($isMentionNode(child)) {
|
|
22
|
-
line += child.getToken();
|
|
23
|
-
mentions.push(child.getEntity());
|
|
24
|
-
}
|
|
25
|
-
else if ($isLineBreakNode(child)) {
|
|
26
|
-
line += '\n';
|
|
27
|
-
}
|
|
28
|
-
else if ($isTextNode(child)) {
|
|
29
|
-
line += child.getTextContent();
|
|
30
|
-
}
|
|
31
|
-
else if ($isElementNode(child)) {
|
|
32
|
-
line += child.getTextContent();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
blocks.push(line);
|
|
36
|
-
}
|
|
12
|
+
const blocks = $getRoot()
|
|
13
|
+
.getChildren()
|
|
14
|
+
.map((block) => $isParagraphNode(block)
|
|
15
|
+
? serializeParagraph({ paragraph: block, mentions })
|
|
16
|
+
: // Stray non-paragraph block (shouldn't happen): fall back to its text.
|
|
17
|
+
block.getTextContent());
|
|
37
18
|
return { text: blocks.join('\n'), mentions };
|
|
38
19
|
});
|
|
39
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* One paragraph's wire text; appends each atomic mention's entity to
|
|
23
|
+
* `mentions` in document order. A non-mention decorator child contributes
|
|
24
|
+
* nothing.
|
|
25
|
+
*/
|
|
26
|
+
function serializeParagraph(at) {
|
|
27
|
+
let line = '';
|
|
28
|
+
for (const child of at.paragraph.getChildren()) {
|
|
29
|
+
if ($isMentionNode(child)) {
|
|
30
|
+
line += child.getToken();
|
|
31
|
+
at.mentions.push(child.getEntity());
|
|
32
|
+
}
|
|
33
|
+
else if ($isLineBreakNode(child)) {
|
|
34
|
+
line += '\n';
|
|
35
|
+
}
|
|
36
|
+
else if ($isTextNode(child) || $isElementNode(child)) {
|
|
37
|
+
line += child.getTextContent();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return line;
|
|
41
|
+
}
|
|
40
42
|
//# sourceMappingURL=serialize.js.map
|
|
@@ -27,51 +27,131 @@ function checkedFields(form) {
|
|
|
27
27
|
return form.fields.map(field => ({ ...field }));
|
|
28
28
|
}
|
|
29
29
|
/** Classify before persistence; an abort wins over an already-buffered answer.
|
|
30
|
-
*
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (ctx.signal.aborted)
|
|
36
|
-
return { status: 'abandoned' };
|
|
30
|
+
* @complexity O(1). */
|
|
31
|
+
function answerStep(required) {
|
|
32
|
+
const { answer, signal } = required;
|
|
33
|
+
if (signal.aborted)
|
|
34
|
+
return { run: { status: 'abandoned' } };
|
|
37
35
|
if (answer.status !== 'received')
|
|
38
|
-
return { status: answer.status };
|
|
36
|
+
return { run: { status: answer.status } };
|
|
39
37
|
if (answer.params[SURFACE_DISMISSED_PARAM] === true)
|
|
40
|
-
return { status: 'cancelled' };
|
|
41
|
-
|
|
38
|
+
return { run: { status: 'cancelled' } };
|
|
39
|
+
return { params: answer.params };
|
|
40
|
+
}
|
|
41
|
+
/** The exact submitted secret, or undefined when it is blank or malformed.
|
|
42
|
+
* Trimming tests blankness only: rewriting a provider secret can corrupt intentional newlines.
|
|
43
|
+
* @complexity O(b) in the submitted secret bytes. */
|
|
44
|
+
function secretValue(required) {
|
|
45
|
+
const { field, value } = required;
|
|
46
|
+
if (value !== undefined && typeof value !== 'string')
|
|
47
|
+
return undefined;
|
|
48
|
+
const secret = typeof value === 'string' ? value : '';
|
|
49
|
+
if (secret.trim() === '' && (secret !== '' || field.allowBlank !== true))
|
|
50
|
+
return undefined;
|
|
51
|
+
return secret;
|
|
52
|
+
}
|
|
53
|
+
/** Project only declared names; undefined means a required secret was blank or malformed.
|
|
54
|
+
* @complexity O(n + b) in fields and submitted secret bytes. */
|
|
55
|
+
function collectValues(required) {
|
|
56
|
+
const { fields, params } = required;
|
|
57
|
+
const values = Object.fromEntries(fields.map(field => [field.name, params[field.name]]));
|
|
42
58
|
const secrets = [];
|
|
43
59
|
for (const field of fields) {
|
|
44
60
|
if (field.secret !== true)
|
|
45
61
|
continue;
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
48
|
-
return
|
|
49
|
-
const secret = typeof value === 'string' ? value : '';
|
|
50
|
-
if (secret.trim() === '' && (secret !== '' || field.allowBlank !== true))
|
|
51
|
-
return { status: 'blank' };
|
|
62
|
+
const secret = secretValue({ field, value: values[field.name] });
|
|
63
|
+
if (secret === undefined)
|
|
64
|
+
return undefined;
|
|
52
65
|
values[field.name] = secret;
|
|
53
66
|
secrets.push(secret);
|
|
54
67
|
}
|
|
68
|
+
return { values, secrets };
|
|
69
|
+
}
|
|
70
|
+
/** Map a save exception to fixed, redacted text and log fixed metadata only.
|
|
71
|
+
* @complexity O(m + b): delegates to core's exact-secret redaction scan. */
|
|
72
|
+
function failedRun(required) {
|
|
73
|
+
const { error, secrets, signal, toolId, options, exchangeId } = required;
|
|
74
|
+
if (signal.aborted)
|
|
75
|
+
return { status: 'abandoned' };
|
|
76
|
+
let safeMessage = options.text?.saveFailure ?? 'Saving failed. Nothing was saved.';
|
|
77
|
+
try {
|
|
78
|
+
safeMessage = options.safeError?.(error) ?? safeMessage;
|
|
79
|
+
}
|
|
80
|
+
catch { /* An error mapper must not disclose a second exception containing the submitted value. */ }
|
|
81
|
+
// Even an accidentally permissive allowlist must not echo the submitted secret.
|
|
82
|
+
safeMessage = redactSecrets({ input: safeMessage }, { exactSecrets: secrets });
|
|
83
|
+
try {
|
|
84
|
+
options.logFailure?.({ toolId, exchangeId, saved: false });
|
|
85
|
+
}
|
|
86
|
+
catch { /* Logging must not replace the safe model result with an opaque logger exception. */ }
|
|
87
|
+
return { status: 'failed', safeMessage };
|
|
88
|
+
}
|
|
89
|
+
/** Classify, then persist; an abort wins over an already-buffered answer.
|
|
90
|
+
* @complexity O(n + b) before save in fields and submitted secret bytes; failure text delegates
|
|
91
|
+
* to core's exact-secret redaction scan. Host persistence cost is external. */
|
|
92
|
+
async function saveAnswer(required) {
|
|
93
|
+
const { answer, fields, prep, ctx, spec, options, exchangeId } = required;
|
|
94
|
+
const step = answerStep({ answer, signal: ctx.signal });
|
|
95
|
+
if ('run' in step)
|
|
96
|
+
return step.run;
|
|
97
|
+
const collected = collectValues({ fields, params: step.params });
|
|
98
|
+
if (collected === undefined)
|
|
99
|
+
return { status: 'blank' };
|
|
55
100
|
if (ctx.signal.aborted)
|
|
56
101
|
return { status: 'abandoned' };
|
|
102
|
+
const { values, secrets } = collected;
|
|
57
103
|
try {
|
|
58
104
|
return { status: 'saved', saved: await spec.save({ values, prep, signal: ctx.signal }) };
|
|
59
105
|
}
|
|
60
106
|
catch (error) {
|
|
107
|
+
return failedRun({ error, secrets, signal: ctx.signal, toolId: spec.toolId, options, exchangeId });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Fail closed without an emitter. @complexity O(1). @throws ToolInputError with fixed text. */
|
|
111
|
+
function requireEmitter(required, optional) {
|
|
112
|
+
if (optional.emitSurface)
|
|
113
|
+
return optional.emitSurface;
|
|
114
|
+
throw new ToolInputError({ message: required.options.text?.noEmitter ?? `${required.toolId}: this execution context has no interactive form channel (no emitSurface), so this form cannot be shown here. Nothing was changed.` });
|
|
115
|
+
}
|
|
116
|
+
/** The form resource: engine-owned routing params and dismissal around the host's copy.
|
|
117
|
+
* @complexity O(n + h) in fields and rendered HTML. */
|
|
118
|
+
function buildCardForm(required) {
|
|
119
|
+
const { form, fields, uri, framing, toolId, exchangeId, options } = required;
|
|
120
|
+
return buildFormSurface({ ...form, fields, uri, ...framing, toolName: toolId,
|
|
121
|
+
baseParams: { [SURFACE_EXCHANGE_ID_PARAM]: exchangeId },
|
|
122
|
+
cancel: { label: form.cancelLabel ?? options.text?.cancelLabel ?? 'Cancel', toolName: toolId,
|
|
123
|
+
params: { [SURFACE_EXCHANGE_ID_PARAM]: exchangeId, [SURFACE_DISMISSED_PARAM]: true } },
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/** Open the exchange, emit the card and hold the call until the real save is reported.
|
|
127
|
+
* @complexity O(n + h + b) locally, plus host I/O. */
|
|
128
|
+
async function runCard(required) {
|
|
129
|
+
const { spec, options, deps, ctx, emit, prep, form, fields } = required;
|
|
130
|
+
const exchange = deps.surfaceExchanges.open({ binding: { toolId: spec.toolId, principalId: ctx.principal.id, channel: 'mcp-ui' }, emit });
|
|
131
|
+
const closeOnAbort = () => exchange.close({});
|
|
132
|
+
ctx.signal.addEventListener('abort', closeOnAbort, { once: true });
|
|
133
|
+
try {
|
|
134
|
+
// Close the open/register race as well as the prepare/abort race.
|
|
61
135
|
if (ctx.signal.aborted)
|
|
62
|
-
return { status: 'abandoned' };
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
136
|
+
return spec.result({ prep, run: { status: 'abandoned' } });
|
|
137
|
+
const uri = `ui://${options.uriHost ?? 'jini'}/secret-card/${encodeURIComponent(spec.toolId)}/${encodeURIComponent(exchange.id)}`;
|
|
138
|
+
const framing = options.frameSize === undefined ? {} : { preferredFrameSize: options.frameSize };
|
|
139
|
+
const resource = buildCardForm({ form, fields, uri, framing, toolId: spec.toolId, exchangeId: exchange.id, options });
|
|
140
|
+
return await deps.askThenReport({ exchange, confirmationEmission: { channel: 'mcp-ui', payload: { resource } },
|
|
141
|
+
handle: async (answer) => {
|
|
142
|
+
const run = await saveAnswer({ answer, fields, prep, ctx, spec, options, exchangeId: exchange.id });
|
|
143
|
+
const result = spec.result({ prep, run });
|
|
144
|
+
const outcome = spec.outcome({ prep, run });
|
|
145
|
+
if (outcome === undefined)
|
|
146
|
+
return { result };
|
|
147
|
+
return { result, outcome: { channel: 'mcp-ui', payload: { resource: buildOutcomeSurface({ ...outcome, uri, ...framing }) } } };
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
ctx.signal.removeEventListener('abort', closeOnAbort);
|
|
153
|
+
// Also covers rendering/projection failures before or inside askThenReport; close is idempotent.
|
|
154
|
+
exchange.close({});
|
|
75
155
|
}
|
|
76
156
|
}
|
|
77
157
|
/**
|
|
@@ -92,8 +172,7 @@ export function defineSecretCardTool(required, options = {}) {
|
|
|
92
172
|
toolId: spec.toolId,
|
|
93
173
|
secretFieldNames: prep => checkedFields(spec.form({ prep })).filter(field => field.secret === true).map(field => field.name),
|
|
94
174
|
handler: deps => async (ctx, optional = {}) => {
|
|
95
|
-
|
|
96
|
-
throw new ToolInputError({ message: options.text?.noEmitter ?? `${spec.toolId}: this execution context has no interactive form channel (no emitSurface), so this form cannot be shown here. Nothing was changed.` });
|
|
175
|
+
const emit = requireEmitter({ toolId: spec.toolId, options }, optional);
|
|
97
176
|
const prep = await spec.prepare({ ctx });
|
|
98
177
|
if (ctx.signal.aborted)
|
|
99
178
|
return spec.result({ prep, run: { status: 'abandoned' } });
|
|
@@ -101,36 +180,7 @@ export function defineSecretCardTool(required, options = {}) {
|
|
|
101
180
|
const fields = checkedFields(form);
|
|
102
181
|
if (ctx.signal.aborted)
|
|
103
182
|
return spec.result({ prep, run: { status: 'abandoned' } });
|
|
104
|
-
|
|
105
|
-
const closeOnAbort = () => exchange.close({});
|
|
106
|
-
ctx.signal.addEventListener('abort', closeOnAbort, { once: true });
|
|
107
|
-
try {
|
|
108
|
-
// Close the open/register race as well as the prepare/abort race.
|
|
109
|
-
if (ctx.signal.aborted)
|
|
110
|
-
return spec.result({ prep, run: { status: 'abandoned' } });
|
|
111
|
-
const uri = `ui://${options.uriHost ?? 'jini'}/secret-card/${encodeURIComponent(spec.toolId)}/${encodeURIComponent(exchange.id)}`;
|
|
112
|
-
const framing = options.frameSize === undefined ? {} : { preferredFrameSize: options.frameSize };
|
|
113
|
-
const resource = buildFormSurface({ ...form, fields, uri, ...framing, toolName: spec.toolId,
|
|
114
|
-
baseParams: { [SURFACE_EXCHANGE_ID_PARAM]: exchange.id },
|
|
115
|
-
cancel: { label: form.cancelLabel ?? options.text?.cancelLabel ?? 'Cancel', toolName: spec.toolId,
|
|
116
|
-
params: { [SURFACE_EXCHANGE_ID_PARAM]: exchange.id, [SURFACE_DISMISSED_PARAM]: true } },
|
|
117
|
-
});
|
|
118
|
-
return await deps.askThenReport({ exchange, confirmationEmission: { channel: 'mcp-ui', payload: { resource } },
|
|
119
|
-
handle: async (answer) => {
|
|
120
|
-
const run = await saveAnswer({ answer, fields, prep, ctx, spec, options, exchangeId: exchange.id });
|
|
121
|
-
const result = spec.result({ prep, run });
|
|
122
|
-
const outcome = spec.outcome({ prep, run });
|
|
123
|
-
if (outcome === undefined)
|
|
124
|
-
return { result };
|
|
125
|
-
return { result, outcome: { channel: 'mcp-ui', payload: { resource: buildOutcomeSurface({ ...outcome, uri, ...framing }) } } };
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
finally {
|
|
130
|
-
ctx.signal.removeEventListener('abort', closeOnAbort);
|
|
131
|
-
// Also covers rendering/projection failures before or inside askThenReport; close is idempotent.
|
|
132
|
-
exchange.close({});
|
|
133
|
-
}
|
|
183
|
+
return runCard({ spec, options, deps, ctx, emit, prep, form, fields });
|
|
134
184
|
},
|
|
135
185
|
};
|
|
136
186
|
}
|