@flowdrop/flowdrop 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -51
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +27 -47
- package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +2 -2
- package/dist/adapters/agentspec/AgentSpecAdapter.js +122 -133
- package/dist/adapters/agentspec/agentAdapter.d.ts +2 -2
- package/dist/adapters/agentspec/agentAdapter.js +10 -10
- package/dist/adapters/agentspec/autoLayout.d.ts +52 -6
- package/dist/adapters/agentspec/autoLayout.js +118 -23
- package/dist/adapters/agentspec/componentTypeDefaults.d.ts +1 -1
- package/dist/adapters/agentspec/componentTypeDefaults.js +120 -120
- package/dist/adapters/agentspec/defaultNodeTypes.d.ts +2 -2
- package/dist/adapters/agentspec/defaultNodeTypes.js +307 -307
- package/dist/adapters/agentspec/index.d.ts +10 -10
- package/dist/adapters/agentspec/index.js +6 -6
- package/dist/adapters/agentspec/validator.d.ts +2 -2
- package/dist/adapters/agentspec/validator.js +20 -22
- package/dist/api/enhanced-client.d.ts +3 -3
- package/dist/api/enhanced-client.js +72 -73
- package/dist/chat/commandClassifier.d.ts +19 -0
- package/dist/chat/commandClassifier.js +30 -0
- package/dist/chat/index.d.ts +27 -0
- package/dist/chat/index.js +32 -0
- package/dist/chat/responseParser.d.ts +21 -0
- package/dist/chat/responseParser.js +91 -0
- package/dist/commands/batch.d.ts +18 -0
- package/dist/commands/batch.js +54 -0
- package/dist/commands/executor.d.ts +37 -0
- package/dist/commands/executor.js +1133 -0
- package/dist/commands/index.d.ts +14 -0
- package/dist/commands/index.js +17 -0
- package/dist/commands/parser.d.ts +16 -0
- package/dist/commands/parser.js +295 -0
- package/dist/commands/positioner.d.ts +19 -0
- package/dist/commands/positioner.js +33 -0
- package/dist/commands/storeIntegration.svelte.d.ts +16 -0
- package/dist/commands/storeIntegration.svelte.js +67 -0
- package/dist/commands/types.d.ts +343 -0
- package/dist/commands/types.js +45 -0
- package/dist/components/App.svelte +522 -237
- package/dist/components/App.svelte.d.ts +11 -8
- package/dist/components/CanvasBanner.stories.svelte +10 -16
- package/dist/components/CanvasBanner.stories.svelte.d.ts +1 -1
- package/dist/components/CanvasBanner.svelte +2 -2
- package/dist/components/CanvasBanner.svelte.d.ts +1 -1
- package/dist/components/CanvasController.svelte +37 -0
- package/dist/components/CanvasController.svelte.d.ts +32 -0
- package/dist/components/ConfigForm.svelte +118 -256
- package/dist/components/ConfigForm.svelte.d.ts +2 -2
- package/dist/components/ConfigMappingRow.svelte +128 -0
- package/dist/components/ConfigMappingRow.svelte.d.ts +8 -0
- package/dist/components/ConfigModal.svelte +3 -3
- package/dist/components/ConfigModal.svelte.d.ts +1 -1
- package/dist/components/ConfigPanel.stories.svelte +19 -19
- package/dist/components/ConfigPanel.stories.svelte.d.ts +1 -1
- package/dist/components/ConfigPanel.svelte +57 -19
- package/dist/components/ConfigPanel.svelte.d.ts +3 -1
- package/dist/components/ConnectionLine.svelte +4 -4
- package/dist/components/EdgeRefresher.svelte +1 -1
- package/dist/components/FlowDropEdge.stories.svelte +110 -110
- package/dist/components/FlowDropEdge.svelte +11 -19
- package/dist/components/FlowDropEdge.svelte.d.ts +1 -1
- package/dist/components/FlowDropZone.svelte +6 -9
- package/dist/components/FlowDropZone.svelte.d.ts +1 -1
- package/dist/components/LoadingSpinner.stories.svelte +13 -13
- package/dist/components/LoadingSpinner.stories.svelte.d.ts +1 -1
- package/dist/components/LoadingSpinner.svelte +3 -3
- package/dist/components/LoadingSpinner.svelte.d.ts +1 -1
- package/dist/components/Logo.stories.svelte +4 -4
- package/dist/components/Logo.stories.svelte.d.ts +1 -1
- package/dist/components/Logo.svelte +3 -9
- package/dist/components/LogsSidebar.svelte +46 -53
- package/dist/components/LogsSidebar.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.stories.svelte +10 -14
- package/dist/components/MarkdownDisplay.stories.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.svelte +4 -6
- package/dist/components/Navbar.stories.svelte +19 -19
- package/dist/components/Navbar.stories.svelte.d.ts +1 -1
- package/dist/components/Navbar.svelte +28 -49
- package/dist/components/Navbar.svelte.d.ts +2 -2
- package/dist/components/NodeSidebar.svelte +55 -135
- package/dist/components/NodeSidebar.svelte.d.ts +1 -1
- package/dist/components/NodeStatusOverlay.stories.svelte +19 -31
- package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +1 -1
- package/dist/components/NodeStatusOverlay.svelte +40 -55
- package/dist/components/NodeStatusOverlay.svelte.d.ts +3 -3
- package/dist/components/NodeSwapPicker.svelte +493 -0
- package/dist/components/NodeSwapPicker.svelte.d.ts +16 -0
- package/dist/components/PipelineStatus.svelte +63 -89
- package/dist/components/PipelineStatus.svelte.d.ts +4 -4
- package/dist/components/PortCoordinateTracker.svelte +5 -7
- package/dist/components/PortCoordinateTracker.svelte.d.ts +1 -1
- package/dist/components/PortMappingRow.svelte +205 -0
- package/dist/components/PortMappingRow.svelte.d.ts +12 -0
- package/dist/components/ReadOnlyDetails.svelte +1 -1
- package/dist/components/SchemaForm.stories.svelte +53 -53
- package/dist/components/SchemaForm.stories.svelte.d.ts +1 -1
- package/dist/components/SchemaForm.svelte +24 -51
- package/dist/components/SchemaForm.svelte.d.ts +2 -2
- package/dist/components/SettingsModal.svelte +6 -9
- package/dist/components/SettingsModal.svelte.d.ts +1 -1
- package/dist/components/SettingsPanel.svelte +138 -158
- package/dist/components/SettingsPanel.svelte.d.ts +1 -1
- package/dist/components/StatusIcon.stories.svelte +16 -29
- package/dist/components/StatusIcon.stories.svelte.d.ts +1 -1
- package/dist/components/StatusIcon.svelte +19 -19
- package/dist/components/StatusIcon.svelte.d.ts +2 -2
- package/dist/components/StatusLabel.stories.svelte +8 -8
- package/dist/components/StatusLabel.stories.svelte.d.ts +1 -1
- package/dist/components/SwapMappingEditor.svelte +529 -0
- package/dist/components/SwapMappingEditor.svelte.d.ts +12 -0
- package/dist/components/ThemeToggle.stories.svelte +10 -10
- package/dist/components/ThemeToggle.stories.svelte.d.ts +1 -1
- package/dist/components/ThemeToggle.svelte +22 -33
- package/dist/components/ThemeToggle.svelte.d.ts +1 -1
- package/dist/components/UniversalNode.svelte +29 -41
- package/dist/components/UniversalNode.svelte.d.ts +3 -3
- package/dist/components/WorkflowEditor.svelte +210 -170
- package/dist/components/WorkflowEditor.svelte.d.ts +12 -4
- package/dist/components/chat/AIChatPanel.svelte +797 -0
- package/dist/components/chat/AIChatPanel.svelte.d.ts +13 -0
- package/dist/components/chat/CommandPreview.svelte +234 -0
- package/dist/components/chat/CommandPreview.svelte.d.ts +9 -0
- package/dist/components/console/CommandConsole.stories.svelte +111 -0
- package/dist/components/console/CommandConsole.stories.svelte.d.ts +27 -0
- package/dist/components/console/CommandConsole.svelte +263 -0
- package/dist/components/console/CommandConsole.svelte.d.ts +11 -0
- package/dist/components/console/ConsoleAutocomplete.svelte +142 -0
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +21 -0
- package/dist/components/console/ConsoleInput.svelte +771 -0
- package/dist/components/console/ConsoleInput.svelte.d.ts +16 -0
- package/dist/components/console/ConsoleOutput.svelte +116 -0
- package/dist/components/console/ConsoleOutput.svelte.d.ts +11 -0
- package/dist/components/console/formatters.d.ts +26 -0
- package/dist/components/console/formatters.js +116 -0
- package/dist/components/form/FormArray.svelte +75 -132
- package/dist/components/form/FormArray.svelte.d.ts +1 -1
- package/dist/components/form/FormAutocomplete.svelte +65 -108
- package/dist/components/form/FormAutocomplete.svelte.d.ts +1 -1
- package/dist/components/form/FormCheckboxGroup.stories.svelte +13 -16
- package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormCheckboxGroup.svelte +2 -2
- package/dist/components/form/FormCodeEditor.svelte +42 -56
- package/dist/components/form/FormField.svelte +79 -90
- package/dist/components/form/FormField.svelte.d.ts +2 -2
- package/dist/components/form/FormFieldLight.svelte +72 -88
- package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldWrapper.stories.svelte +14 -14
- package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldWrapper.svelte +2 -9
- package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldset.svelte +3 -3
- package/dist/components/form/FormFieldset.svelte.d.ts +2 -2
- package/dist/components/form/FormMarkdownEditor.svelte +123 -156
- package/dist/components/form/FormNumberField.stories.svelte +18 -18
- package/dist/components/form/FormNumberField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormNumberField.svelte +6 -6
- package/dist/components/form/FormRangeField.stories.svelte +13 -13
- package/dist/components/form/FormRangeField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormRangeField.svelte +4 -12
- package/dist/components/form/FormSelect.stories.svelte +21 -21
- package/dist/components/form/FormSelect.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormSelect.svelte +5 -5
- package/dist/components/form/FormSelect.svelte.d.ts +1 -1
- package/dist/components/form/FormTemplateEditor.svelte +126 -175
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +1 -1
- package/dist/components/form/FormTextField.stories.svelte +17 -23
- package/dist/components/form/FormTextField.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormTextField.svelte +4 -4
- package/dist/components/form/FormTextarea.stories.svelte +18 -21
- package/dist/components/form/FormTextarea.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormTextarea.svelte +4 -4
- package/dist/components/form/FormToggle.stories.svelte +13 -16
- package/dist/components/form/FormToggle.stories.svelte.d.ts +1 -1
- package/dist/components/form/FormToggle.svelte +3 -3
- package/dist/components/form/FormUISchemaRenderer.svelte +12 -19
- package/dist/components/form/FormUISchemaRenderer.svelte.d.ts +3 -3
- package/dist/components/form/index.d.ts +19 -19
- package/dist/components/form/index.js +18 -18
- package/dist/components/form/templateAutocomplete.d.ts +2 -2
- package/dist/components/form/templateAutocomplete.js +55 -64
- package/dist/components/form/types.d.ts +6 -6
- package/dist/components/form/types.js +4 -9
- package/dist/components/icons/AlertCircleIcon.svelte +1 -6
- package/dist/components/icons/CogIcon.svelte +1 -6
- package/dist/components/interrupt/ChoicePrompt.stories.svelte +27 -27
- package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ChoicePrompt.svelte +17 -41
- package/dist/components/interrupt/ChoicePrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +17 -17
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ConfirmationPrompt.svelte +10 -16
- package/dist/components/interrupt/ConfirmationPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/FormPrompt.svelte +10 -15
- package/dist/components/interrupt/FormPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/InterruptBubble.svelte +87 -121
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +2 -2
- package/dist/components/interrupt/ReviewPrompt.stories.svelte +37 -37
- package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/ReviewPrompt.svelte +55 -75
- package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/TextInputPrompt.stories.svelte +16 -17
- package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +1 -1
- package/dist/components/interrupt/TextInputPrompt.svelte +13 -18
- package/dist/components/interrupt/TextInputPrompt.svelte.d.ts +1 -1
- package/dist/components/interrupt/index.d.ts +6 -5
- package/dist/components/interrupt/index.js +6 -5
- package/dist/components/layouts/MainLayout.svelte +46 -84
- package/dist/components/layouts/MainLayout.svelte.d.ts +6 -6
- package/dist/components/nodes/GatewayNode.stories.svelte +64 -65
- package/dist/components/nodes/GatewayNode.svelte +37 -70
- package/dist/components/nodes/GatewayNode.svelte.d.ts +3 -3
- package/dist/components/nodes/IdeaNode.stories.svelte +25 -26
- package/dist/components/nodes/IdeaNode.svelte +22 -36
- package/dist/components/nodes/IdeaNode.svelte.d.ts +1 -1
- package/dist/components/nodes/NotesNode.stories.svelte +37 -38
- package/dist/components/nodes/NotesNode.svelte +28 -39
- package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SimpleNode.stories.svelte +137 -138
- package/dist/components/nodes/SimpleNode.svelte +44 -74
- package/dist/components/nodes/SimpleNode.svelte.d.ts +1 -1
- package/dist/components/nodes/SquareNode.stories.svelte +75 -75
- package/dist/components/nodes/SquareNode.svelte +42 -68
- package/dist/components/nodes/SquareNode.svelte.d.ts +1 -1
- package/dist/components/nodes/TerminalNode.stories.svelte +10 -10
- package/dist/components/nodes/TerminalNode.svelte +74 -112
- package/dist/components/nodes/TerminalNode.svelte.d.ts +1 -1
- package/dist/components/nodes/ToolNode.stories.svelte +115 -116
- package/dist/components/nodes/ToolNode.svelte +31 -64
- package/dist/components/nodes/ToolNode.svelte.d.ts +1 -1
- package/dist/components/nodes/WorkflowNode.stories.svelte +84 -89
- package/dist/components/nodes/WorkflowNode.svelte +50 -103
- package/dist/components/nodes/WorkflowNode.svelte.d.ts +3 -3
- package/dist/components/playground/ChatPanel.svelte +47 -103
- package/dist/components/playground/ExecutionLogs.svelte +45 -68
- package/dist/components/playground/InputCollector.svelte +32 -51
- package/dist/components/playground/MessageBubble.stories.svelte +25 -25
- package/dist/components/playground/MessageBubble.stories.svelte.d.ts +1 -1
- package/dist/components/playground/MessageBubble.svelte +54 -70
- package/dist/components/playground/MessageBubble.svelte.d.ts +1 -1
- package/dist/components/playground/Playground.svelte +60 -91
- package/dist/components/playground/Playground.svelte.d.ts +3 -3
- package/dist/components/playground/PlaygroundModal.svelte +8 -12
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -3
- package/dist/components/playground/SessionManager.svelte +34 -40
- package/dist/components/playground/SessionManager.svelte.d.ts +1 -1
- package/dist/config/agentSpecEndpoints.d.ts +1 -1
- package/dist/config/agentSpecEndpoints.js +20 -20
- package/dist/config/constants.js +2 -2
- package/dist/config/defaultCategories.d.ts +1 -1
- package/dist/config/defaultCategories.js +86 -86
- package/dist/config/defaultPortConfig.d.ts +1 -1
- package/dist/config/defaultPortConfig.js +144 -144
- package/dist/config/endpoints.d.ts +12 -4
- package/dist/config/endpoints.js +70 -65
- package/dist/config/runtimeConfig.d.ts +2 -2
- package/dist/config/runtimeConfig.js +8 -8
- package/dist/core/index.d.ts +68 -63
- package/dist/core/index.js +44 -35
- package/dist/display/index.d.ts +2 -2
- package/dist/display/index.js +2 -2
- package/dist/editor/index.d.ts +64 -62
- package/dist/editor/index.js +57 -55
- package/dist/form/code.d.ts +5 -5
- package/dist/form/code.js +14 -14
- package/dist/form/fieldRegistry.d.ts +3 -3
- package/dist/form/fieldRegistry.js +9 -11
- package/dist/form/full.d.ts +8 -8
- package/dist/form/full.js +9 -9
- package/dist/form/index.d.ts +18 -18
- package/dist/form/index.js +16 -16
- package/dist/form/markdown.d.ts +4 -4
- package/dist/form/markdown.js +8 -8
- package/dist/helpers/proximityConnect.d.ts +3 -3
- package/dist/helpers/proximityConnect.js +40 -35
- package/dist/helpers/workflowEditorHelper.d.ts +8 -58
- package/dist/helpers/workflowEditorHelper.js +73 -292
- package/dist/index.d.ts +6 -6
- package/dist/index.js +6 -6
- package/dist/mocks/app-environment.js +2 -2
- package/dist/mocks/app-forms.js +1 -1
- package/dist/mocks/app-navigation.js +2 -2
- package/dist/mocks/app-stores.js +3 -3
- package/dist/playground/index.d.ts +19 -19
- package/dist/playground/index.js +16 -16
- package/dist/playground/mount.d.ts +3 -3
- package/dist/playground/mount.js +24 -24
- package/dist/registry/builtinFormats.js +13 -13
- package/dist/registry/builtinNodes.d.ts +2 -2
- package/dist/registry/builtinNodes.js +77 -77
- package/dist/registry/index.d.ts +4 -4
- package/dist/registry/index.js +4 -4
- package/dist/registry/nodeComponentRegistry.d.ts +8 -8
- package/dist/registry/nodeComponentRegistry.js +9 -11
- package/dist/registry/plugin.d.ts +2 -2
- package/dist/registry/plugin.js +11 -11
- package/dist/registry/workflowFormatRegistry.d.ts +3 -3
- package/dist/registry/workflowFormatRegistry.js +2 -2
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.js +2 -2
- package/dist/schemas/v1/workflow.schema.json +107 -22
- package/dist/services/agentSpecExecutionService.d.ts +3 -3
- package/dist/services/agentSpecExecutionService.js +55 -56
- package/dist/services/api.d.ts +2 -2
- package/dist/services/api.js +37 -37
- package/dist/services/apiVariableService.d.ts +1 -1
- package/dist/services/apiVariableService.js +34 -41
- package/dist/services/autoSaveService.js +8 -8
- package/dist/services/categoriesApi.d.ts +2 -2
- package/dist/services/categoriesApi.js +8 -8
- package/dist/services/chatService.d.ts +65 -0
- package/dist/services/chatService.js +131 -0
- package/dist/services/draftStorage.d.ts +1 -1
- package/dist/services/draftStorage.js +11 -11
- package/dist/services/dynamicSchemaService.d.ts +1 -1
- package/dist/services/dynamicSchemaService.js +39 -41
- package/dist/services/globalSave.d.ts +2 -2
- package/dist/services/globalSave.js +38 -41
- package/dist/services/historyService.d.ts +7 -5
- package/dist/services/historyService.js +29 -14
- package/dist/services/interruptService.d.ts +1 -1
- package/dist/services/interruptService.js +29 -35
- package/dist/services/nodeExecutionService.d.ts +1 -1
- package/dist/services/nodeExecutionService.js +44 -45
- package/dist/services/playgroundService.d.ts +1 -1
- package/dist/services/playgroundService.js +29 -29
- package/dist/services/portConfigApi.d.ts +2 -2
- package/dist/services/portConfigApi.js +8 -8
- package/dist/services/settingsService.d.ts +2 -2
- package/dist/services/settingsService.js +19 -25
- package/dist/services/toastService.d.ts +4 -4
- package/dist/services/toastService.js +33 -33
- package/dist/services/variableService.d.ts +1 -1
- package/dist/services/variableService.js +36 -36
- package/dist/services/workflowStorage.d.ts +2 -2
- package/dist/services/workflowStorage.js +13 -13
- package/dist/settings/index.d.ts +7 -7
- package/dist/settings/index.js +6 -6
- package/dist/skins/default.d.ts +1 -1
- package/dist/skins/default.js +1 -1
- package/dist/skins/index.d.ts +3 -3
- package/dist/skins/index.js +7 -7
- package/dist/skins/slate.d.ts +1 -1
- package/dist/skins/slate.js +69 -69
- package/dist/stores/categoriesStore.svelte.d.ts +1 -1
- package/dist/stores/categoriesStore.svelte.js +5 -5
- package/dist/stores/editorStateMachine.svelte.d.ts +2 -2
- package/dist/stores/editorStateMachine.svelte.js +34 -34
- package/dist/stores/historyStore.svelte.d.ts +4 -4
- package/dist/stores/historyStore.svelte.js +4 -4
- package/dist/stores/interruptStore.svelte.d.ts +3 -3
- package/dist/stores/interruptStore.svelte.js +27 -22
- package/dist/stores/playgroundStore.svelte.d.ts +3 -3
- package/dist/stores/playgroundStore.svelte.js +29 -23
- package/dist/stores/portCoordinateStore.svelte.d.ts +6 -2
- package/dist/stores/portCoordinateStore.svelte.js +30 -39
- package/dist/stores/settingsStore.svelte.d.ts +2 -2
- package/dist/stores/settingsStore.svelte.js +57 -62
- package/dist/stores/workflowStore.svelte.d.ts +34 -5
- package/dist/stores/workflowStore.svelte.js +127 -108
- package/dist/stories/CanvasDecorator.svelte +7 -10
- package/dist/stories/CanvasDecorator.svelte.d.ts +2 -2
- package/dist/stories/EdgeDecorator.svelte +28 -31
- package/dist/stories/EdgeDecorator.svelte.d.ts +1 -1
- package/dist/stories/NodeDecorator.svelte +14 -20
- package/dist/stories/NodeDecorator.svelte.d.ts +1 -1
- package/dist/stories/utils.d.ts +2 -2
- package/dist/stories/utils.js +89 -93
- package/dist/styles/base.css +16 -50
- package/dist/styles/tokens.css +10 -28
- package/dist/svelte-app.d.ts +10 -10
- package/dist/svelte-app.js +39 -39
- package/dist/themes/default.d.ts +1 -1
- package/dist/themes/default.js +4 -4
- package/dist/themes/index.d.ts +3 -3
- package/dist/themes/index.js +11 -11
- package/dist/themes/minimal.d.ts +1 -1
- package/dist/themes/minimal.js +5 -5
- package/dist/types/agentspec.d.ts +18 -18
- package/dist/types/agentspec.js +2 -2
- package/dist/types/auth.d.ts +1 -1
- package/dist/types/auth.js +6 -6
- package/dist/types/chat.d.ts +63 -0
- package/dist/types/chat.js +9 -0
- package/dist/types/config.d.ts +6 -6
- package/dist/types/events.d.ts +28 -2
- package/dist/types/events.js +2 -1
- package/dist/types/index.d.ts +40 -32
- package/dist/types/index.js +6 -6
- package/dist/types/interrupt.d.ts +6 -6
- package/dist/types/interrupt.js +21 -21
- package/dist/types/interruptState.d.ts +12 -12
- package/dist/types/interruptState.js +66 -66
- package/dist/types/playground.d.ts +7 -7
- package/dist/types/playground.js +14 -14
- package/dist/types/settings.d.ts +12 -4
- package/dist/types/settings.js +21 -23
- package/dist/types/skin.d.ts +1 -1
- package/dist/types/theme.d.ts +2 -2
- package/dist/types/uischema.d.ts +4 -4
- package/dist/types/uischema.js +3 -3
- package/dist/utils/colors.d.ts +1 -1
- package/dist/utils/colors.js +95 -97
- package/dist/utils/config.d.ts +2 -2
- package/dist/utils/config.js +48 -48
- package/dist/utils/connections.d.ts +2 -2
- package/dist/utils/connections.js +15 -15
- package/dist/utils/edgeStyling.d.ts +42 -0
- package/dist/utils/edgeStyling.js +173 -0
- package/dist/utils/errors.js +3 -3
- package/dist/utils/fetchWithAuth.d.ts +1 -1
- package/dist/utils/fetchWithAuth.js +2 -2
- package/dist/utils/handleIds.d.ts +2 -2
- package/dist/utils/handleIds.js +8 -8
- package/dist/utils/handlePositioning.d.ts +1 -1
- package/dist/utils/handlePositioning.js +2 -2
- package/dist/utils/icons.d.ts +1 -1
- package/dist/utils/icons.js +74 -74
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +7 -7
- package/dist/utils/nodeIds.d.ts +31 -0
- package/dist/utils/nodeIds.js +42 -0
- package/dist/utils/nodeStatus.d.ts +1 -1
- package/dist/utils/nodeStatus.js +48 -48
- package/dist/utils/nodeSwap.d.ts +221 -0
- package/dist/utils/nodeSwap.js +680 -0
- package/dist/utils/nodeTypes.d.ts +1 -1
- package/dist/utils/nodeTypes.js +20 -21
- package/dist/utils/nodeWrapper.d.ts +7 -7
- package/dist/utils/nodeWrapper.js +19 -21
- package/dist/utils/performanceUtils.d.ts +1 -1
- package/dist/utils/performanceUtils.js +1 -2
- package/dist/utils/portUtils.d.ts +2 -2
- package/dist/utils/portUtils.js +1 -1
- package/dist/utils/sanitize.js +1 -1
- package/dist/utils/uischema.d.ts +2 -2
- package/dist/utils/uischema.js +8 -8
- package/dist/utils/validation.js +8 -8
- package/package.json +12 -11
- package/dist/helpers/nodeLayoutHelper.d.ts +0 -14
- package/dist/helpers/nodeLayoutHelper.js +0 -19
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
ConsoleInput Component
|
|
3
|
+
Single-line command input with prompt prefix, Enter-to-submit, Escape-to-close
|
|
4
|
+
Includes autocomplete for command verbs and node type IDs
|
|
5
|
+
Styled with BEM syntax matching CommandConsole pattern
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
<script lang="ts">
|
|
9
|
+
import type { NodeMetadata } from '../../types/index.js';
|
|
10
|
+
import { getWorkflowStore } from '../../stores/workflowStore.svelte.js';
|
|
11
|
+
import { toShortId, resolveNode } from '../../commands/index.js';
|
|
12
|
+
import ConsoleAutocomplete, { type Suggestion } from './ConsoleAutocomplete.svelte';
|
|
13
|
+
|
|
14
|
+
interface Props {
|
|
15
|
+
/** Whether the console is currently visible/open */
|
|
16
|
+
open: boolean;
|
|
17
|
+
/** Available node types for autocomplete suggestions */
|
|
18
|
+
nodeTypes?: NodeMetadata[];
|
|
19
|
+
/** Called when user submits a command (Enter key) */
|
|
20
|
+
onSubmit: (value: string) => void;
|
|
21
|
+
/** Called when user pastes multiple lines */
|
|
22
|
+
onBatchSubmit?: (lines: string[]) => void;
|
|
23
|
+
/** Called when user presses Escape to close the console */
|
|
24
|
+
onClose: () => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let { open, nodeTypes = [], onSubmit, onBatchSubmit, onClose }: Props = $props();
|
|
28
|
+
|
|
29
|
+
let inputValue = $state('');
|
|
30
|
+
let inputElement: HTMLInputElement | undefined = $state();
|
|
31
|
+
|
|
32
|
+
// Multiline value entry state
|
|
33
|
+
let multilineMode = $state(false);
|
|
34
|
+
let multilinePrefix = $state(''); // e.g. "set node1:prompt"
|
|
35
|
+
let textareaValue = $state('');
|
|
36
|
+
let textareaElement: HTMLTextAreaElement | undefined = $state();
|
|
37
|
+
|
|
38
|
+
// Command history state
|
|
39
|
+
const MAX_HISTORY = 100;
|
|
40
|
+
let history: string[] = $state([]);
|
|
41
|
+
let historyIndex = $state(-1);
|
|
42
|
+
let savedInput = $state('');
|
|
43
|
+
|
|
44
|
+
// Autocomplete state
|
|
45
|
+
let acVisible = $state(false);
|
|
46
|
+
let acSelectedIndex = $state(0);
|
|
47
|
+
let acSuggestions: Suggestion[] = $state([]);
|
|
48
|
+
|
|
49
|
+
const COMMAND_VERBS = [
|
|
50
|
+
'add',
|
|
51
|
+
'delete',
|
|
52
|
+
'rename',
|
|
53
|
+
'set',
|
|
54
|
+
'get',
|
|
55
|
+
'info',
|
|
56
|
+
'config',
|
|
57
|
+
'select',
|
|
58
|
+
'connect',
|
|
59
|
+
'disconnect',
|
|
60
|
+
'list',
|
|
61
|
+
'undo',
|
|
62
|
+
'redo',
|
|
63
|
+
'help',
|
|
64
|
+
'clear',
|
|
65
|
+
'cls',
|
|
66
|
+
'swap',
|
|
67
|
+
'move',
|
|
68
|
+
'layout',
|
|
69
|
+
'canvas'
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
/** Verbs that take a nodeId as their first argument */
|
|
73
|
+
const NODE_ID_VERBS = [
|
|
74
|
+
'delete',
|
|
75
|
+
'rename',
|
|
76
|
+
'info',
|
|
77
|
+
'config',
|
|
78
|
+
'select',
|
|
79
|
+
'set',
|
|
80
|
+
'get',
|
|
81
|
+
'disconnect',
|
|
82
|
+
'swap',
|
|
83
|
+
'move'
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
$effect(() => {
|
|
87
|
+
if (open && inputElement) {
|
|
88
|
+
inputElement.focus();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get node suggestions from the live workflow store.
|
|
94
|
+
* Returns suggestions with short IDs and labels.
|
|
95
|
+
*/
|
|
96
|
+
function getWorkflowNodeSuggestions(prefix: string): Suggestion[] {
|
|
97
|
+
const workflow = getWorkflowStore();
|
|
98
|
+
if (!workflow) return [];
|
|
99
|
+
|
|
100
|
+
const lowerPrefix = prefix.toLowerCase();
|
|
101
|
+
return workflow.nodes
|
|
102
|
+
.map((node) => {
|
|
103
|
+
const shortId = toShortId(node.id);
|
|
104
|
+
return {
|
|
105
|
+
value: shortId,
|
|
106
|
+
label: shortId,
|
|
107
|
+
detail: node.data.label
|
|
108
|
+
};
|
|
109
|
+
})
|
|
110
|
+
.filter((s) => s.value.toLowerCase().startsWith(lowerPrefix))
|
|
111
|
+
.slice(0, 50);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Detect if cursor is at a position expecting a node ID.
|
|
116
|
+
* Returns the partial text typed so far, or null if not at a nodeId position.
|
|
117
|
+
*/
|
|
118
|
+
function getNodeIdContext(value: string): {
|
|
119
|
+
partial: string;
|
|
120
|
+
type: 'nodeId' | 'connectSource' | 'connectTarget';
|
|
121
|
+
} | null {
|
|
122
|
+
// "connect <source> to <partial>" — target node ID
|
|
123
|
+
const connectToMatch = value.match(/^connect\s+\S+\s+to\s+(.*)$/i);
|
|
124
|
+
if (connectToMatch) return { partial: connectToMatch[1], type: 'connectTarget' };
|
|
125
|
+
|
|
126
|
+
// "connect <partial>" — source node ID (only if no "to" keyword yet)
|
|
127
|
+
const connectMatch = value.match(/^connect\s+(?!.*\bto\b)(.*)$/i);
|
|
128
|
+
if (connectMatch) return { partial: connectMatch[1], type: 'connectSource' };
|
|
129
|
+
|
|
130
|
+
// Verbs that take nodeId as first arg: "verb <partial>"
|
|
131
|
+
for (const verb of NODE_ID_VERBS) {
|
|
132
|
+
const regex = new RegExp(`^${verb}\\s+(.*)$`, 'i');
|
|
133
|
+
const match = value.match(regex);
|
|
134
|
+
if (match) {
|
|
135
|
+
// Only suggest if the partial doesn't already contain a space
|
|
136
|
+
// (user has moved past the nodeId arg to further args)
|
|
137
|
+
const partial = match[1];
|
|
138
|
+
if (!partial.includes(' ') && !partial.includes(':')) {
|
|
139
|
+
return { partial, type: 'nodeId' };
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Detect if cursor is after a "<nodeId>:" pattern, indicating port or config key position.
|
|
150
|
+
* Returns the nodeId, partial text after colon, and context type.
|
|
151
|
+
*/
|
|
152
|
+
function getPortOrConfigContext(value: string): {
|
|
153
|
+
nodeId: string;
|
|
154
|
+
partial: string;
|
|
155
|
+
type: 'outputPort' | 'inputPort' | 'configKey' | 'port';
|
|
156
|
+
} | null {
|
|
157
|
+
// "connect <nodeId>:<partial>" — output ports (source position, no "to" yet)
|
|
158
|
+
const connectSourcePort = value.match(/^connect\s+(\S+?):(\S*)$/i);
|
|
159
|
+
if (connectSourcePort && !/\bto\b/i.test(value)) {
|
|
160
|
+
return {
|
|
161
|
+
nodeId: connectSourcePort[1],
|
|
162
|
+
partial: connectSourcePort[2],
|
|
163
|
+
type: 'outputPort'
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// "connect <source> to <nodeId>:<partial>" — input ports (target position)
|
|
168
|
+
const connectTargetPort = value.match(/^connect\s+\S+\s+to\s+(\S+?):(\S*)$/i);
|
|
169
|
+
if (connectTargetPort) {
|
|
170
|
+
return {
|
|
171
|
+
nodeId: connectTargetPort[1],
|
|
172
|
+
partial: connectTargetPort[2],
|
|
173
|
+
type: 'inputPort'
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// "set <nodeId>:<partial>" — config keys
|
|
178
|
+
const setMatch = value.match(/^set\s+(\S+?):(\S*)$/i);
|
|
179
|
+
if (setMatch) {
|
|
180
|
+
return { nodeId: setMatch[1], partial: setMatch[2], type: 'configKey' };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// "get <nodeId>:<partial>" — config keys
|
|
184
|
+
const getMatch = value.match(/^get\s+(\S+?):(\S*)$/i);
|
|
185
|
+
if (getMatch) {
|
|
186
|
+
return { nodeId: getMatch[1], partial: getMatch[2], type: 'configKey' };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// "disconnect <nodeId>:<partial>" — all ports
|
|
190
|
+
const disconnectMatch = value.match(/^disconnect\s+(\S+?):(\S*)$/i);
|
|
191
|
+
if (disconnectMatch) {
|
|
192
|
+
return {
|
|
193
|
+
nodeId: disconnectMatch[1],
|
|
194
|
+
partial: disconnectMatch[2],
|
|
195
|
+
type: 'port'
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get port suggestions for a resolved node, filtered by direction and prefix.
|
|
204
|
+
*/
|
|
205
|
+
function getPortSuggestions(
|
|
206
|
+
nodeId: string,
|
|
207
|
+
partial: string,
|
|
208
|
+
filter: 'input' | 'output' | 'all'
|
|
209
|
+
): Suggestion[] {
|
|
210
|
+
const workflow = getWorkflowStore();
|
|
211
|
+
if (!workflow) return [];
|
|
212
|
+
|
|
213
|
+
const node = resolveNode(nodeId, workflow.nodes);
|
|
214
|
+
if (!node) return [];
|
|
215
|
+
|
|
216
|
+
const metadata = node.data.metadata;
|
|
217
|
+
if (!metadata) return [];
|
|
218
|
+
|
|
219
|
+
const lowerPartial = partial.toLowerCase();
|
|
220
|
+
const ports = [
|
|
221
|
+
...(filter === 'input' || filter === 'all' ? metadata.inputs : []),
|
|
222
|
+
...(filter === 'output' || filter === 'all' ? metadata.outputs : [])
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
const staticSuggestions = ports
|
|
226
|
+
.filter((p) => p.id.toLowerCase().startsWith(lowerPartial))
|
|
227
|
+
.map((p) => ({
|
|
228
|
+
value: p.id,
|
|
229
|
+
label: p.id,
|
|
230
|
+
detail: `${p.name} (${p.dataType})`
|
|
231
|
+
}));
|
|
232
|
+
|
|
233
|
+
// Gateway nodes (e.g. if_else) have dynamic branch outputs stored in config, not metadata
|
|
234
|
+
const branchSuggestions: Suggestion[] = [];
|
|
235
|
+
if ((filter === 'output' || filter === 'all') && metadata.type === 'gateway') {
|
|
236
|
+
const branches = node.data.config?.branches as
|
|
237
|
+
| Array<{ name: string; label?: string }>
|
|
238
|
+
| undefined;
|
|
239
|
+
if (branches) {
|
|
240
|
+
for (const branch of branches) {
|
|
241
|
+
if (branch.name.toLowerCase().startsWith(lowerPartial)) {
|
|
242
|
+
branchSuggestions.push({
|
|
243
|
+
value: branch.name,
|
|
244
|
+
label: branch.name,
|
|
245
|
+
detail: branch.label ? `branch: ${branch.label}` : 'branch'
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return [...staticSuggestions, ...branchSuggestions].slice(0, 50);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get config key suggestions for a resolved node, filtered by prefix.
|
|
257
|
+
*/
|
|
258
|
+
function getConfigKeySuggestions(nodeId: string, partial: string): Suggestion[] {
|
|
259
|
+
const workflow = getWorkflowStore();
|
|
260
|
+
if (!workflow) return [];
|
|
261
|
+
|
|
262
|
+
const node = resolveNode(nodeId, workflow.nodes);
|
|
263
|
+
if (!node) return [];
|
|
264
|
+
|
|
265
|
+
const metadata = node.data.metadata;
|
|
266
|
+
if (!metadata?.configSchema?.properties) return [];
|
|
267
|
+
|
|
268
|
+
const lowerPartial = partial.toLowerCase();
|
|
269
|
+
return Object.entries(metadata.configSchema.properties)
|
|
270
|
+
.filter(([key]) => key.toLowerCase().startsWith(lowerPartial))
|
|
271
|
+
.map(([key, prop]) => ({
|
|
272
|
+
value: key,
|
|
273
|
+
label: key,
|
|
274
|
+
detail: typeof prop === 'object' && 'type' in prop ? String(prop.type) : undefined
|
|
275
|
+
}))
|
|
276
|
+
.slice(0, 50);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Sub-commands for verbs that have them */
|
|
280
|
+
const SUBCOMMAND_MAP: Record<string, Array<{ value: string; detail?: string }>> = {
|
|
281
|
+
layout: [
|
|
282
|
+
{ value: 'auto', detail: 'Re-arrange all nodes from scratch' },
|
|
283
|
+
{ value: 'beautify', detail: 'Normalize spacing, preserve arrangement' }
|
|
284
|
+
],
|
|
285
|
+
list: [
|
|
286
|
+
{ value: 'nodes', detail: 'List all workflow nodes' },
|
|
287
|
+
{ value: 'edges', detail: 'List all connections' },
|
|
288
|
+
{ value: 'types', detail: 'List available node types' }
|
|
289
|
+
],
|
|
290
|
+
canvas: [
|
|
291
|
+
{ value: 'fitview', detail: 'Fit all nodes into the viewport' },
|
|
292
|
+
{ value: 'zoom in', detail: 'Zoom in on the canvas' },
|
|
293
|
+
{ value: 'zoom out', detail: 'Zoom out on the canvas' },
|
|
294
|
+
{ value: 'zoom', detail: 'Set zoom level (e.g. canvas zoom 1.5)' },
|
|
295
|
+
{ value: 'pan', detail: 'Pan to position (e.g. canvas pan 100,200)' },
|
|
296
|
+
{ value: 'reset', detail: 'Reset viewport to default' }
|
|
297
|
+
]
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
function computeSuggestions(value: string): Suggestion[] {
|
|
301
|
+
if (!value) return [];
|
|
302
|
+
|
|
303
|
+
// Check if we're after "<nodeId>:" — port names or config keys
|
|
304
|
+
const portConfigCtx = getPortOrConfigContext(value);
|
|
305
|
+
if (portConfigCtx !== null) {
|
|
306
|
+
if (portConfigCtx.type === 'configKey') {
|
|
307
|
+
return getConfigKeySuggestions(portConfigCtx.nodeId, portConfigCtx.partial);
|
|
308
|
+
}
|
|
309
|
+
const filter =
|
|
310
|
+
portConfigCtx.type === 'outputPort'
|
|
311
|
+
? 'output'
|
|
312
|
+
: portConfigCtx.type === 'inputPort'
|
|
313
|
+
? 'input'
|
|
314
|
+
: 'all';
|
|
315
|
+
return getPortSuggestions(portConfigCtx.nodeId, portConfigCtx.partial, filter);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Check if we're at a sub-command position (e.g. "layout <partial>")
|
|
319
|
+
const subCmdContext = getSubcommandContext(value);
|
|
320
|
+
if (subCmdContext !== null) {
|
|
321
|
+
const prefix = subCmdContext.partial.toLowerCase();
|
|
322
|
+
return subCmdContext.options
|
|
323
|
+
.filter((opt) => opt.value.toLowerCase().startsWith(prefix))
|
|
324
|
+
.map((opt) => ({
|
|
325
|
+
value: opt.value,
|
|
326
|
+
label: opt.value,
|
|
327
|
+
detail: opt.detail
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Check if we're in a position where node type IDs should be suggested
|
|
332
|
+
const nodeTypeContext = getNodeTypeContext(value);
|
|
333
|
+
if (nodeTypeContext !== null) {
|
|
334
|
+
const prefix = nodeTypeContext.toLowerCase();
|
|
335
|
+
return nodeTypes
|
|
336
|
+
.filter((nt) => nt.id.toLowerCase().startsWith(prefix))
|
|
337
|
+
.map((nt) => ({
|
|
338
|
+
value: nt.id,
|
|
339
|
+
label: nt.id,
|
|
340
|
+
detail: `${nt.name} (${nt.category})`
|
|
341
|
+
}))
|
|
342
|
+
.slice(0, 50);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Check if we're at a position expecting a node ID from the workflow
|
|
346
|
+
const nodeIdContext = getNodeIdContext(value);
|
|
347
|
+
if (nodeIdContext !== null) {
|
|
348
|
+
return getWorkflowNodeSuggestions(nodeIdContext.partial);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Check if we're at verb position (no space in input yet)
|
|
352
|
+
if (!value.includes(' ')) {
|
|
353
|
+
const prefix = value.toLowerCase();
|
|
354
|
+
return COMMAND_VERBS.filter((v) => v.startsWith(prefix)).map((v) => ({
|
|
355
|
+
value: v,
|
|
356
|
+
label: v
|
|
357
|
+
}));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return [];
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Detect if cursor is at a sub-command position (e.g. "layout <partial>").
|
|
365
|
+
* Returns the verb's sub-command options and the partial typed so far, or null.
|
|
366
|
+
*/
|
|
367
|
+
function getSubcommandContext(value: string): {
|
|
368
|
+
partial: string;
|
|
369
|
+
options: Array<{ value: string; detail?: string }>;
|
|
370
|
+
} | null {
|
|
371
|
+
const match = value.match(/^(\w+)\s+(.*)$/i);
|
|
372
|
+
if (!match) return null;
|
|
373
|
+
const verb = match[1].toLowerCase();
|
|
374
|
+
const partial = match[2];
|
|
375
|
+
const options = SUBCOMMAND_MAP[verb];
|
|
376
|
+
if (!options) return null;
|
|
377
|
+
// Only suggest if the partial has no further spaces (still on sub-command)
|
|
378
|
+
if (partial.includes(' ')) return null;
|
|
379
|
+
return { partial, options };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Returns the partial text after "add " or "swap <nodeId> with " if at a
|
|
384
|
+
* node-type position, or null otherwise.
|
|
385
|
+
*/
|
|
386
|
+
function getNodeTypeContext(value: string): string | null {
|
|
387
|
+
// "add <partial>"
|
|
388
|
+
const addMatch = value.match(/^add\s+(.*)$/i);
|
|
389
|
+
if (addMatch) return addMatch[1];
|
|
390
|
+
|
|
391
|
+
// "swap <nodeId> with <partial>"
|
|
392
|
+
const swapMatch = value.match(/^swap\s+\S+\s+with\s+(.*)$/i);
|
|
393
|
+
if (swapMatch) return swapMatch[1];
|
|
394
|
+
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
let debounceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
399
|
+
|
|
400
|
+
function updateAutocomplete() {
|
|
401
|
+
clearTimeout(debounceTimer);
|
|
402
|
+
debounceTimer = setTimeout(() => {
|
|
403
|
+
const suggestions = computeSuggestions(inputValue);
|
|
404
|
+
acSuggestions = suggestions;
|
|
405
|
+
acSelectedIndex = 0;
|
|
406
|
+
acVisible = suggestions.length > 0;
|
|
407
|
+
}, 100);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function dismissAutocomplete() {
|
|
411
|
+
acVisible = false;
|
|
412
|
+
acSuggestions = [];
|
|
413
|
+
acSelectedIndex = 0;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function acceptSuggestion(suggestion: Suggestion) {
|
|
417
|
+
// Replace the relevant part of input with the suggestion value
|
|
418
|
+
const portConfigCtx = getPortOrConfigContext(inputValue);
|
|
419
|
+
if (portConfigCtx !== null) {
|
|
420
|
+
// Replace the partial after the colon
|
|
421
|
+
const prefixEnd = inputValue.length - portConfigCtx.partial.length;
|
|
422
|
+
inputValue = inputValue.slice(0, prefixEnd) + suggestion.value;
|
|
423
|
+
dismissAutocomplete();
|
|
424
|
+
inputElement?.focus();
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const subCmdContext = getSubcommandContext(inputValue);
|
|
429
|
+
if (subCmdContext !== null) {
|
|
430
|
+
// Replace the partial after the verb
|
|
431
|
+
const prefixEnd = inputValue.length - subCmdContext.partial.length;
|
|
432
|
+
inputValue = inputValue.slice(0, prefixEnd) + suggestion.value;
|
|
433
|
+
} else {
|
|
434
|
+
const nodeTypeContext = getNodeTypeContext(inputValue);
|
|
435
|
+
if (nodeTypeContext !== null) {
|
|
436
|
+
// Replace the partial after the command prefix (node type context)
|
|
437
|
+
const prefixEnd = inputValue.length - nodeTypeContext.length;
|
|
438
|
+
inputValue = inputValue.slice(0, prefixEnd) + suggestion.value;
|
|
439
|
+
} else {
|
|
440
|
+
const nodeIdContext = getNodeIdContext(inputValue);
|
|
441
|
+
if (nodeIdContext !== null) {
|
|
442
|
+
// Replace the partial after the command prefix (node ID context)
|
|
443
|
+
const prefixEnd = inputValue.length - nodeIdContext.partial.length;
|
|
444
|
+
inputValue = inputValue.slice(0, prefixEnd) + suggestion.value;
|
|
445
|
+
} else {
|
|
446
|
+
// Replace the whole input (verb position)
|
|
447
|
+
inputValue = suggestion.value;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
dismissAutocomplete();
|
|
452
|
+
inputElement?.focus();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function addToHistory(command: string) {
|
|
456
|
+
// Don't store duplicate consecutive commands
|
|
457
|
+
if (history.length > 0 && history[history.length - 1] === command) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
history.push(command);
|
|
461
|
+
// Drop oldest when full
|
|
462
|
+
if (history.length > MAX_HISTORY) {
|
|
463
|
+
history.shift();
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Enter multiline textarea mode for the given set-command prefix.
|
|
469
|
+
* prefixText: e.g. "set node1:prompt", initialValue: partial value already typed
|
|
470
|
+
*/
|
|
471
|
+
function enterMultilineMode(prefixText: string, initialValue: string) {
|
|
472
|
+
multilinePrefix = prefixText;
|
|
473
|
+
textareaValue = initialValue;
|
|
474
|
+
multilineMode = true;
|
|
475
|
+
inputValue = '';
|
|
476
|
+
dismissAutocomplete();
|
|
477
|
+
setTimeout(() => textareaElement?.focus(), 0);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
function exitMultilineMode() {
|
|
481
|
+
multilineMode = false;
|
|
482
|
+
multilinePrefix = '';
|
|
483
|
+
textareaValue = '';
|
|
484
|
+
setTimeout(() => inputElement?.focus(), 0);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function submitMultilineValue() {
|
|
488
|
+
const value = textareaValue;
|
|
489
|
+
const prefix = multilinePrefix; // capture before exitMultilineMode clears it
|
|
490
|
+
exitMultilineMode();
|
|
491
|
+
if (!value.trim()) return;
|
|
492
|
+
const command = `${prefix} """\n${value}\n"""`;
|
|
493
|
+
addToHistory(command);
|
|
494
|
+
onSubmit(command);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function handleTextareaKeydown(event: KeyboardEvent) {
|
|
498
|
+
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
|
|
499
|
+
event.preventDefault();
|
|
500
|
+
submitMultilineValue();
|
|
501
|
+
} else if (event.key === 'Escape') {
|
|
502
|
+
event.preventDefault();
|
|
503
|
+
exitMultilineMode();
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function handlePaste(event: ClipboardEvent) {
|
|
508
|
+
const text = event.clipboardData?.getData('text/plain');
|
|
509
|
+
if (!text || !text.includes('\n')) return;
|
|
510
|
+
|
|
511
|
+
// If already typing a set command, treat multiline paste as the value
|
|
512
|
+
const setMatch = inputValue.match(/^(set\s+\S+?:\S+)\s*(.*)$/i);
|
|
513
|
+
if (setMatch) {
|
|
514
|
+
event.preventDefault();
|
|
515
|
+
enterMultilineMode(setMatch[1], (setMatch[2] ? setMatch[2] + '\n' : '') + text);
|
|
516
|
+
historyIndex = -1;
|
|
517
|
+
savedInput = '';
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Multi-line paste: prevent default and batch-submit
|
|
522
|
+
event.preventDefault();
|
|
523
|
+
const lines = text
|
|
524
|
+
.split('\n')
|
|
525
|
+
.map((l) => l.trim())
|
|
526
|
+
.filter((l) => l.length > 0);
|
|
527
|
+
if (lines.length <= 1) return;
|
|
528
|
+
|
|
529
|
+
// Add each line to history
|
|
530
|
+
for (const line of lines) {
|
|
531
|
+
addToHistory(line);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (onBatchSubmit) {
|
|
535
|
+
onBatchSubmit(lines);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
inputValue = '';
|
|
539
|
+
historyIndex = -1;
|
|
540
|
+
savedInput = '';
|
|
541
|
+
dismissAutocomplete();
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
545
|
+
// When autocomplete is visible, intercept navigation keys
|
|
546
|
+
if (acVisible && acSuggestions.length > 0) {
|
|
547
|
+
if (event.key === 'ArrowUp') {
|
|
548
|
+
event.preventDefault();
|
|
549
|
+
acSelectedIndex = acSelectedIndex > 0 ? acSelectedIndex - 1 : acSuggestions.length - 1;
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
if (event.key === 'ArrowDown') {
|
|
553
|
+
event.preventDefault();
|
|
554
|
+
acSelectedIndex = acSelectedIndex < acSuggestions.length - 1 ? acSelectedIndex + 1 : 0;
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (event.key === 'Tab') {
|
|
558
|
+
event.preventDefault();
|
|
559
|
+
acceptSuggestion(acSuggestions[acSelectedIndex]);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
if (event.key === 'Enter') {
|
|
563
|
+
const selected = acSuggestions[acSelectedIndex];
|
|
564
|
+
// If accepting the suggestion wouldn't change the input, execute directly
|
|
565
|
+
const before = inputValue;
|
|
566
|
+
acceptSuggestion(selected);
|
|
567
|
+
if (inputValue !== before) {
|
|
568
|
+
event.preventDefault();
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
// Input unchanged — fall through to submit handler below
|
|
572
|
+
}
|
|
573
|
+
if (event.key === 'Escape') {
|
|
574
|
+
event.preventDefault();
|
|
575
|
+
dismissAutocomplete();
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (event.key === 'Enter' && event.shiftKey) {
|
|
581
|
+
// Shift+Enter on a set command → expand to multiline textarea
|
|
582
|
+
const setMatch = inputValue.match(/^(set\s+\S+?:\S+)\s*(.*)$/i);
|
|
583
|
+
if (setMatch) {
|
|
584
|
+
event.preventDefault();
|
|
585
|
+
enterMultilineMode(setMatch[1], setMatch[2]);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
591
|
+
event.preventDefault();
|
|
592
|
+
const value = inputValue.trim();
|
|
593
|
+
if (value) {
|
|
594
|
+
addToHistory(value);
|
|
595
|
+
onSubmit(value);
|
|
596
|
+
inputValue = '';
|
|
597
|
+
historyIndex = -1;
|
|
598
|
+
savedInput = '';
|
|
599
|
+
dismissAutocomplete();
|
|
600
|
+
}
|
|
601
|
+
} else if (event.key === 'Escape') {
|
|
602
|
+
event.preventDefault();
|
|
603
|
+
onClose();
|
|
604
|
+
} else if (event.key === 'ArrowUp') {
|
|
605
|
+
event.preventDefault();
|
|
606
|
+
if (history.length === 0) return;
|
|
607
|
+
if (historyIndex === -1) {
|
|
608
|
+
// Save current input before navigating history
|
|
609
|
+
savedInput = inputValue;
|
|
610
|
+
historyIndex = history.length - 1;
|
|
611
|
+
} else if (historyIndex > 0) {
|
|
612
|
+
historyIndex--;
|
|
613
|
+
}
|
|
614
|
+
inputValue = history[historyIndex];
|
|
615
|
+
dismissAutocomplete();
|
|
616
|
+
} else if (event.key === 'ArrowDown') {
|
|
617
|
+
event.preventDefault();
|
|
618
|
+
if (historyIndex === -1) return;
|
|
619
|
+
if (historyIndex < history.length - 1) {
|
|
620
|
+
historyIndex++;
|
|
621
|
+
inputValue = history[historyIndex];
|
|
622
|
+
} else {
|
|
623
|
+
// Past newest entry — return to saved input
|
|
624
|
+
historyIndex = -1;
|
|
625
|
+
inputValue = savedInput;
|
|
626
|
+
}
|
|
627
|
+
dismissAutocomplete();
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function handleInput() {
|
|
632
|
+
// Typing resets history navigation
|
|
633
|
+
historyIndex = -1;
|
|
634
|
+
updateAutocomplete();
|
|
635
|
+
}
|
|
636
|
+
</script>
|
|
637
|
+
|
|
638
|
+
<div class="console-input" class:console-input--multiline={multilineMode}>
|
|
639
|
+
<span class="console-input__prompt">></span>
|
|
640
|
+
<div class="console-input__wrapper">
|
|
641
|
+
{#if multilineMode}
|
|
642
|
+
<div class="console-input__multiline-header">
|
|
643
|
+
<span class="console-input__multiline-label">{multilinePrefix}</span>
|
|
644
|
+
<span class="console-input__multiline-hint">Ctrl+Enter to submit · Esc to cancel</span>
|
|
645
|
+
</div>
|
|
646
|
+
<textarea
|
|
647
|
+
bind:this={textareaElement}
|
|
648
|
+
bind:value={textareaValue}
|
|
649
|
+
class="console-input__textarea"
|
|
650
|
+
rows={5}
|
|
651
|
+
spellcheck={false}
|
|
652
|
+
onkeydown={handleTextareaKeydown}
|
|
653
|
+
></textarea>
|
|
654
|
+
{:else}
|
|
655
|
+
<ConsoleAutocomplete
|
|
656
|
+
suggestions={acSuggestions}
|
|
657
|
+
visible={acVisible}
|
|
658
|
+
selectedIndex={acSelectedIndex}
|
|
659
|
+
onAccept={acceptSuggestion}
|
|
660
|
+
/>
|
|
661
|
+
<input
|
|
662
|
+
bind:this={inputElement}
|
|
663
|
+
bind:value={inputValue}
|
|
664
|
+
class="console-input__field"
|
|
665
|
+
type="text"
|
|
666
|
+
placeholder="Type a command... (set node:key + Shift+Enter for multiline)"
|
|
667
|
+
spellcheck="false"
|
|
668
|
+
autocomplete="off"
|
|
669
|
+
role="combobox"
|
|
670
|
+
aria-expanded={acVisible}
|
|
671
|
+
aria-controls="console-autocomplete-listbox"
|
|
672
|
+
aria-activedescendant={acVisible && acSuggestions.length > 0
|
|
673
|
+
? `console-autocomplete-option-${acSelectedIndex}`
|
|
674
|
+
: undefined}
|
|
675
|
+
onkeydown={handleKeydown}
|
|
676
|
+
oninput={handleInput}
|
|
677
|
+
onpaste={handlePaste}
|
|
678
|
+
onblur={() => dismissAutocomplete()}
|
|
679
|
+
/>
|
|
680
|
+
{/if}
|
|
681
|
+
</div>
|
|
682
|
+
</div>
|
|
683
|
+
|
|
684
|
+
<style>
|
|
685
|
+
.console-input {
|
|
686
|
+
display: flex;
|
|
687
|
+
align-items: center;
|
|
688
|
+
padding: 0.5rem 1rem;
|
|
689
|
+
border-top: 1px solid var(--fd-border-muted);
|
|
690
|
+
background-color: var(--fd-background);
|
|
691
|
+
flex-shrink: 0;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.console-input__prompt {
|
|
695
|
+
font-family: monospace;
|
|
696
|
+
font-size: 0.875rem;
|
|
697
|
+
color: var(--fd-muted-foreground);
|
|
698
|
+
margin-right: 0.5rem;
|
|
699
|
+
user-select: none;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
.console-input__wrapper {
|
|
703
|
+
flex: 1;
|
|
704
|
+
position: relative;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.console-input__field {
|
|
708
|
+
width: 100%;
|
|
709
|
+
background: none;
|
|
710
|
+
border: none;
|
|
711
|
+
outline: none;
|
|
712
|
+
font-family: monospace;
|
|
713
|
+
font-size: 0.875rem;
|
|
714
|
+
color: var(--fd-foreground);
|
|
715
|
+
padding: 0;
|
|
716
|
+
line-height: 1.5;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.console-input__field::placeholder {
|
|
720
|
+
color: var(--fd-muted-foreground);
|
|
721
|
+
opacity: 0.6;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.console-input--multiline {
|
|
725
|
+
align-items: flex-start;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.console-input--multiline .console-input__prompt {
|
|
729
|
+
margin-top: 0.125rem;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
.console-input__multiline-header {
|
|
733
|
+
display: flex;
|
|
734
|
+
justify-content: space-between;
|
|
735
|
+
align-items: baseline;
|
|
736
|
+
margin-bottom: 0.25rem;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.console-input__multiline-label {
|
|
740
|
+
font-family: monospace;
|
|
741
|
+
font-size: 0.875rem;
|
|
742
|
+
color: var(--fd-foreground);
|
|
743
|
+
font-weight: 500;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.console-input__multiline-hint {
|
|
747
|
+
font-family: monospace;
|
|
748
|
+
font-size: 0.75rem;
|
|
749
|
+
color: var(--fd-muted-foreground);
|
|
750
|
+
opacity: 0.7;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
.console-input__textarea {
|
|
754
|
+
width: 100%;
|
|
755
|
+
background: none;
|
|
756
|
+
border: 1px solid var(--fd-border-muted);
|
|
757
|
+
border-radius: var(--fd-radius-sm);
|
|
758
|
+
outline: none;
|
|
759
|
+
font-family: monospace;
|
|
760
|
+
font-size: 0.875rem;
|
|
761
|
+
color: var(--fd-foreground);
|
|
762
|
+
padding: 0.375rem 0.5rem;
|
|
763
|
+
line-height: 1.5;
|
|
764
|
+
resize: vertical;
|
|
765
|
+
min-height: 5rem;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.console-input__textarea:focus {
|
|
769
|
+
border-color: var(--fd-border);
|
|
770
|
+
}
|
|
771
|
+
</style>
|