minimal-agent 0.13.0 → 0.14.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 +6 -5
- package/package.json +60 -4
- package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
- package/plugins/cron-runner/src/commands.js +4 -4
- package/plugins/cron-runner/src/commands.ts +4 -4
- package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
- package/plugins/workflow-runner/commands/workflow.md +57 -90
- package/plugins/workflow-runner/commands/workflows.md +4 -4
- package/plugins/workflow-runner/plugin.js +24 -13
- package/plugins/workflow-runner/plugin.ts +28 -13
- package/plugins/workflow-runner/src/discovery.js +160 -0
- package/plugins/workflow-runner/src/discovery.ts +194 -0
- package/plugins/workflow-runner/src/goalAnchor.js +53 -0
- package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
- package/plugins/workflow-runner/src/index.js +197 -206
- package/plugins/workflow-runner/src/index.ts +248 -249
- package/plugins/workflow-runner/src/inputCoercion.js +40 -0
- package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
- package/plugins/workflow-runner/src/journal.js +224 -0
- package/plugins/workflow-runner/src/journal.ts +274 -0
- package/plugins/workflow-runner/src/jsonSchema.js +132 -0
- package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
- package/plugins/workflow-runner/src/moduleResolution.js +64 -0
- package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
- package/plugins/workflow-runner/src/resourceInputs.js +220 -0
- package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
- package/plugins/workflow-runner/src/runner.js +400 -489
- package/plugins/workflow-runner/src/runner.ts +488 -560
- package/plugins/workflow-runner/src/runtime/config.js +46 -0
- package/plugins/workflow-runner/src/runtime/config.ts +69 -0
- package/plugins/workflow-runner/src/runtime/context.js +1304 -0
- package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
- package/plugins/workflow-runner/src/runtime/exec.js +34 -0
- package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
- package/plugins/workflow-runner/src/runtime/flow.js +8 -0
- package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
- package/plugins/workflow-runner/src/runtime/fs.js +27 -0
- package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
- package/plugins/workflow-runner/src/runtime/model.js +6 -0
- package/plugins/workflow-runner/src/runtime/model.ts +8 -0
- package/plugins/workflow-runner/src/runtime/output.js +7 -0
- package/plugins/workflow-runner/src/runtime/output.ts +21 -0
- package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
- package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
- package/plugins/workflow-runner/src/runtime/state.js +16 -0
- package/plugins/workflow-runner/src/runtime/state.ts +19 -0
- package/plugins/workflow-runner/src/runtime/tools.js +3 -0
- package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
- package/plugins/workflow-runner/src/sandbox.js +141 -0
- package/plugins/workflow-runner/src/sandbox.ts +182 -0
- package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
- package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
- package/plugins/workflow-runner/src/taskIdentity.js +151 -307
- package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
- package/plugins/workflow-runner/src/toolRuntime.js +29 -8
- package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
- package/plugins/workflow-runner/src/types.js +7 -211
- package/plugins/workflow-runner/src/types.ts +154 -623
- package/plugins/workflow-runner/src/util.js +47 -0
- package/plugins/workflow-runner/src/util.ts +51 -0
- package/plugins/workflow-runner/src/workflowContext.js +20 -0
- package/plugins/workflow-runner/src/workflowContext.ts +58 -0
- package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
- package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
- package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
- package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
- package/plugins/workflow-runner/src/workflowState.js +474 -802
- package/plugins/workflow-runner/src/workflowState.ts +575 -970
- package/plugins/workflow-runner/test/api.test.ts +223 -0
- package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
- package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
- package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
- package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
- package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
- package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
- package/plugins/workflow-runner/test/discovery.test.ts +234 -0
- package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
- package/plugins/workflow-runner/test/goalController.test.ts +317 -0
- package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
- package/plugins/workflow-runner/test/listResources.test.ts +106 -0
- package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
- package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
- package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
- package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
- package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
- package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
- package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
- package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
- package/skills/pptx/examples/assets/cover-bg.svg +23 -0
- package/skills/pptx/examples/assets/icon-spark.svg +5 -0
- package/skills/ui-design/SKILL.md +5 -2
- package/skills/ui-design/references/layout-composition.md +1 -1
- package/skills/workflow-creator/SKILL.md +344 -0
- package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
- package/skills/workflow-creator/references/api.md +216 -0
- package/skills/workflow-creator/references/migration.md +103 -0
- package/skills/workflow-creator/references/patterns.md +779 -0
- package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
- package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
- package/skills/workflow-creator/scripts/validate.mjs +275 -0
- package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
- package/src/advisor/advisorCoordinator.js +503 -0
- package/src/advisor/advisorCoordinator.ts +657 -0
- package/src/cli/configMenu.tsx +0 -1
- package/src/cli/print.js +27 -6
- package/src/cli/print.ts +48 -4
- package/src/cli/streamJson.js +5 -6
- package/src/cli/streamJson.ts +8 -4
- package/src/cli/wizards/advisorWizard.js +4 -2
- package/src/cli/wizards/advisorWizard.tsx +8 -2
- package/src/cli/wizards/contextAdvisorWizard.js +5 -4
- package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
- package/src/collaboration/taskFlow.js +115 -0
- package/src/collaboration/taskFlow.ts +169 -0
- package/src/config/configDefaults.js +41 -1
- package/src/config/configDefaults.ts +43 -1
- package/src/config/configDiagnostics.ts +2 -2
- package/src/config/configFile.js +40 -9
- package/src/config/configFile.ts +60 -11
- package/src/config/configService.js +419 -74
- package/src/config/configService.ts +703 -145
- package/src/config/numericLimits.js +22 -0
- package/src/config/numericLimits.ts +24 -0
- package/src/config.js +1 -0
- package/src/config.ts +3 -2
- package/src/context/budgetPlan.js +1 -1
- package/src/context/budgetPlan.ts +1 -1
- package/src/context/compact.js +7 -2
- package/src/context/compact.ts +9 -2
- package/src/context/microCompactLite.js +212 -13
- package/src/context/microCompactLite.ts +261 -12
- package/src/context/sessionRegistry.js +8 -1
- package/src/context/sessionRegistry.ts +18 -5
- package/src/context/toolResultArchive.js +72 -0
- package/src/context/toolResultArchive.ts +95 -0
- package/src/goal/errors.js +8 -0
- package/src/goal/errors.ts +18 -0
- package/src/goal/goalRuntime.js +344 -0
- package/src/goal/goalRuntime.ts +466 -0
- package/src/goal/goalStore.js +200 -0
- package/src/goal/goalStore.ts +219 -0
- package/src/goal/index.js +4 -0
- package/src/goal/index.ts +4 -0
- package/src/goal/statusMapping.js +71 -0
- package/src/goal/statusMapping.ts +95 -0
- package/src/goal/types.js +7 -0
- package/src/goal/types.ts +179 -0
- package/src/goal/workflowController.js +306 -0
- package/src/goal/workflowController.ts +360 -0
- package/src/harness/evidenceLedger.js +2 -0
- package/src/harness/evidenceLedger.ts +1 -0
- package/src/harness/stallGuard.js +9 -3
- package/src/harness/stallGuard.ts +7 -3
- package/src/images/imageResolver.js +161 -0
- package/src/images/imageResolver.ts +189 -0
- package/src/infra/verification.js +34 -5
- package/src/infra/verification.ts +39 -4
- package/src/llm/client.js +79 -21
- package/src/llm/client.ts +182 -35
- package/src/llm/gatewayClient.js +201 -0
- package/src/llm/gatewayClient.ts +299 -0
- package/src/llm/messageProvenance.js +46 -0
- package/src/llm/messageProvenance.ts +58 -0
- package/src/llm/modelProvider.js +1 -0
- package/src/llm/modelProvider.ts +22 -0
- package/src/llm/providers/anthropicFormat.js +108 -1
- package/src/llm/providers/anthropicFormat.ts +115 -4
- package/src/llm/providers/openaiFormat.js +9 -0
- package/src/llm/providers/openaiFormat.ts +12 -3
- package/src/loop.js +319 -54
- package/src/loop.ts +373 -57
- package/src/main.js +4 -1
- package/src/main.tsx +4 -1
- package/src/managedExecution/index.js +2 -0
- package/src/managedExecution/index.ts +2 -0
- package/src/managedExecution/registry.js +15 -0
- package/src/managedExecution/registry.ts +20 -0
- package/src/managedExecution/types.js +1 -0
- package/src/managedExecution/types.ts +86 -0
- package/src/modelRef.js +9 -0
- package/src/modelRef.ts +31 -0
- package/src/multimodal.js +14 -28
- package/src/multimodal.ts +17 -33
- package/src/net/lanDiscovery.js +65 -0
- package/src/net/lanDiscovery.ts +82 -0
- package/src/plugin-sdk.js +28 -3
- package/src/plugin-sdk.ts +39 -6
- package/src/plugins/pluginApi.ts +16 -1
- package/src/plugins/pluginLoader.js +4 -0
- package/src/plugins/pluginLoader.ts +6 -0
- package/src/plugins/pluginRunner.js +139 -7
- package/src/plugins/pluginRunner.ts +173 -9
- package/src/plugins/slashFallback.js +113 -0
- package/src/plugins/slashFallback.ts +137 -0
- package/src/prompts/policyRegistry.js +12 -32
- package/src/prompts/policyRegistry.ts +15 -32
- package/src/prompts/promptAssembly.js +103 -12
- package/src/prompts/promptAssembly.ts +114 -12
- package/src/prompts/skillList.js +21 -3
- package/src/prompts/skillList.ts +27 -2
- package/src/prompts/stableSystemPrompt.js +18 -0
- package/src/prompts/stableSystemPrompt.ts +33 -0
- package/src/runtime/agentRuntimeContext.js +8 -2
- package/src/runtime/agentRuntimeContext.ts +17 -4
- package/src/session/runAgentTurn.js +78 -12
- package/src/session/runAgentTurn.ts +105 -23
- package/src/session/runTurn.js +10 -9
- package/src/session/runTurn.ts +17 -8
- package/src/session/sessionState.ts +2 -0
- package/src/team/auth.js +186 -0
- package/src/team/auth.ts +298 -0
- package/src/team/cli.js +105 -0
- package/src/team/cli.ts +122 -0
- package/src/team/onlineToolContract.js +64 -0
- package/src/team/onlineToolContract.ts +109 -0
- package/src/team/toolPolicy.js +36 -0
- package/src/team/toolPolicy.ts +75 -0
- package/src/tools/advisor/advisor.js +90 -46
- package/src/tools/advisor/advisor.ts +100 -47
- package/src/tools/advisor/advisorDecision.js +71 -0
- package/src/tools/advisor/advisorDecision.ts +85 -0
- package/src/tools/agent/agent.js +18 -5
- package/src/tools/agent/agent.ts +21 -7
- package/src/tools/agent/agentControl.js +246 -0
- package/src/tools/agent/agentControl.ts +284 -0
- package/src/tools/agent/agentTaskService.js +40 -1
- package/src/tools/agent/agentTaskService.ts +44 -1
- package/src/tools/agent/agentTypes.js +14 -2
- package/src/tools/agent/agentTypes.ts +15 -2
- package/src/tools/applypatch/applyPatch.js +362 -0
- package/src/tools/applypatch/applyPatch.ts +428 -0
- package/src/tools/bash/bash.js +22 -15
- package/src/tools/bash/bash.ts +23 -17
- package/src/tools/capabilities.js +10 -5
- package/src/tools/capabilities.ts +10 -5
- package/src/tools/computeruse/computerIntent.js +32 -0
- package/src/tools/computeruse/computerIntent.ts +46 -0
- package/src/tools/computeruse/telemetryLog.js +12 -0
- package/src/tools/computeruse/telemetryLog.ts +16 -0
- package/src/tools/computeruse/vision/telemetry.js +1 -0
- package/src/tools/computeruse/vision/telemetry.ts +1 -0
- package/src/tools/effectiveToolSet.js +4 -0
- package/src/tools/effectiveToolSet.ts +4 -0
- package/src/tools/index.js +21 -2
- package/src/tools/index.ts +33 -2
- package/src/tools/presentresult/presentresult.js +6 -15
- package/src/tools/presentresult/presentresult.ts +6 -15
- package/src/tools/read/read.js +62 -9
- package/src/tools/read/read.ts +63 -9
- package/src/tools/shared/fileUtils.js +1 -2
- package/src/tools/shared/fileUtils.ts +1 -2
- package/src/tools/shared/toolOutputStore.js +23 -1
- package/src/tools/shared/toolOutputStore.ts +22 -1
- package/src/tools/skill/skill.js +9 -3
- package/src/tools/skill/skill.ts +8 -4
- package/src/tools/toolPromptGuides.js +117 -0
- package/src/tools/toolPromptGuides.ts +137 -0
- package/src/tools/webbrowser/agentBrowserPath.js +19 -9
- package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
- package/src/tools/webbrowser/browser.js +27 -11
- package/src/tools/webbrowser/browser.ts +68 -24
- package/src/tools/webbrowser/browserAutomation.js +329 -0
- package/src/tools/webbrowser/browserAutomation.ts +467 -0
- package/src/tools/webbrowser/browserAxState.js +97 -0
- package/src/tools/webbrowser/browserAxState.ts +142 -0
- package/src/tools/webbrowser/browserBatch.js +1578 -0
- package/src/tools/webbrowser/browserBatch.ts +2382 -0
- package/src/tools/webbrowser/browserCdp.js +208 -0
- package/src/tools/webbrowser/browserCdp.ts +255 -0
- package/src/tools/webbrowser/browserConditions.js +24 -0
- package/src/tools/webbrowser/browserConditions.ts +45 -0
- package/src/tools/webbrowser/browserContent.js +281 -0
- package/src/tools/webbrowser/browserContent.ts +438 -0
- package/src/tools/webbrowser/browserControl.js +131 -34
- package/src/tools/webbrowser/browserControl.ts +210 -56
- package/src/tools/webbrowser/browserDaemon.js +22 -14
- package/src/tools/webbrowser/browserDaemon.ts +54 -21
- package/src/tools/webbrowser/browserFrames.js +47 -0
- package/src/tools/webbrowser/browserFrames.ts +54 -0
- package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
- package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
- package/src/tools/webbrowser/browserLocator.js +140 -0
- package/src/tools/webbrowser/browserLocator.ts +194 -0
- package/src/tools/webbrowser/browserOutcome.js +10 -17
- package/src/tools/webbrowser/browserOutcome.ts +48 -31
- package/src/tools/webbrowser/browserRecovery.js +58 -0
- package/src/tools/webbrowser/browserRecovery.ts +83 -0
- package/src/tools/webbrowser/browserRunRegistry.js +35 -3
- package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
- package/src/tools/webbrowser/browserService.js +28 -2
- package/src/tools/webbrowser/browserService.ts +49 -9
- package/src/tools/webbrowser/browserStream.js +132 -33
- package/src/tools/webbrowser/browserStream.ts +224 -50
- package/src/tools/webbrowser/browserTabs.js +48 -15
- package/src/tools/webbrowser/browserTabs.ts +178 -96
- package/src/tools/webbrowser/webbrowser.js +679 -144
- package/src/tools/webbrowser/webbrowser.ts +975 -236
- package/src/tools/webfetch/preapproved.js +0 -2
- package/src/tools/webfetch/preapproved.ts +0 -2
- package/src/tools/websearch/websearch.js +129 -8
- package/src/tools/websearch/websearch.ts +138 -6
- package/src/types.ts +440 -38
- package/src/ui/App.js +377 -58
- package/src/ui/App.tsx +576 -111
- package/src/ui/LiveArea.js +14 -8
- package/src/ui/LiveArea.tsx +14 -10
- package/src/ui/MessageList.js +63 -20
- package/src/ui/MessageList.tsx +101 -16
- package/src/ui/ModelPicker.js +7 -4
- package/src/ui/ModelPicker.tsx +55 -8
- package/src/ui/hooks/useChat.js +152 -163
- package/src/ui/hooks/useChat.ts +396 -334
- package/src/ui/loginCommand.js +56 -0
- package/src/ui/loginCommand.ts +63 -0
- package/src/ui/toolProgress.js +41 -0
- package/src/ui/toolProgress.ts +44 -0
- package/src/web/browserBridge.js +20 -2
- package/src/web/browserBridge.ts +20 -2
- package/src/web/protocol.ts +1897 -194
- package/workflows/adaptive-research/workflow.mjs +86 -0
- package/workflows/e2e-capabilities/workflow.mjs +102 -0
- package/workflows/e2e-llm/workflow.mjs +52 -0
- package/workflows/e2e-smoke/workflow.mjs +59 -0
- package/workflows/e2e-vision-schema/README.md +48 -0
- package/workflows/e2e-vision-schema/workflow.mjs +149 -0
- package/workflows/e2e-write-greet/workflow.mjs +37 -0
- package/workflows/file-census/README.md +14 -0
- package/workflows/file-census/scripts/.gitkeep +2 -0
- package/workflows/file-census/workflow.mjs +110 -0
- package/workflows/goal/README.md +166 -0
- package/workflows/goal/prompts/audit.md +57 -0
- package/workflows/goal/prompts/contract.md +56 -0
- package/workflows/goal/prompts/iterate.md +37 -0
- package/workflows/goal/workflow.mjs +501 -0
- package/workflows/illustrate/README.md +90 -0
- package/workflows/illustrate/assets/engines.json +20 -0
- package/workflows/illustrate/assets/extract-baidu.js +21 -0
- package/workflows/illustrate/assets/extract-bing.js +33 -0
- package/workflows/illustrate/assets/extract-google.js +31 -0
- package/workflows/illustrate/workflow.mjs +301 -0
- package/workflows/plan/workflow.mjs +389 -0
- package/workflows/question-crops/README.md +35 -0
- package/workflows/question-crops/prompts/inventory.md +23 -0
- package/workflows/question-crops/scripts/image-ops.mjs +305 -0
- package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
- package/workflows/question-crops/workflow.mjs +172 -0
- package/workflows/ralph-loop/workflow.mjs +162 -0
- package/workflows/research/README.md +74 -0
- package/workflows/research/prompts/s0-goal.md +43 -0
- package/workflows/research/prompts/s1-early-exit.md +22 -0
- package/workflows/research/prompts/s1-map.md +58 -0
- package/workflows/research/prompts/s2-options.md +53 -0
- package/workflows/research/prompts/s3-deep-dive.md +56 -0
- package/workflows/research/prompts/s4-verify.md +74 -0
- package/workflows/research/prompts/s5-synthesis.md +81 -0
- package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
- package/workflows/research/prompts/s6-package.md +32 -0
- package/workflows/research/scripts/build-report.mjs +98 -0
- package/workflows/research/workflow.mjs +288 -0
- package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
- package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
- package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
- package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
- package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
- package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
- package/workflows/wechat-reading-shots/workflow.mjs +266 -0
- package/workflows/wrong-question-docx/README.md +55 -0
- package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
- package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
- package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
- package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
- package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
- package/workflows/wrong-question-docx/workflow.mjs +485 -0
- package/plugins/workflow-runner/src/agentCommon.js +0 -354
- package/plugins/workflow-runner/src/agentCommon.ts +0 -435
- package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
- package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
- package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
- package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
- package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
- package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
- package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
- package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
- package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
- package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
- package/plugins/workflow-runner/src/dslManifest.js +0 -72
- package/plugins/workflow-runner/src/dslManifest.ts +0 -127
- package/plugins/workflow-runner/src/expressions.js +0 -639
- package/plugins/workflow-runner/src/expressions.ts +0 -640
- package/plugins/workflow-runner/src/loader.js +0 -573
- package/plugins/workflow-runner/src/loader.ts +0 -721
- package/plugins/workflow-runner/src/multimodal.js +0 -38
- package/plugins/workflow-runner/src/multimodal.ts +0 -64
- package/plugins/workflow-runner/src/recovery.js +0 -126
- package/plugins/workflow-runner/src/recovery.ts +0 -156
- package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
- package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
- package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
- package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
- package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
- package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
- package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
- package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
- package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
- package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
- package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
- package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
- package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
- package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
- package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
- package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
- package/plugins/workflow-runner/src/stepPipeline.js +0 -277
- package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
- package/plugins/workflow-runner/test/agent.test.ts +0 -587
- package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
- package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
- package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
- package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
- package/plugins/workflow-runner/test/context-files.test.ts +0 -320
- package/plugins/workflow-runner/test/e2e.test.ts +0 -370
- package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
- package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
- package/plugins/workflow-runner/test/expressions.test.ts +0 -439
- package/plugins/workflow-runner/test/foundation.test.ts +0 -126
- package/plugins/workflow-runner/test/graceful.test.ts +0 -139
- package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
- package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
- package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
- package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
- package/plugins/workflow-runner/test/loader.test.ts +0 -617
- package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
- package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
- package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
- package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
- package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
- package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
- package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
- package/plugins/workflow-runner/test/recovery.test.ts +0 -265
- package/plugins/workflow-runner/test/research.load.test.ts +0 -328
- package/plugins/workflow-runner/test/runner.test.ts +0 -911
- package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
- package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
- package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
- package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
- package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
- package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
- package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
- package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
- package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
- package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
- package/plugins/workflow-runner/test/word.load.test.ts +0 -208
- package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
- package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
- package/src/advisorState.js +0 -22
- package/src/cli/configWizard.js +0 -293
- package/src/tools/toolProgressBridge.js +0 -48
- package/workflows/adaptive-research.yaml +0 -50
- package/workflows/book-review-short.yaml +0 -125
- package/workflows/e2e-write-greet.yaml +0 -31
- package/workflows/illustrate.yaml +0 -227
- package/workflows/plan.yaml +0 -470
- package/workflows/ppt.yaml +0 -1670
- package/workflows/ralph-loop.yaml +0 -201
- package/workflows/research.yaml +0 -873
- package/workflows/schema.json +0 -176
- package/workflows/webppt.yaml +0 -496
- package/workflows/wechat-reading-shots.yaml +0 -315
- package/workflows/word.yaml +0 -720
- package/workflows/youtube-shorts.yaml +0 -202
- /package/workflows/{research.md → research/DESIGN.md} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { dirname, isAbsolute } from 'node:path';
|
|
3
|
-
import { resolveAgentBrowserPath, resolveBundledChromium, resolveSystemBrowser } from './agentBrowserPath.js';
|
|
3
|
+
import { resolveAgentBrowserPath, resolveBundledChromium, resolveSystemBrowser, } from './agentBrowserPath.js';
|
|
4
4
|
import { browserGlobalArgs, runBounded, sessionArgs, spawnRunner, } from './browser.js';
|
|
5
5
|
/** Daemon 启动(拉起 Chrome + CDP 就绪)总预算:超时即掐断并抛可操作错误,绝不无限挂。 */
|
|
6
6
|
export const DAEMON_BRINGUP_TIMEOUT_MS = 45_000;
|
|
@@ -50,17 +50,7 @@ export async function reclaimStaleDaemons(deps = {}) {
|
|
|
50
50
|
const root = dir.toLowerCase().replace(/'/g, "''");
|
|
51
51
|
const ps =
|
|
52
52
|
// (a) 本 App 路径下的 agent-browser daemon + 其 Chrome 子树。
|
|
53
|
-
`Get-CimInstance Win32_Process -Filter "Name='agent-browser.exe'" |
|
|
54
|
-
`Where-Object { $_.ExecutablePath -and $_.ExecutablePath.ToLower().StartsWith('${root}') } | ` +
|
|
55
|
-
`ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }; ` +
|
|
56
|
-
// (b) 真孤儿 agent-browser Chrome(父进程已死)。daemon 崩溃后残留、上面的 agent-browser 树
|
|
57
|
-
// 够不着,堆积起来会把新 daemon 的 Chrome 拉起拖到几十秒(实测 18 棵孤儿 → 卡 43s;
|
|
58
|
-
// 清空后同一启动仅 1s)。**只杀父进程已不在的孤儿**,绝不误伤有活父进程的正常浏览器
|
|
59
|
-
// (安装版 App 的活浏览器父 agent-browser 健在 → 不匹配,天然豁免)。
|
|
60
|
-
`$alive=@{}; Get-CimInstance Win32_Process | ForEach-Object { $alive[[int]$_.ProcessId]=$true }; ` +
|
|
61
|
-
`Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | ` +
|
|
62
|
-
`Where-Object { ($_.CommandLine -match 'agent-browser-chrome' -or $_.CommandLine -match '\\.minimal-agent.{0,40}profiles') -and -not $alive.ContainsKey([int]$_.ParentProcessId) } | ` +
|
|
63
|
-
`ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }`;
|
|
53
|
+
`Get-CimInstance Win32_Process -Filter "Name='agent-browser.exe'" | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.ToLower().StartsWith('${root}') } | ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }; $alive=@{}; Get-CimInstance Win32_Process | ForEach-Object { $alive[[int]$_.ProcessId]=$true }; Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | Where-Object { ($_.CommandLine -match 'agent-browser-chrome' -or $_.CommandLine -match '\\.minimal-agent.{0,40}profiles') -and -not $alive.ContainsKey([int]$_.ParentProcessId) } | ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }`;
|
|
64
54
|
await exec('powershell', ['-NoProfile', '-NonInteractive', '-Command', ps]);
|
|
65
55
|
}
|
|
66
56
|
else {
|
|
@@ -94,6 +84,17 @@ export async function ensureDaemon(sessionName = 'minimal-agent', opts = {}, dep
|
|
|
94
84
|
const bin = await deps.resolveBin();
|
|
95
85
|
if (!bin)
|
|
96
86
|
throw new Error('未找到 agent-browser 可执行文件');
|
|
87
|
+
if (opts.forceRestart) {
|
|
88
|
+
// The shipped wrapper may launch a daemon from a different resolved
|
|
89
|
+
// global path. In that case executable-prefix process cleanup is
|
|
90
|
+
// intentionally conservative and cannot see the daemon. Ask the
|
|
91
|
+
// session manager to close its own browser first, then apply the scoped
|
|
92
|
+
// process cleanup as a second line of defense.
|
|
93
|
+
await deps
|
|
94
|
+
.runner(bin, [...sessionArgs(sessionName), 'close', '--all'], opts.signal)
|
|
95
|
+
.catch(() => undefined);
|
|
96
|
+
await reclaimStaleDaemons(opts.reclaim);
|
|
97
|
+
}
|
|
97
98
|
const status = await readStatus(bin, sessionName, { signal: opts.signal }, deps);
|
|
98
99
|
if (status.port && status.connected) {
|
|
99
100
|
ports.set(sessionName, status.port);
|
|
@@ -143,10 +144,17 @@ export async function ensureDaemon(sessionName = 'minimal-agent', opts = {}, dep
|
|
|
143
144
|
]);
|
|
144
145
|
if (ac.signal.aborted)
|
|
145
146
|
throw bringUpError();
|
|
146
|
-
if (opened.code !== 0 &&
|
|
147
|
+
if (opened.code !== 0 &&
|
|
148
|
+
browserRuntimeMissing(`${opened.stderr}\n${opened.stdout}`)) {
|
|
147
149
|
const chromium = resolveBundledChromium();
|
|
148
150
|
if (chromium) {
|
|
149
|
-
opened = await run([
|
|
151
|
+
opened = await run([
|
|
152
|
+
...globals,
|
|
153
|
+
'--executable-path',
|
|
154
|
+
chromium,
|
|
155
|
+
'open',
|
|
156
|
+
'about:blank',
|
|
157
|
+
]);
|
|
150
158
|
}
|
|
151
159
|
else {
|
|
152
160
|
const installed = await run(['install']);
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
2
|
import { dirname, isAbsolute } from 'node:path';
|
|
3
3
|
|
|
4
|
-
import { resolveAgentBrowserPath, resolveBundledChromium, resolveSystemBrowser } from './agentBrowserPath.js';
|
|
5
4
|
import {
|
|
5
|
+
resolveAgentBrowserPath,
|
|
6
|
+
resolveBundledChromium,
|
|
7
|
+
resolveSystemBrowser,
|
|
8
|
+
} from './agentBrowserPath.js';
|
|
9
|
+
import {
|
|
10
|
+
type AgentBrowserRunner,
|
|
6
11
|
browserGlobalArgs,
|
|
7
12
|
runBounded,
|
|
8
13
|
sessionArgs,
|
|
9
14
|
spawnRunner,
|
|
10
|
-
type AgentBrowserRunner,
|
|
11
15
|
} from './browser.js';
|
|
12
16
|
|
|
13
17
|
export interface BrowserDaemonInfo {
|
|
@@ -30,6 +34,8 @@ export interface EnsureDaemonOptions {
|
|
|
30
34
|
signal?: AbortSignal;
|
|
31
35
|
timeoutMs?: number;
|
|
32
36
|
reclaim?: ReclaimDeps;
|
|
37
|
+
/** Forcefully rebuild a browser whose CDP endpoint has gone stale. */
|
|
38
|
+
forceRestart?: boolean;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
/**
|
|
@@ -78,7 +84,9 @@ export interface ReclaimDeps {
|
|
|
78
84
|
* 或系统上别处的 agent-browser 用法(对标 scripts/dev-browser.ts::reclaimStalePort)。无法作用域限定
|
|
79
85
|
* (PATH 上裸二进制 / 没装)时保守放弃,不做全局杀。幂等、best-effort(失败静默)。
|
|
80
86
|
*/
|
|
81
|
-
export async function reclaimStaleDaemons(
|
|
87
|
+
export async function reclaimStaleDaemons(
|
|
88
|
+
deps: ReclaimDeps = {},
|
|
89
|
+
): Promise<void> {
|
|
82
90
|
const platform = deps.platform ?? process.platform;
|
|
83
91
|
const exec = deps.exec ?? realReclaimExec;
|
|
84
92
|
const resolveDir =
|
|
@@ -94,17 +102,7 @@ export async function reclaimStaleDaemons(deps: ReclaimDeps = {}): Promise<void>
|
|
|
94
102
|
const root = dir.toLowerCase().replace(/'/g, "''");
|
|
95
103
|
const ps =
|
|
96
104
|
// (a) 本 App 路径下的 agent-browser daemon + 其 Chrome 子树。
|
|
97
|
-
`Get-CimInstance Win32_Process -Filter "Name='agent-browser.exe'" |
|
|
98
|
-
`Where-Object { $_.ExecutablePath -and $_.ExecutablePath.ToLower().StartsWith('${root}') } | ` +
|
|
99
|
-
`ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }; ` +
|
|
100
|
-
// (b) 真孤儿 agent-browser Chrome(父进程已死)。daemon 崩溃后残留、上面的 agent-browser 树
|
|
101
|
-
// 够不着,堆积起来会把新 daemon 的 Chrome 拉起拖到几十秒(实测 18 棵孤儿 → 卡 43s;
|
|
102
|
-
// 清空后同一启动仅 1s)。**只杀父进程已不在的孤儿**,绝不误伤有活父进程的正常浏览器
|
|
103
|
-
// (安装版 App 的活浏览器父 agent-browser 健在 → 不匹配,天然豁免)。
|
|
104
|
-
`$alive=@{}; Get-CimInstance Win32_Process | ForEach-Object { $alive[[int]$_.ProcessId]=$true }; ` +
|
|
105
|
-
`Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | ` +
|
|
106
|
-
`Where-Object { ($_.CommandLine -match 'agent-browser-chrome' -or $_.CommandLine -match '\\.minimal-agent.{0,40}profiles') -and -not $alive.ContainsKey([int]$_.ParentProcessId) } | ` +
|
|
107
|
-
`ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }`;
|
|
105
|
+
`Get-CimInstance Win32_Process -Filter "Name='agent-browser.exe'" | Where-Object { $_.ExecutablePath -and $_.ExecutablePath.ToLower().StartsWith('${root}') } | ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }; $alive=@{}; Get-CimInstance Win32_Process | ForEach-Object { $alive[[int]$_.ProcessId]=$true }; Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | Where-Object { ($_.CommandLine -match 'agent-browser-chrome' -or $_.CommandLine -match '\\.minimal-agent.{0,40}profiles') -and -not $alive.ContainsKey([int]$_.ParentProcessId) } | ForEach-Object { taskkill /F /T /PID $_.ProcessId 2>$null | Out-Null }`;
|
|
108
106
|
await exec('powershell', ['-NoProfile', '-NonInteractive', '-Command', ps]);
|
|
109
107
|
} else {
|
|
110
108
|
// unix:按可执行路径前缀 pkill agent-browser(其 Chrome 子进程随之收尾)。unix 孤儿会被
|
|
@@ -121,7 +119,9 @@ function parsePort(text: string): number | null {
|
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
function browserRuntimeMissing(text: string): boolean {
|
|
124
|
-
return /browser\s+(?:not found|was not found)|chrom(?:e|ium).*(?:not found|missing)|executable.*(?:not found|does not exist)|run ['\"]?agent-browser install/i.test(
|
|
122
|
+
return /browser\s+(?:not found|was not found)|chrom(?:e|ium).*(?:not found|missing)|executable.*(?:not found|does not exist)|run ['\"]?agent-browser install/i.test(
|
|
123
|
+
text,
|
|
124
|
+
);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
export { browserRuntimeMissing as _browserRuntimeMissing };
|
|
@@ -153,7 +153,23 @@ export async function ensureDaemon(
|
|
|
153
153
|
): Promise<BrowserDaemonInfo> {
|
|
154
154
|
const bin = await deps.resolveBin();
|
|
155
155
|
if (!bin) throw new Error('未找到 agent-browser 可执行文件');
|
|
156
|
-
|
|
156
|
+
if (opts.forceRestart) {
|
|
157
|
+
// The shipped wrapper may launch a daemon from a different resolved
|
|
158
|
+
// global path. In that case executable-prefix process cleanup is
|
|
159
|
+
// intentionally conservative and cannot see the daemon. Ask the
|
|
160
|
+
// session manager to close its own browser first, then apply the scoped
|
|
161
|
+
// process cleanup as a second line of defense.
|
|
162
|
+
await deps
|
|
163
|
+
.runner(bin, [...sessionArgs(sessionName), 'close', '--all'], opts.signal)
|
|
164
|
+
.catch(() => undefined);
|
|
165
|
+
await reclaimStaleDaemons(opts.reclaim);
|
|
166
|
+
}
|
|
167
|
+
const status = await readStatus(
|
|
168
|
+
bin,
|
|
169
|
+
sessionName,
|
|
170
|
+
{ signal: opts.signal },
|
|
171
|
+
deps,
|
|
172
|
+
);
|
|
157
173
|
if (status.port && status.connected) {
|
|
158
174
|
ports.set(sessionName, status.port);
|
|
159
175
|
return { sessionName, streamPort: status.port, alreadyRunning: true };
|
|
@@ -202,18 +218,30 @@ export async function ensureDaemon(
|
|
|
202
218
|
'about:blank',
|
|
203
219
|
]);
|
|
204
220
|
if (ac.signal.aborted) throw bringUpError();
|
|
205
|
-
if (
|
|
221
|
+
if (
|
|
222
|
+
opened.code !== 0 &&
|
|
223
|
+
browserRuntimeMissing(`${opened.stderr}\n${opened.stdout}`)
|
|
224
|
+
) {
|
|
206
225
|
const chromium = resolveBundledChromium();
|
|
207
226
|
if (chromium) {
|
|
208
|
-
opened = await run([
|
|
227
|
+
opened = await run([
|
|
228
|
+
...globals,
|
|
229
|
+
'--executable-path',
|
|
230
|
+
chromium,
|
|
231
|
+
'open',
|
|
232
|
+
'about:blank',
|
|
233
|
+
]);
|
|
209
234
|
} else {
|
|
210
235
|
const installed = await run(['install']);
|
|
211
|
-
if (installed.code === 0)
|
|
236
|
+
if (installed.code === 0)
|
|
237
|
+
opened = await run([...globals, 'open', 'about:blank']);
|
|
212
238
|
}
|
|
213
239
|
if (ac.signal.aborted) throw bringUpError();
|
|
214
240
|
}
|
|
215
241
|
if (opened.code !== 0) {
|
|
216
|
-
throw new Error(
|
|
242
|
+
throw new Error(
|
|
243
|
+
(opened.stderr || opened.stdout || '浏览器启动失败').trim(),
|
|
244
|
+
);
|
|
217
245
|
}
|
|
218
246
|
const streamPort = await waitForStreamPort(sessionName, 10_000, deps);
|
|
219
247
|
ports.set(sessionName, streamPort);
|
|
@@ -235,7 +263,12 @@ export async function stopDaemon(
|
|
|
235
263
|
const bin = await deps.resolveBin();
|
|
236
264
|
ports.delete(sessionName);
|
|
237
265
|
if (bin) {
|
|
238
|
-
await runBounded(
|
|
266
|
+
await runBounded(
|
|
267
|
+
bin,
|
|
268
|
+
[...sessionArgs(sessionName), 'close'],
|
|
269
|
+
{ timeoutMs: STATUS_TIMEOUT_MS },
|
|
270
|
+
deps.runner,
|
|
271
|
+
);
|
|
239
272
|
}
|
|
240
273
|
// 优雅 close 之外再 tree-kill 一遍本 App 路径下的残留:崩溃/close 不彻底时仍杜绝临时 profile
|
|
241
274
|
// 孤儿 Chrome 堆积(实测同时存活 ≥2 棵孤儿 Chrome 树的根因)。
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Fixed, read-only expression for observing nested same-origin frame trees. */
|
|
2
|
+
export const FRAME_INFO_EXPRESSION = `(() => { const walk = (doc, parentId = '', path = '') => Array.from(doc.querySelectorAll('iframe,frame')).flatMap((el, index) => { const id = 'dom-frame-' + (path ? path + '-' : '') + index; const item = { id, ...(parentId ? { parentId } : {}), url: el.src || '', name: el.name || undefined }; try { return [item, ...walk(el.contentDocument, id, id.replace('dom-frame-', ''))]; } catch { return [item]; } }); return walk(document); })()`;
|
|
3
|
+
/** Normalize the recursive, browser-owned frame tree returned by CDP. */
|
|
4
|
+
export function normalizeFrameTree(value) {
|
|
5
|
+
const frames = [];
|
|
6
|
+
const walk = (node, parentId) => {
|
|
7
|
+
if (!node || typeof node !== 'object')
|
|
8
|
+
return;
|
|
9
|
+
const item = node;
|
|
10
|
+
if (typeof item.frame?.id !== 'string' || !item.frame.id)
|
|
11
|
+
return;
|
|
12
|
+
const id = item.frame.id;
|
|
13
|
+
frames.push({
|
|
14
|
+
id,
|
|
15
|
+
...(parentId ? { parentId } : {}),
|
|
16
|
+
url: typeof item.frame.url === 'string' ? item.frame.url : '',
|
|
17
|
+
...(typeof item.frame.name === 'string' && item.frame.name
|
|
18
|
+
? { name: item.frame.name }
|
|
19
|
+
: {}),
|
|
20
|
+
});
|
|
21
|
+
for (const child of item.childFrames ?? [])
|
|
22
|
+
walk(child, id);
|
|
23
|
+
};
|
|
24
|
+
walk(value);
|
|
25
|
+
return frames;
|
|
26
|
+
}
|
|
27
|
+
export function normalizeFrameInfo(value) {
|
|
28
|
+
if (!Array.isArray(value))
|
|
29
|
+
return [];
|
|
30
|
+
return value.flatMap((item) => {
|
|
31
|
+
if (!item || typeof item !== 'object')
|
|
32
|
+
return [];
|
|
33
|
+
const frame = item;
|
|
34
|
+
if (typeof frame.id !== 'string' || typeof frame.url !== 'string')
|
|
35
|
+
return [];
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
id: frame.id,
|
|
39
|
+
url: frame.url,
|
|
40
|
+
...(typeof frame.parentId === 'string'
|
|
41
|
+
? { parentId: frame.parentId }
|
|
42
|
+
: {}),
|
|
43
|
+
...(typeof frame.name === 'string' ? { name: frame.name } : {}),
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
});
|
|
47
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type BrowserFrameInfo = {
|
|
2
|
+
id: string;
|
|
3
|
+
parentId?: string;
|
|
4
|
+
url: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
/** Fixed, read-only expression for observing nested same-origin frame trees. */
|
|
9
|
+
export const FRAME_INFO_EXPRESSION = `(() => { const walk = (doc, parentId = '', path = '') => Array.from(doc.querySelectorAll('iframe,frame')).flatMap((el, index) => { const id = 'dom-frame-' + (path ? path + '-' : '') + index; const item = { id, ...(parentId ? { parentId } : {}), url: el.src || '', name: el.name || undefined }; try { return [item, ...walk(el.contentDocument, id, id.replace('dom-frame-', ''))]; } catch { return [item]; } }); return walk(document); })()`;
|
|
10
|
+
|
|
11
|
+
/** Normalize the recursive, browser-owned frame tree returned by CDP. */
|
|
12
|
+
export function normalizeFrameTree(value: unknown): BrowserFrameInfo[] {
|
|
13
|
+
const frames: BrowserFrameInfo[] = [];
|
|
14
|
+
const walk = (node: unknown, parentId?: string): void => {
|
|
15
|
+
if (!node || typeof node !== 'object') return;
|
|
16
|
+
const item = node as {
|
|
17
|
+
frame?: { id?: unknown; url?: unknown; name?: unknown };
|
|
18
|
+
childFrames?: unknown[];
|
|
19
|
+
};
|
|
20
|
+
if (typeof item.frame?.id !== 'string' || !item.frame.id) return;
|
|
21
|
+
const id = item.frame.id;
|
|
22
|
+
frames.push({
|
|
23
|
+
id,
|
|
24
|
+
...(parentId ? { parentId } : {}),
|
|
25
|
+
url: typeof item.frame.url === 'string' ? item.frame.url : '',
|
|
26
|
+
...(typeof item.frame.name === 'string' && item.frame.name
|
|
27
|
+
? { name: item.frame.name }
|
|
28
|
+
: {}),
|
|
29
|
+
});
|
|
30
|
+
for (const child of item.childFrames ?? []) walk(child, id);
|
|
31
|
+
};
|
|
32
|
+
walk(value);
|
|
33
|
+
return frames;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function normalizeFrameInfo(value: unknown): BrowserFrameInfo[] {
|
|
37
|
+
if (!Array.isArray(value)) return [];
|
|
38
|
+
return value.flatMap((item) => {
|
|
39
|
+
if (!item || typeof item !== 'object') return [];
|
|
40
|
+
const frame = item as Record<string, unknown>;
|
|
41
|
+
if (typeof frame.id !== 'string' || typeof frame.url !== 'string')
|
|
42
|
+
return [];
|
|
43
|
+
return [
|
|
44
|
+
{
|
|
45
|
+
id: frame.id,
|
|
46
|
+
url: frame.url,
|
|
47
|
+
...(typeof frame.parentId === 'string'
|
|
48
|
+
? { parentId: frame.parentId }
|
|
49
|
+
: {}),
|
|
50
|
+
...(typeof frame.name === 'string' ? { name: frame.name } : {}),
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function resolveInteractionStrategy(target) {
|
|
2
|
+
if (target.locator?.by === 'ax')
|
|
3
|
+
return 'ax';
|
|
4
|
+
if (target.locator?.by === 'role' ||
|
|
5
|
+
target.locator?.by === 'label' ||
|
|
6
|
+
target.locator?.by === 'text' ||
|
|
7
|
+
target.locator?.by === 'placeholder' ||
|
|
8
|
+
target.locator?.by === 'testid')
|
|
9
|
+
return 'role-locator';
|
|
10
|
+
if (target.locator || target.selector)
|
|
11
|
+
return 'playwright-locator';
|
|
12
|
+
if (target.node_id !== undefined)
|
|
13
|
+
return 'dom-cua';
|
|
14
|
+
if (target.x !== undefined && target.y !== undefined)
|
|
15
|
+
return 'visual-coordinate';
|
|
16
|
+
return 'cdp';
|
|
17
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deterministic interaction strategy selection shared by batch results and
|
|
3
|
+
* future adapters. MCP/WebMCP is intentionally absent: this project uses the
|
|
4
|
+
* visible supervised browser and falls back through its strongest local
|
|
5
|
+
* representation.
|
|
6
|
+
*/
|
|
7
|
+
export type BrowserInteractionStrategy =
|
|
8
|
+
| 'ax'
|
|
9
|
+
| 'role-locator'
|
|
10
|
+
| 'playwright-locator'
|
|
11
|
+
| 'dom-cua'
|
|
12
|
+
| 'visual-coordinate'
|
|
13
|
+
| 'cdp';
|
|
14
|
+
|
|
15
|
+
export type BrowserInteractionTarget = {
|
|
16
|
+
locator?: { by?: string };
|
|
17
|
+
selector?: string;
|
|
18
|
+
node_id?: number;
|
|
19
|
+
x?: number;
|
|
20
|
+
y?: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function resolveInteractionStrategy(
|
|
24
|
+
target: BrowserInteractionTarget,
|
|
25
|
+
): BrowserInteractionStrategy {
|
|
26
|
+
if (target.locator?.by === 'ax') return 'ax';
|
|
27
|
+
if (
|
|
28
|
+
target.locator?.by === 'role' ||
|
|
29
|
+
target.locator?.by === 'label' ||
|
|
30
|
+
target.locator?.by === 'text' ||
|
|
31
|
+
target.locator?.by === 'placeholder' ||
|
|
32
|
+
target.locator?.by === 'testid'
|
|
33
|
+
)
|
|
34
|
+
return 'role-locator';
|
|
35
|
+
if (target.locator || target.selector) return 'playwright-locator';
|
|
36
|
+
if (target.node_id !== undefined) return 'dom-cua';
|
|
37
|
+
if (target.x !== undefined && target.y !== undefined)
|
|
38
|
+
return 'visual-coordinate';
|
|
39
|
+
return 'cdp';
|
|
40
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser locators shared by BrowserBatch and future visible-DOM adapters.
|
|
3
|
+
*
|
|
4
|
+
* This deliberately emits a small, self-contained browser expression instead
|
|
5
|
+
* of retaining DOM node handles. A locator is resolved again for every step,
|
|
6
|
+
* so a navigation or React re-render cannot silently reuse a stale element.
|
|
7
|
+
*/
|
|
8
|
+
const quote = (value) => JSON.stringify(value);
|
|
9
|
+
/** Build an expression returning `Element[]` in the selected document. */
|
|
10
|
+
export function buildLocatorExpression(locator, selector, rootExpression = 'document') {
|
|
11
|
+
if (selector) {
|
|
12
|
+
return `Array.from(${rootExpression}.querySelectorAll(${quote(selector)}))`;
|
|
13
|
+
}
|
|
14
|
+
if (!locator)
|
|
15
|
+
throw new Error('step requires selector or locator');
|
|
16
|
+
if (locator.by === 'ax') {
|
|
17
|
+
throw new Error('AX locator must be resolved against the live accessibility tree first');
|
|
18
|
+
}
|
|
19
|
+
const root = locator.within
|
|
20
|
+
? `${buildLocatorExpression(locator.within, undefined, rootExpression)}.flatMap((scope) => Array.from(scope.querySelectorAll('*')))`
|
|
21
|
+
: `Array.from(${rootExpression}.querySelectorAll('*'))`;
|
|
22
|
+
const value = quote(locator.value);
|
|
23
|
+
const exact = locator.exact === true;
|
|
24
|
+
const compare = (expression, expected = value) => exact
|
|
25
|
+
? `${expression}.trim()===${expected}`
|
|
26
|
+
: `${expression}.includes(${expected})`;
|
|
27
|
+
let predicate;
|
|
28
|
+
switch (locator.by) {
|
|
29
|
+
case 'css':
|
|
30
|
+
return applyFilters(`Array.from(${rootExpression}.querySelectorAll(${value}))`, locator);
|
|
31
|
+
case 'role': {
|
|
32
|
+
const name = locator.name ? quote(locator.name) : value;
|
|
33
|
+
const nameCompare = locator.name
|
|
34
|
+
? `(function(name){return ${exact ? `name.trim()===${name}` : `name.includes(${name})`};})(__name)`
|
|
35
|
+
: 'true';
|
|
36
|
+
predicate = `(__role===${value}&&${nameCompare})`;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
case 'label':
|
|
40
|
+
predicate = `Array.from(__el.labels||[]).some((label)=>${compare("(label.textContent||'')")})`;
|
|
41
|
+
break;
|
|
42
|
+
case 'placeholder':
|
|
43
|
+
predicate = compare(`__el.getAttribute('placeholder')||''`);
|
|
44
|
+
break;
|
|
45
|
+
case 'alt':
|
|
46
|
+
predicate = compare(`__el.getAttribute('alt')||''`);
|
|
47
|
+
break;
|
|
48
|
+
case 'title':
|
|
49
|
+
predicate = compare(`__el.getAttribute('title')||''`);
|
|
50
|
+
break;
|
|
51
|
+
case 'testid':
|
|
52
|
+
predicate = compare(`__el.getAttribute('data-testid')||''`);
|
|
53
|
+
break;
|
|
54
|
+
case 'text':
|
|
55
|
+
predicate = `(!__el.children.length&&${compare("(__el.textContent||'')")})`;
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
const expression = `(() => {
|
|
59
|
+
const __accessibleName = (el) => {
|
|
60
|
+
const labelled = el.getAttribute('aria-label');
|
|
61
|
+
if (labelled) return labelled;
|
|
62
|
+
const ids = (el.getAttribute('aria-labelledby')||'').split(/\\s+/).filter(Boolean);
|
|
63
|
+
if (ids.length) return ids.map((id)=>${rootExpression}.getElementById(id)?.textContent||'').join(' ').trim();
|
|
64
|
+
if (el.labels?.length) return Array.from(el.labels).map((label)=>label.textContent||'').join(' ').trim();
|
|
65
|
+
return (el.innerText||el.textContent||'').trim();
|
|
66
|
+
};
|
|
67
|
+
const __implicitRole = (el) => {
|
|
68
|
+
const explicit = el.getAttribute('role');
|
|
69
|
+
if (explicit) return explicit;
|
|
70
|
+
const tag = el.tagName.toLowerCase();
|
|
71
|
+
if (tag === 'button') return 'button';
|
|
72
|
+
if (tag === 'a' && el.hasAttribute('href')) return 'link';
|
|
73
|
+
if (tag === 'textarea') return 'textbox';
|
|
74
|
+
if (tag === 'select') return 'combobox';
|
|
75
|
+
if (tag === 'input') {
|
|
76
|
+
const type = (el.getAttribute('type')||'text').toLowerCase();
|
|
77
|
+
if (type === 'checkbox') return 'checkbox';
|
|
78
|
+
if (type === 'radio') return 'radio';
|
|
79
|
+
if (type === 'button' || type === 'submit' || type === 'reset') return 'button';
|
|
80
|
+
return 'textbox';
|
|
81
|
+
}
|
|
82
|
+
return '';
|
|
83
|
+
};
|
|
84
|
+
return ${root}.filter((__el) => {
|
|
85
|
+
const __role = __implicitRole(__el);
|
|
86
|
+
const __name = __accessibleName(__el);
|
|
87
|
+
return ${predicate};
|
|
88
|
+
});
|
|
89
|
+
})()`;
|
|
90
|
+
const filtered = applyFilters(expression, locator);
|
|
91
|
+
const framePath = locator.frame ?? locator.framePath ?? locator.frame_path;
|
|
92
|
+
if (!framePath?.length)
|
|
93
|
+
return filtered;
|
|
94
|
+
// Same-origin frame traversal is explicit. Cross-origin frames cannot be
|
|
95
|
+
// inspected through Runtime.evaluate and must be handled by a backend that
|
|
96
|
+
// can attach to the child target; never pretend the parent matched instead.
|
|
97
|
+
let frameRoot = rootExpression;
|
|
98
|
+
for (const frame of framePath) {
|
|
99
|
+
const frameSelector = frame.by === 'css'
|
|
100
|
+
? quote(frame.value)
|
|
101
|
+
: quote(`iframe[title*="${frame.value.replaceAll('"', '\\"')}"]`);
|
|
102
|
+
frameRoot = `(() => { const frame = ${frameRoot}.querySelector(${frameSelector}); if (!frame || !frame.contentDocument) throw new Error('frameLocator could not resolve a same-origin iframe'); return frame.contentDocument; })()`;
|
|
103
|
+
}
|
|
104
|
+
return buildLocatorExpression({
|
|
105
|
+
...locator,
|
|
106
|
+
frame: undefined,
|
|
107
|
+
framePath: undefined,
|
|
108
|
+
frame_path: undefined,
|
|
109
|
+
frameId: undefined,
|
|
110
|
+
frame_id: undefined,
|
|
111
|
+
}, selector, frameRoot);
|
|
112
|
+
}
|
|
113
|
+
function applyFilters(expression, locator) {
|
|
114
|
+
const filters = [];
|
|
115
|
+
if (locator.has_text)
|
|
116
|
+
filters.push(`(__el.textContent||'').includes(${quote(locator.has_text)})`);
|
|
117
|
+
return filters.length
|
|
118
|
+
? `Array.from(${expression}).filter((__el)=>${filters.join('&&')})`
|
|
119
|
+
: expression;
|
|
120
|
+
}
|
|
121
|
+
export function buildTargetExpression(locator, selector) {
|
|
122
|
+
const elements = buildLocatorExpression(locator, selector);
|
|
123
|
+
const strict = locator?.strict !== false;
|
|
124
|
+
const nth = locator?.nth ?? 0;
|
|
125
|
+
return `(() => {
|
|
126
|
+
const __matches = ${elements}.filter((__candidate) => {
|
|
127
|
+
const __style = getComputedStyle(__candidate);
|
|
128
|
+
const __rect = __candidate.getBoundingClientRect();
|
|
129
|
+
return __style.display!=='none' && __style.visibility!=='hidden' && __style.pointerEvents!=='none' && (!!__rect.width || !!__rect.height);
|
|
130
|
+
});
|
|
131
|
+
if (!__matches.length) throw new Error('Locator matched no elements');
|
|
132
|
+
if (__matches.length > 1 && ${strict}) throw new Error('Locator matched '+__matches.length+' elements; use nth or strict:false');
|
|
133
|
+
const __el = __matches[${nth}];
|
|
134
|
+
if (!__el) throw new Error('Locator nth is outside the matched elements');
|
|
135
|
+
const __style = getComputedStyle(__el);
|
|
136
|
+
const __rect = __el.getBoundingClientRect();
|
|
137
|
+
if (__style.display==='none'||__style.visibility==='hidden'||__style.pointerEvents==='none'||(!__rect.width&&!__rect.height)) throw new Error('Locator matched a hidden element');
|
|
138
|
+
return __el;
|
|
139
|
+
})()`;
|
|
140
|
+
}
|