@xdelivered/emberflow 0.2.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/LICENSE +21 -0
- package/README.md +153 -0
- package/bin/commands.test.ts +185 -0
- package/bin/commands.ts +306 -0
- package/bin/emberflow.mjs +38 -0
- package/bin/init.test.ts +165 -0
- package/bin/init.ts +297 -0
- package/bin/runtime.mjs +105 -0
- package/bin/runtime.test.ts +167 -0
- package/bin/skillTargets.test.ts +108 -0
- package/bin/skillTargets.ts +36 -0
- package/bin/skillTemplates.test.ts +37 -0
- package/bin/tsconfig.json +23 -0
- package/dist/bin/commands.d.ts +24 -0
- package/dist/bin/commands.js +252 -0
- package/dist/bin/init.d.ts +17 -0
- package/dist/bin/init.js +241 -0
- package/dist/bin/runtime.d.mts +39 -0
- package/dist/bin/runtime.mjs +96 -0
- package/dist/bin/skillTargets.d.ts +13 -0
- package/dist/bin/skillTargets.js +22 -0
- package/dist/server/agents/claudeAdapter.d.ts +8 -0
- package/dist/server/agents/claudeAdapter.js +190 -0
- package/dist/server/agents/claudeParse.d.ts +2 -0
- package/dist/server/agents/claudeParse.js +162 -0
- package/dist/server/agents/codexAdapter.d.ts +13 -0
- package/dist/server/agents/codexAdapter.js +174 -0
- package/dist/server/agents/codexParse.d.ts +2 -0
- package/dist/server/agents/codexParse.js +74 -0
- package/dist/server/agents/detect.d.ts +23 -0
- package/dist/server/agents/detect.js +35 -0
- package/dist/server/agents/gitScope.d.ts +24 -0
- package/dist/server/agents/gitScope.js +95 -0
- package/dist/server/agents/modelRejectionHint.d.ts +8 -0
- package/dist/server/agents/modelRejectionHint.js +12 -0
- package/dist/server/agents/prompt.d.ts +79 -0
- package/dist/server/agents/prompt.js +364 -0
- package/dist/server/agents/runManager.d.ts +90 -0
- package/dist/server/agents/runManager.js +259 -0
- package/dist/server/agents/types.d.ts +15 -0
- package/dist/server/agents/types.js +1 -0
- package/dist/server/apiStore.d.ts +60 -0
- package/dist/server/apiStore.js +249 -0
- package/dist/server/auth/enforce.d.ts +1 -0
- package/dist/server/auth/enforce.js +6 -0
- package/dist/server/auth/types.d.ts +1 -0
- package/dist/server/auth/types.js +1 -0
- package/dist/server/auth/verifiers.d.ts +1 -0
- package/dist/server/auth/verifiers.js +4 -0
- package/dist/server/authAttach.d.ts +19 -0
- package/dist/server/authAttach.js +79 -0
- package/dist/server/cli.d.ts +7 -0
- package/dist/server/cli.js +804 -0
- package/dist/server/client.d.ts +130 -0
- package/dist/server/client.js +247 -0
- package/dist/server/environments.d.ts +103 -0
- package/dist/server/environments.js +486 -0
- package/dist/server/flowStore.d.ts +37 -0
- package/dist/server/flowStore.js +117 -0
- package/dist/server/httpOperations.d.ts +32 -0
- package/dist/server/httpOperations.js +62 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1022 -0
- package/dist/server/infrastructure.d.ts +51 -0
- package/dist/server/infrastructure.js +116 -0
- package/dist/server/login.d.ts +21 -0
- package/dist/server/login.js +44 -0
- package/dist/server/mcp.d.ts +1 -0
- package/dist/server/mcp.js +182 -0
- package/dist/server/migrateFlows.d.ts +8 -0
- package/dist/server/migrateFlows.js +25 -0
- package/dist/server/mockHandler.d.ts +15 -0
- package/dist/server/mockHandler.js +35 -0
- package/dist/server/nodesPayload.d.ts +14 -0
- package/dist/server/nodesPayload.js +14 -0
- package/dist/server/normalizeFlow.d.ts +21 -0
- package/dist/server/normalizeFlow.js +48 -0
- package/dist/server/openBrowser.d.ts +8 -0
- package/dist/server/openBrowser.js +16 -0
- package/dist/server/operationResult.d.ts +12 -0
- package/dist/server/operationResult.js +26 -0
- package/dist/server/pathGuard.d.ts +1 -0
- package/dist/server/pathGuard.js +16 -0
- package/dist/server/pathSafety.d.ts +20 -0
- package/dist/server/pathSafety.js +35 -0
- package/dist/server/projectConfig.d.ts +47 -0
- package/dist/server/projectConfig.js +61 -0
- package/dist/server/projectMode.d.ts +26 -0
- package/dist/server/projectMode.js +44 -0
- package/dist/server/redact.d.ts +6 -0
- package/dist/server/redact.js +37 -0
- package/dist/server/runRegistry.d.ts +84 -0
- package/dist/server/runRegistry.js +200 -0
- package/dist/server/runtime/RuntimeAdapter.d.ts +22 -0
- package/dist/server/runtime/RuntimeAdapter.js +1 -0
- package/dist/server/runtime/expressAdapter.d.ts +19 -0
- package/dist/server/runtime/expressAdapter.js +56 -0
- package/dist/server/scenarioTest.d.ts +14 -0
- package/dist/server/scenarioTest.js +66 -0
- package/dist/server/subflowRunner.d.ts +32 -0
- package/dist/server/subflowRunner.js +72 -0
- package/dist/server/testRunner.d.ts +70 -0
- package/dist/server/testRunner.js +151 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +2 -0
- package/dist/src/engine/authVerify.d.ts +33 -0
- package/dist/src/engine/authVerify.js +63 -0
- package/dist/src/engine/diagnostics.d.ts +62 -0
- package/dist/src/engine/diagnostics.js +148 -0
- package/dist/src/engine/executor.d.ts +151 -0
- package/dist/src/engine/executor.js +684 -0
- package/dist/src/engine/httpError.d.ts +7 -0
- package/dist/src/engine/httpError.js +14 -0
- package/dist/src/engine/index.d.ts +11 -0
- package/dist/src/engine/index.js +11 -0
- package/dist/src/engine/output.d.ts +11 -0
- package/dist/src/engine/output.js +20 -0
- package/dist/src/engine/publish.d.ts +30 -0
- package/dist/src/engine/publish.js +95 -0
- package/dist/src/engine/registry.d.ts +34 -0
- package/dist/src/engine/registry.js +67 -0
- package/dist/src/engine/scenarios.d.ts +12 -0
- package/dist/src/engine/scenarios.js +19 -0
- package/dist/src/engine/schemaCheck.d.ts +4 -0
- package/dist/src/engine/schemaCheck.js +34 -0
- package/dist/src/engine/trace.d.ts +12 -0
- package/dist/src/engine/trace.js +12 -0
- package/dist/src/engine/types.d.ts +308 -0
- package/dist/src/engine/types.js +1 -0
- package/dist/src/engine/validation.d.ts +26 -0
- package/dist/src/engine/validation.js +318 -0
- package/dist/src/flows/anomaly-flows.d.ts +23 -0
- package/dist/src/flows/anomaly-flows.js +151 -0
- package/dist/src/flows/city-sweep-flow.d.ts +10 -0
- package/dist/src/flows/city-sweep-flow.js +127 -0
- package/dist/src/flows/login-flow.d.ts +13 -0
- package/dist/src/flows/login-flow.js +145 -0
- package/dist/src/flows/pradar-flows.d.ts +5 -0
- package/dist/src/flows/pradar-flows.js +375 -0
- package/dist/src/flows/weather-flow.d.ts +12 -0
- package/dist/src/flows/weather-flow.js +150 -0
- package/dist/src/lib/pathParams.d.ts +3 -0
- package/dist/src/lib/pathParams.js +6 -0
- package/dist/src/nodes/anomaly.d.ts +2 -0
- package/dist/src/nodes/anomaly.js +556 -0
- package/dist/src/nodes/flow-control.d.ts +7 -0
- package/dist/src/nodes/flow-control.js +270 -0
- package/dist/src/nodes/index.d.ts +3 -0
- package/dist/src/nodes/index.js +20 -0
- package/dist/src/nodes/login.d.ts +7 -0
- package/dist/src/nodes/login.js +158 -0
- package/dist/src/nodes/loops.d.ts +11 -0
- package/dist/src/nodes/loops.js +60 -0
- package/dist/src/nodes/pradar/index.d.ts +7 -0
- package/dist/src/nodes/pradar/index.js +9 -0
- package/dist/src/nodes/pradar/logic.d.ts +189 -0
- package/dist/src/nodes/pradar/logic.js +370 -0
- package/dist/src/nodes/pradar/nodes.d.ts +42 -0
- package/dist/src/nodes/pradar/nodes.js +801 -0
- package/dist/src/nodes/requireAuth.d.ts +20 -0
- package/dist/src/nodes/requireAuth.js +48 -0
- package/dist/src/nodes/response.d.ts +8 -0
- package/dist/src/nodes/response.js +33 -0
- package/dist/src/nodes/weather.d.ts +33 -0
- package/dist/src/nodes/weather.js +260 -0
- package/package.json +92 -0
- package/server/agentRoute.test.ts +157 -0
- package/server/agents/__fixtures__/fake-claude-writer.mjs +23 -0
- package/server/agents/__fixtures__/fake-claude.mjs +55 -0
- package/server/agents/__fixtures__/fake-codex-writer.mjs +27 -0
- package/server/agents/__fixtures__/fake-codex.mjs +52 -0
- package/server/agents/__fixtures__/fake-version-empty.mjs +3 -0
- package/server/agents/__fixtures__/fake-version-fail.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-garbage.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-good.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-hang.mjs +3 -0
- package/server/agents/claudeAdapter.test.ts +127 -0
- package/server/agents/claudeAdapter.ts +212 -0
- package/server/agents/claudeParse.ts +193 -0
- package/server/agents/codexAdapter.test.ts +125 -0
- package/server/agents/codexAdapter.ts +198 -0
- package/server/agents/codexParse.test.ts +58 -0
- package/server/agents/codexParse.ts +126 -0
- package/server/agents/detect.test.ts +65 -0
- package/server/agents/detect.ts +43 -0
- package/server/agents/gitScope.test.ts +129 -0
- package/server/agents/gitScope.ts +110 -0
- package/server/agents/modelRejectionHint.test.ts +30 -0
- package/server/agents/modelRejectionHint.ts +14 -0
- package/server/agents/prompt.test.ts +613 -0
- package/server/agents/prompt.ts +527 -0
- package/server/agents/runManager.test.ts +251 -0
- package/server/agents/runManager.ts +286 -0
- package/server/agents/types.ts +17 -0
- package/server/apiMount.test.ts +591 -0
- package/server/apiStore.test.ts +324 -0
- package/server/apiStore.ts +241 -0
- package/server/auth/enforce.test.ts +61 -0
- package/server/auth/enforce.ts +6 -0
- package/server/auth/types.ts +5 -0
- package/server/auth/verifiers.test.ts +37 -0
- package/server/auth/verifiers.ts +9 -0
- package/server/authAttach.test.ts +175 -0
- package/server/authAttach.ts +99 -0
- package/server/cli.ts +847 -0
- package/server/cliAuth.test.ts +229 -0
- package/server/cliCreate.test.ts +131 -0
- package/server/cliDoctor.test.ts +326 -0
- package/server/cliTest.test.ts +735 -0
- package/server/client.ts +314 -0
- package/server/demoProject.test.ts +29 -0
- package/server/diagnosticsRoute.test.ts +169 -0
- package/server/environments.test.ts +620 -0
- package/server/environments.ts +603 -0
- package/server/environmentsRoute.test.ts +385 -0
- package/server/errorWorkflow.test.ts +205 -0
- package/server/flowStore.test.ts +84 -0
- package/server/flowStore.ts +125 -0
- package/server/httpOperations.test.ts +377 -0
- package/server/httpOperations.ts +96 -0
- package/server/index.ts +1111 -0
- package/server/infrastructure.test.ts +154 -0
- package/server/infrastructure.ts +161 -0
- package/server/infrastructureRoute.test.ts +105 -0
- package/server/login.test.ts +153 -0
- package/server/login.ts +67 -0
- package/server/mcp.ts +278 -0
- package/server/migrateFlows.test.ts +55 -0
- package/server/migrateFlows.ts +23 -0
- package/server/mockHandler.test.ts +138 -0
- package/server/mockHandler.ts +52 -0
- package/server/mockRun.test.ts +367 -0
- package/server/mockServe.test.ts +467 -0
- package/server/nodesPayload.test.ts +29 -0
- package/server/nodesPayload.ts +26 -0
- package/server/normalizeFlow.test.ts +80 -0
- package/server/normalizeFlow.ts +59 -0
- package/server/openBrowser.test.ts +20 -0
- package/server/openBrowser.ts +22 -0
- package/server/operationResult.test.ts +67 -0
- package/server/operationResult.ts +27 -0
- package/server/pathGuard.test.ts +19 -0
- package/server/pathGuard.ts +12 -0
- package/server/pathSafety.test.ts +38 -0
- package/server/pathSafety.ts +33 -0
- package/server/projectConfig.test.ts +67 -0
- package/server/projectConfig.ts +101 -0
- package/server/projectMode.test.ts +106 -0
- package/server/projectMode.ts +59 -0
- package/server/redact.test.ts +88 -0
- package/server/redact.ts +35 -0
- package/server/redactEgress.test.ts +281 -0
- package/server/runRegistry.ts +270 -0
- package/server/runsAuth.test.ts +119 -0
- package/server/runtime/RuntimeAdapter.ts +24 -0
- package/server/runtime/expressAdapter.test.ts +38 -0
- package/server/runtime/expressAdapter.ts +70 -0
- package/server/scenarioTest.test.ts +148 -0
- package/server/scenarioTest.ts +88 -0
- package/server/setupStatus.test.ts +127 -0
- package/server/subflowRunner.ts +104 -0
- package/server/testRunner.ts +216 -0
- package/server/tsconfig.json +20 -0
- package/server/workflowTestRoute.test.ts +297 -0
- package/src/App.tsx +233 -0
- package/src/components/AgentConsole.tsx +461 -0
- package/src/components/BranchRulesEditor.tsx +156 -0
- package/src/components/CreateModal.tsx +275 -0
- package/src/components/Dock.tsx +487 -0
- package/src/components/EnvironmentDialog.tsx +569 -0
- package/src/components/EnvironmentPicker.tsx +357 -0
- package/src/components/EnvironmentsDialog.tsx +144 -0
- package/src/components/ExecutionPager.tsx +67 -0
- package/src/components/InfraPanel.test.tsx +103 -0
- package/src/components/InfraPanel.tsx +171 -0
- package/src/components/Inspector.tsx +1182 -0
- package/src/components/Json.tsx +50 -0
- package/src/components/JsonModal.tsx +52 -0
- package/src/components/LogMessage.tsx +61 -0
- package/src/components/NodeRunModal.tsx +213 -0
- package/src/components/RunLogPanel.tsx +397 -0
- package/src/components/RunbookView.tsx +1085 -0
- package/src/components/Scenarios.tsx +476 -0
- package/src/components/SettingsDialog.tsx +229 -0
- package/src/components/Sidebar.tsx +436 -0
- package/src/components/StatusBar.tsx +302 -0
- package/src/components/Toolbar.tsx +663 -0
- package/src/components/WelcomeDialog.test.tsx +107 -0
- package/src/components/WelcomeDialog.tsx +412 -0
- package/src/components/agentMarkdown.test.tsx +91 -0
- package/src/components/agentMarkdown.tsx +158 -0
- package/src/components/ui/badge.tsx +31 -0
- package/src/components/ui/button.tsx +46 -0
- package/src/components/ui/combobox.tsx +114 -0
- package/src/components/ui/command.tsx +82 -0
- package/src/components/ui/dialog.tsx +73 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/popover.tsx +32 -0
- package/src/components/ui/resizable.tsx +44 -0
- package/src/components/ui/tabs.tsx +36 -0
- package/src/config.ts +4 -0
- package/src/engine/authVerify.ts +81 -0
- package/src/engine/diagnostics.test.ts +437 -0
- package/src/engine/diagnostics.ts +211 -0
- package/src/engine/executor.test.ts +1339 -0
- package/src/engine/executor.ts +840 -0
- package/src/engine/httpError.test.ts +12 -0
- package/src/engine/httpError.ts +16 -0
- package/src/engine/index.ts +11 -0
- package/src/engine/output.ts +21 -0
- package/src/engine/publish.test.ts +176 -0
- package/src/engine/publish.ts +127 -0
- package/src/engine/registry.test.ts +64 -0
- package/src/engine/registry.ts +80 -0
- package/src/engine/scenarios.test.ts +55 -0
- package/src/engine/scenarios.ts +29 -0
- package/src/engine/schemaCheck.test.ts +21 -0
- package/src/engine/schemaCheck.ts +35 -0
- package/src/engine/trace.test.ts +19 -0
- package/src/engine/trace.ts +23 -0
- package/src/engine/types.test.ts +22 -0
- package/src/engine/types.ts +316 -0
- package/src/engine/validation.test.ts +314 -0
- package/src/engine/validation.ts +354 -0
- package/src/flows/anomaly-flows.test.ts +81 -0
- package/src/flows/anomaly-flows.ts +202 -0
- package/src/flows/city-sweep-flow.ts +131 -0
- package/src/flows/flows.test.ts +30 -0
- package/src/flows/login-flow.ts +150 -0
- package/src/flows/pradar-flows.test.ts +204 -0
- package/src/flows/pradar-flows.ts +419 -0
- package/src/flows/weather-flow.ts +154 -0
- package/src/globals.css +147 -0
- package/src/lib/pathParams.test.ts +24 -0
- package/src/lib/pathParams.ts +6 -0
- package/src/lib/registerLens.test.ts +79 -0
- package/src/lib/registerLens.ts +59 -0
- package/src/lib/runbookModel.test.ts +61 -0
- package/src/lib/runbookModel.ts +290 -0
- package/src/lib/runbookProjection.test.ts +417 -0
- package/src/lib/runbookProjection.ts +254 -0
- package/src/lib/useTailAnchor.ts +53 -0
- package/src/lib/utils.ts +7 -0
- package/src/main.tsx +13 -0
- package/src/nodes/anomaly.test.ts +98 -0
- package/src/nodes/anomaly.ts +637 -0
- package/src/nodes/effects-scan.test.ts +44 -0
- package/src/nodes/flow-control.test.ts +280 -0
- package/src/nodes/flow-control.ts +305 -0
- package/src/nodes/index.ts +22 -0
- package/src/nodes/login.test.ts +81 -0
- package/src/nodes/login.ts +186 -0
- package/src/nodes/loops.ts +69 -0
- package/src/nodes/pradar/index.ts +11 -0
- package/src/nodes/pradar/logic.test.ts +288 -0
- package/src/nodes/pradar/logic.ts +582 -0
- package/src/nodes/pradar/nodes.test.ts +146 -0
- package/src/nodes/pradar/nodes.ts +955 -0
- package/src/nodes/requireAuth.test.ts +75 -0
- package/src/nodes/requireAuth.ts +55 -0
- package/src/nodes/response.test.ts +33 -0
- package/src/nodes/response.ts +39 -0
- package/src/nodes/traceDetail.test.ts +39 -0
- package/src/nodes/weather.test.ts +65 -0
- package/src/nodes/weather.ts +306 -0
- package/src/store/agentClient.test.ts +103 -0
- package/src/store/agentClient.ts +131 -0
- package/src/store/apiTree.test.ts +17 -0
- package/src/store/apiTree.ts +73 -0
- package/src/store/builderStore.test.ts +1234 -0
- package/src/store/builderStore.ts +1879 -0
- package/src/store/infraClient.ts +63 -0
- package/src/store/nodeMeta.test.ts +24 -0
- package/src/store/nodeMeta.ts +21 -0
- package/src/store/persistence.test.ts +15 -0
- package/src/store/persistence.ts +54 -0
- package/src/store/serverRunner.ts +381 -0
- package/src/store/setupClient.ts +57 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
- package/studio-dist/assets/index-DNJwW-hM.css +1 -0
- package/studio-dist/assets/index-O26dKRjW.js +65 -0
- package/studio-dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/studio-dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/studio-dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/studio-dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/studio-dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/studio-dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/studio-dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/studio-dist/favicon.svg +1 -0
- package/studio-dist/icons.svg +24 -0
- package/studio-dist/index.html +14 -0
- package/templates/skills/emberflow-basics/SKILL.md +316 -0
- package/templates/skills/emberflow-model-process/SKILL.md +209 -0
- package/templates/skills/emberflow-new-workflow/SKILL.md +211 -0
- package/templates/skills/emberflow-review-workflow/SKILL.md +148 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { Maximize2Icon, PanelBottomIcon, PanelRightIcon, ShieldIcon, XIcon } from 'lucide-react';
|
|
3
|
+
import { Badge } from '@/components/ui/badge';
|
|
4
|
+
import { Button } from '@/components/ui/button';
|
|
5
|
+
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable';
|
|
6
|
+
import { effectiveConsolePosition, useBuilderStore } from '../store/builderStore';
|
|
7
|
+
import { useTailAnchor } from '../lib/useTailAnchor';
|
|
8
|
+
import { Json } from './Json';
|
|
9
|
+
import { LogMessage } from './LogMessage';
|
|
10
|
+
import { JsonModal } from './JsonModal';
|
|
11
|
+
import { cn } from '@/lib/utils';
|
|
12
|
+
import { filterLogs, formatDuration, payloadOpenByDefault } from '@/lib/registerLens';
|
|
13
|
+
import type { ViewRegister } from '@/lib/registerLens';
|
|
14
|
+
import type { NodeRunState } from '../engine';
|
|
15
|
+
|
|
16
|
+
const statusDot: Record<string, string> = {
|
|
17
|
+
succeeded: 'bg-success',
|
|
18
|
+
failed: 'bg-destructive',
|
|
19
|
+
cancelled: 'bg-muted-foreground',
|
|
20
|
+
running: 'bg-highlight animate-pulse',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const levelColor: Record<string, string> = {
|
|
24
|
+
info: 'text-success',
|
|
25
|
+
debug: 'text-muted-foreground/60',
|
|
26
|
+
warn: 'text-yellow-500',
|
|
27
|
+
error: 'text-destructive',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Whether the run console panel should be docked into the layout. Owned at
|
|
32
|
+
* the App level so the panel can join the resizable panel group like any
|
|
33
|
+
* other IDE panel. Only runs that actually executed while this session
|
|
34
|
+
* watched summon it — browsing run history never does — and it stays after
|
|
35
|
+
* the run finishes until dismissed.
|
|
36
|
+
*
|
|
37
|
+
* In the simple register, starting a run never auto-opens the console — it
|
|
38
|
+
* only opens once the user explicitly asks (the toolbar toggle), which is
|
|
39
|
+
* tracked per-run in `runConsoleOpenedIds`; from then on that run's console
|
|
40
|
+
* behaves exactly like the technical register's (dismiss/reopen). The
|
|
41
|
+
* technical register ignores that tracking and stays open as it always has.
|
|
42
|
+
*/
|
|
43
|
+
export function useRunConsole(): { available: boolean; open: boolean; running: boolean } {
|
|
44
|
+
const run = useBuilderStore((s) => s.run);
|
|
45
|
+
const dismissedId = useBuilderStore((s) => s.runConsoleDismissedId);
|
|
46
|
+
const register = useBuilderStore((s) => s.viewRegister);
|
|
47
|
+
const openedIds = useBuilderStore((s) => s.runConsoleOpenedIds);
|
|
48
|
+
const liveRunIds = useRef(new Set<string>());
|
|
49
|
+
if (run?.status === 'running') liveRunIds.current.add(run.id);
|
|
50
|
+
const available = run !== null && liveRunIds.current.has(run.id);
|
|
51
|
+
const userOpenedForThisRun = run !== null && openedIds.has(run.id);
|
|
52
|
+
const open = available && run!.id !== dismissedId && (register === 'technical' || userOpenedForThisRun);
|
|
53
|
+
const running = run?.status === 'running';
|
|
54
|
+
return { available, open, running };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Node detail: the lower half of the console's master-detail split. Shows the
|
|
59
|
+
* clicked node's LATEST input/output (or error), live as you step,
|
|
60
|
+
* iteration-aware for loop bodies.
|
|
61
|
+
*/
|
|
62
|
+
function NodeDetail({
|
|
63
|
+
label,
|
|
64
|
+
typeName,
|
|
65
|
+
state,
|
|
66
|
+
onClose,
|
|
67
|
+
register,
|
|
68
|
+
}: {
|
|
69
|
+
label: string;
|
|
70
|
+
typeName?: string;
|
|
71
|
+
state: NodeRunState | undefined;
|
|
72
|
+
onClose: () => void;
|
|
73
|
+
register: ViewRegister;
|
|
74
|
+
}) {
|
|
75
|
+
const [modal, setModal] = useState<{ title: string; value: unknown } | null>(null);
|
|
76
|
+
const latestExec = state?.executions?.[state.executions.length - 1];
|
|
77
|
+
const input = latestExec ? latestExec.input : state?.input;
|
|
78
|
+
const output = latestExec ? latestExec.output : state?.output;
|
|
79
|
+
const error = latestExec ? latestExec.error : state?.error;
|
|
80
|
+
const durationMs =
|
|
81
|
+
state?.startedAt && state?.completedAt
|
|
82
|
+
? new Date(state.completedAt).getTime() - new Date(state.startedAt).getTime()
|
|
83
|
+
: null;
|
|
84
|
+
|
|
85
|
+
const pane = (title: string, value: unknown) => (
|
|
86
|
+
<div className="group relative min-w-0 flex-1">
|
|
87
|
+
<div className="mb-1.5 text-[10px] font-medium uppercase tracking-widest text-muted-foreground">
|
|
88
|
+
{title}
|
|
89
|
+
</div>
|
|
90
|
+
{value !== undefined ? (
|
|
91
|
+
<>
|
|
92
|
+
<Json value={value} />
|
|
93
|
+
<Button
|
|
94
|
+
variant="ghost"
|
|
95
|
+
size="icon"
|
|
96
|
+
className="absolute top-6 right-1.5 size-6 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100 hover:text-foreground"
|
|
97
|
+
onClick={() => setModal({ title: `${label} · ${title.toLowerCase()}`, value })}
|
|
98
|
+
aria-label={`View full ${title.toLowerCase()}`}
|
|
99
|
+
>
|
|
100
|
+
<Maximize2Icon className="size-3.5" />
|
|
101
|
+
</Button>
|
|
102
|
+
</>
|
|
103
|
+
) : (
|
|
104
|
+
<div className="rounded-md border border-dashed border-border px-3 py-4 text-center text-[11.5px] text-muted-foreground/60">
|
|
105
|
+
nothing captured
|
|
106
|
+
</div>
|
|
107
|
+
)}
|
|
108
|
+
</div>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<div className="flex h-full min-h-0 flex-col bg-background/40">
|
|
113
|
+
<div className="flex h-9 shrink-0 items-center gap-2 border-b border-border/70 px-3">
|
|
114
|
+
<span className={cn('size-1.5 rounded-full', statusDot[state?.status ?? 'running'] ?? 'bg-muted-foreground')} />
|
|
115
|
+
<span className="min-w-0 truncate text-[12px] font-medium">{label}</span>
|
|
116
|
+
{typeName && (
|
|
117
|
+
<span className="hidden truncate font-mono text-[9.5px] text-muted-foreground sm:inline">{typeName}</span>
|
|
118
|
+
)}
|
|
119
|
+
{state?.iteration && (
|
|
120
|
+
<Badge variant="mono" className="shrink-0 text-[9px]">
|
|
121
|
+
{state.iteration.index + 1}/{state.iteration.total}
|
|
122
|
+
</Badge>
|
|
123
|
+
)}
|
|
124
|
+
<span className="ml-auto shrink-0 text-[9.5px] text-muted-foreground/70">
|
|
125
|
+
latest{durationMs !== null ? ` · ${formatDuration(durationMs, register)}` : ''}
|
|
126
|
+
</span>
|
|
127
|
+
<Button
|
|
128
|
+
variant="ghost"
|
|
129
|
+
size="icon"
|
|
130
|
+
className="size-5 shrink-0 text-muted-foreground hover:text-foreground"
|
|
131
|
+
onClick={onClose}
|
|
132
|
+
aria-label="Close node detail"
|
|
133
|
+
>
|
|
134
|
+
<XIcon className="size-3" />
|
|
135
|
+
</Button>
|
|
136
|
+
</div>
|
|
137
|
+
{state ? (
|
|
138
|
+
<div className="min-h-0 flex-1 space-y-3 overflow-y-auto p-3">
|
|
139
|
+
{pane('Input', input)}
|
|
140
|
+
{error !== undefined ? (
|
|
141
|
+
<div className="min-w-0">
|
|
142
|
+
<div className="mb-1.5 text-[10px] font-medium uppercase tracking-widest text-destructive">Error</div>
|
|
143
|
+
<pre className="overflow-auto rounded-md border border-destructive/50 bg-card p-3 font-mono text-[11.5px] leading-relaxed whitespace-pre-wrap text-destructive-foreground">
|
|
144
|
+
{error}
|
|
145
|
+
</pre>
|
|
146
|
+
</div>
|
|
147
|
+
) : (
|
|
148
|
+
pane('Output', output)
|
|
149
|
+
)}
|
|
150
|
+
</div>
|
|
151
|
+
) : (
|
|
152
|
+
<div className="p-4 text-[12px] text-muted-foreground/70">Not executed yet.</div>
|
|
153
|
+
)}
|
|
154
|
+
{modal && (
|
|
155
|
+
<JsonModal
|
|
156
|
+
title={modal.title}
|
|
157
|
+
value={modal.value}
|
|
158
|
+
open
|
|
159
|
+
onOpenChange={(open) => {
|
|
160
|
+
if (!open) setModal(null);
|
|
161
|
+
}}
|
|
162
|
+
/>
|
|
163
|
+
)}
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Run console: a docked IDE-style panel — either the rightmost column of the
|
|
170
|
+
* layout or a panel below the dock (position-agnostic, chosen by the user via
|
|
171
|
+
* the header's dock-side toggle) — that streams a run's logs live. Clicking a
|
|
172
|
+
* node in the log opens a master-detail split with that node's latest
|
|
173
|
+
* input/output.
|
|
174
|
+
*/
|
|
175
|
+
export function RunConsole({ onDismiss }: { onDismiss: () => void }) {
|
|
176
|
+
const run = useBuilderStore((s) => s.run);
|
|
177
|
+
const rawLogs = useBuilderStore((s) => s.logs);
|
|
178
|
+
const register = useBuilderStore((s) => s.viewRegister);
|
|
179
|
+
const flowName = useBuilderStore((s) => s.flow.name);
|
|
180
|
+
const flowNodes = useBuilderStore((s) => s.flow.nodes);
|
|
181
|
+
const selectNode = useBuilderStore((s) => s.selectNode);
|
|
182
|
+
const consolePositionChoice = useBuilderStore((s) => s.consolePosition);
|
|
183
|
+
const consolePosition = effectiveConsolePosition(consolePositionChoice, register);
|
|
184
|
+
const setConsolePosition = useBuilderStore((s) => s.setConsolePosition);
|
|
185
|
+
const [peek, setPeek] = useState<{ line: number; nodeId: string } | null>(null);
|
|
186
|
+
|
|
187
|
+
const logs = filterLogs(rawLogs, register);
|
|
188
|
+
const openByDefault = payloadOpenByDefault(register);
|
|
189
|
+
|
|
190
|
+
// Follow the tail only while the reader is at the bottom (and no peek is
|
|
191
|
+
// open) — scrolling up detaches; the pill jumps back.
|
|
192
|
+
const { scrollerRef, endRef: logEndRef, detached, jumpToLatest } = useTailAnchor(logs.length, { suspended: !!peek });
|
|
193
|
+
|
|
194
|
+
// Log indices reset with a new run's log stream — drop any open peek.
|
|
195
|
+
const peekRunRef = useRef<string | null>(null);
|
|
196
|
+
if ((run?.id ?? null) !== peekRunRef.current) {
|
|
197
|
+
peekRunRef.current = run?.id ?? null;
|
|
198
|
+
if (peek) setPeek(null);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Filtering changes which line index maps to which log entry — a peek
|
|
202
|
+
// anchored in one register can point at the wrong line (or nothing) in the
|
|
203
|
+
// other, so drop it on register flips just like a new run does.
|
|
204
|
+
const peekRegisterRef = useRef<ViewRegister>(register);
|
|
205
|
+
if (register !== peekRegisterRef.current) {
|
|
206
|
+
peekRegisterRef.current = register;
|
|
207
|
+
if (peek) setPeek(null);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const finished = run !== null && run.status !== 'running';
|
|
211
|
+
const durationMs =
|
|
212
|
+
run?.completedAt && run.startedAt
|
|
213
|
+
? new Date(run.completedAt).getTime() - new Date(run.startedAt).getTime()
|
|
214
|
+
: null;
|
|
215
|
+
|
|
216
|
+
// Live elapsed while running — a static "running…" undersells real work.
|
|
217
|
+
const [nowTick, setNowTick] = useState(() => Date.now());
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
if (finished) return;
|
|
220
|
+
const t = setInterval(() => setNowTick(Date.now()), 250);
|
|
221
|
+
return () => clearInterval(t);
|
|
222
|
+
}, [finished]);
|
|
223
|
+
const elapsedMs = finished
|
|
224
|
+
? durationMs
|
|
225
|
+
: run?.startedAt
|
|
226
|
+
? Math.max(0, nowTick - new Date(run.startedAt).getTime())
|
|
227
|
+
: null;
|
|
228
|
+
const elapsedText = elapsedMs === null ? '' : formatDuration(elapsedMs, register);
|
|
229
|
+
|
|
230
|
+
// Coarse progress: settled nodes over the flow's node count.
|
|
231
|
+
const states = Object.values(run?.nodeStates ?? {});
|
|
232
|
+
const settled = states.filter((s) => s.status === 'succeeded' || s.status === 'failed' || s.status === 'skipped').length;
|
|
233
|
+
const total = Math.max(states.length, 1);
|
|
234
|
+
const errorCount = states.filter((s) => s.status === 'failed').length;
|
|
235
|
+
|
|
236
|
+
const peekNode = peek ? flowNodes.find((n) => n.id === peek.nodeId) : undefined;
|
|
237
|
+
|
|
238
|
+
const logList = (
|
|
239
|
+
<div className="flex h-full min-h-0 flex-col">
|
|
240
|
+
<div ref={scrollerRef as unknown as React.Ref<HTMLDivElement>} className="relative min-h-0 flex-1 overflow-y-auto px-3 py-2">
|
|
241
|
+
{detached && (
|
|
242
|
+
<button
|
|
243
|
+
type="button"
|
|
244
|
+
onClick={jumpToLatest}
|
|
245
|
+
className="sticky top-0 left-1/2 z-10 -translate-x-1/2 rounded-full border border-highlight/40 bg-card px-3 py-0.5 text-[10.5px] text-highlight shadow-md hover:bg-secondary"
|
|
246
|
+
>
|
|
247
|
+
↓ latest
|
|
248
|
+
</button>
|
|
249
|
+
)}
|
|
250
|
+
{logs.length === 0 && (
|
|
251
|
+
<div className="px-1 py-2 text-[12px] text-muted-foreground/70">Waiting for logs…</div>
|
|
252
|
+
)}
|
|
253
|
+
{logs.map((line, i) => (
|
|
254
|
+
<div
|
|
255
|
+
key={i}
|
|
256
|
+
className={cn(
|
|
257
|
+
'flex items-baseline gap-2.5 py-0.5 font-mono text-[11px]',
|
|
258
|
+
line.level === 'debug' && 'opacity-60',
|
|
259
|
+
)}
|
|
260
|
+
>
|
|
261
|
+
<span className="shrink-0 text-muted-foreground/50">{line.timestamp.slice(11, 19)}</span>
|
|
262
|
+
<span
|
|
263
|
+
className={cn('w-9 shrink-0 text-[9.5px] uppercase tracking-wider', levelColor[line.level] ?? '')}
|
|
264
|
+
>
|
|
265
|
+
{line.level}
|
|
266
|
+
</span>
|
|
267
|
+
{line.nodeId ? (
|
|
268
|
+
<button
|
|
269
|
+
type="button"
|
|
270
|
+
onClick={() => {
|
|
271
|
+
const already = peek?.line === i;
|
|
272
|
+
setPeek(already ? null : { line: i, nodeId: line.nodeId! });
|
|
273
|
+
if (!already) selectNode(line.nodeId!);
|
|
274
|
+
}}
|
|
275
|
+
title="Inspect latest input/output"
|
|
276
|
+
className={cn(
|
|
277
|
+
'w-36 shrink-0 cursor-pointer truncate text-left underline-offset-2 transition-colors',
|
|
278
|
+
peek?.line === i
|
|
279
|
+
? 'text-highlight underline'
|
|
280
|
+
: 'text-foreground/85 hover:text-highlight hover:underline',
|
|
281
|
+
)}
|
|
282
|
+
>
|
|
283
|
+
{line.nodeLabel ?? line.nodeId}
|
|
284
|
+
</button>
|
|
285
|
+
) : (
|
|
286
|
+
<span className="w-36 shrink-0 truncate text-foreground/85">{line.nodeLabel ?? '—'}</span>
|
|
287
|
+
)}
|
|
288
|
+
<LogMessage message={line.message} defaultOpen={openByDefault} />
|
|
289
|
+
</div>
|
|
290
|
+
))}
|
|
291
|
+
<div ref={logEndRef} />
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<div
|
|
298
|
+
className={cn(
|
|
299
|
+
'flex h-full min-h-0 flex-col bg-card/60',
|
|
300
|
+
consolePosition === 'bottom' ? 'border-t border-border' : 'border-l border-border',
|
|
301
|
+
)}
|
|
302
|
+
>
|
|
303
|
+
<header className="relative flex h-11 shrink-0 items-center gap-2.5 border-b border-border/70 px-3.5">
|
|
304
|
+
<span className={cn('size-2 rounded-full', statusDot[run?.status ?? 'running'])} />
|
|
305
|
+
<span className="min-w-0 truncate text-[12.5px] font-medium">{flowName}</span>
|
|
306
|
+
{run?.environment && (
|
|
307
|
+
<Badge variant="outline" className="shrink-0 text-[9px] uppercase">
|
|
308
|
+
{run.environment}
|
|
309
|
+
</Badge>
|
|
310
|
+
)}
|
|
311
|
+
{run?.safeMode && <ShieldIcon className="size-3 shrink-0 text-muted-foreground" />}
|
|
312
|
+
<span className="ml-auto shrink-0 font-mono text-[11px] tabular-nums text-muted-foreground">{elapsedText}</span>
|
|
313
|
+
<div className="flex shrink-0 items-center gap-0.5 border-l border-border/70 pl-1.5">
|
|
314
|
+
<Button
|
|
315
|
+
variant="ghost"
|
|
316
|
+
size="icon"
|
|
317
|
+
className={cn(
|
|
318
|
+
'size-6 text-muted-foreground hover:text-foreground',
|
|
319
|
+
consolePosition === 'right' && 'bg-secondary/60 text-foreground',
|
|
320
|
+
)}
|
|
321
|
+
onClick={() => setConsolePosition('right')}
|
|
322
|
+
aria-label="Dock right"
|
|
323
|
+
aria-pressed={consolePosition === 'right'}
|
|
324
|
+
title="Dock right"
|
|
325
|
+
>
|
|
326
|
+
<PanelRightIcon className="size-3.5" />
|
|
327
|
+
</Button>
|
|
328
|
+
<Button
|
|
329
|
+
variant="ghost"
|
|
330
|
+
size="icon"
|
|
331
|
+
className={cn(
|
|
332
|
+
'size-6 text-muted-foreground hover:text-foreground',
|
|
333
|
+
consolePosition === 'bottom' && 'bg-secondary/60 text-foreground',
|
|
334
|
+
)}
|
|
335
|
+
onClick={() => setConsolePosition('bottom')}
|
|
336
|
+
aria-label="Dock bottom"
|
|
337
|
+
aria-pressed={consolePosition === 'bottom'}
|
|
338
|
+
title="Dock bottom"
|
|
339
|
+
>
|
|
340
|
+
<PanelBottomIcon className="size-3.5" />
|
|
341
|
+
</Button>
|
|
342
|
+
</div>
|
|
343
|
+
<Button
|
|
344
|
+
variant="ghost"
|
|
345
|
+
size="icon"
|
|
346
|
+
className="size-6 shrink-0 text-muted-foreground hover:text-foreground"
|
|
347
|
+
onClick={onDismiss}
|
|
348
|
+
aria-label="Dismiss run console"
|
|
349
|
+
>
|
|
350
|
+
<XIcon className="size-3.5" />
|
|
351
|
+
</Button>
|
|
352
|
+
{/* Run progress underlining the header — completes and quietly fades. */}
|
|
353
|
+
<div className="absolute inset-x-0 bottom-0 h-px overflow-visible">
|
|
354
|
+
<div
|
|
355
|
+
className={cn(
|
|
356
|
+
'h-[2px] rounded-full transition-[width,opacity] duration-500 ease-out',
|
|
357
|
+
run?.status === 'failed' ? 'bg-destructive/80' : 'bg-highlight/80',
|
|
358
|
+
finished && run?.status !== 'failed' && 'opacity-0',
|
|
359
|
+
)}
|
|
360
|
+
style={{ width: `${Math.round((settled / total) * 100)}%` }}
|
|
361
|
+
/>
|
|
362
|
+
</div>
|
|
363
|
+
</header>
|
|
364
|
+
{peek ? (
|
|
365
|
+
<ResizablePanelGroup direction="vertical" className="min-h-0 flex-1" autoSaveId="emberflow-run-detail">
|
|
366
|
+
<ResizablePanel id="run-logs" order={1} defaultSize={55} minSize={25}>
|
|
367
|
+
{logList}
|
|
368
|
+
</ResizablePanel>
|
|
369
|
+
<ResizableHandle />
|
|
370
|
+
<ResizablePanel id="run-node" order={2} defaultSize={45} minSize={25}>
|
|
371
|
+
<NodeDetail
|
|
372
|
+
label={peekNode?.label ?? peek.nodeId}
|
|
373
|
+
typeName={peekNode?.type}
|
|
374
|
+
state={run?.nodeStates[peek.nodeId]}
|
|
375
|
+
onClose={() => setPeek(null)}
|
|
376
|
+
register={register}
|
|
377
|
+
/>
|
|
378
|
+
</ResizablePanel>
|
|
379
|
+
</ResizablePanelGroup>
|
|
380
|
+
) : (
|
|
381
|
+
logList
|
|
382
|
+
)}
|
|
383
|
+
{finished && (
|
|
384
|
+
<footer className="flex shrink-0 items-center gap-2 border-t border-border/70 px-3.5 py-2">
|
|
385
|
+
<span className={cn('size-1.5 rounded-full', statusDot[run.status])} />
|
|
386
|
+
<span className="text-[12px] capitalize text-foreground/90">{run.status}</span>
|
|
387
|
+
<span className="text-[11px] text-muted-foreground">
|
|
388
|
+
· {settled}/{total} nodes{errorCount > 0 ? ` · ${errorCount} failed` : ''}
|
|
389
|
+
</span>
|
|
390
|
+
<Button variant="secondary" size="sm" className="ml-auto" onClick={onDismiss}>
|
|
391
|
+
Dismiss
|
|
392
|
+
</Button>
|
|
393
|
+
</footer>
|
|
394
|
+
)}
|
|
395
|
+
</div>
|
|
396
|
+
);
|
|
397
|
+
}
|