minimal-agent 0.10.0 → 0.12.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 +11 -3
- package/package.json +52 -5
- package/plugins/computer_use/.claude-plugin/plugin.json +6 -0
- package/plugins/computer_use/README.md +94 -0
- package/plugins/computer_use/app/_template.md +142 -0
- package/plugins/computer_use/app/chrome.md +165 -0
- package/plugins/computer_use/app/finder.md +76 -0
- package/plugins/computer_use/app/macos-system-settings.md +81 -0
- package/plugins/computer_use/app/microsoft-excel.md +80 -0
- package/plugins/computer_use/app/microsoft-powerpoint.md +80 -0
- package/plugins/computer_use/app/microsoft-word.md +79 -0
- package/plugins/computer_use/app/wechat.md +413 -0
- package/plugins/computer_use/app/weread.md +319 -0
- package/plugins/computer_use/commands/computeruse.md +25 -0
- package/plugins/computer_use/commands/cu.md +9 -0
- package/plugins/computer_use/plugin.js +26 -0
- package/plugins/computer_use/plugin.ts +30 -0
- package/plugins/computer_use/src/capture.js +90 -0
- package/plugins/computer_use/src/capture.ts +104 -0
- package/plugins/computer_use/src/commands.js +91 -0
- package/plugins/computer_use/src/commands.ts +103 -0
- package/plugins/computer_use/src/daemon.js +134 -0
- package/plugins/computer_use/src/daemon.ts +161 -0
- package/plugins/computer_use/src/manuals.js +135 -0
- package/plugins/computer_use/src/manuals.ts +159 -0
- package/plugins/computer_use/src/verify.js +168 -0
- package/plugins/computer_use/src/verify.ts +219 -0
- package/plugins/computer_use/test/commands.test.ts +73 -0
- package/plugins/cron-runner/plugin.ts +38 -0
- package/plugins/cron-runner/src/commands.ts +373 -0
- package/plugins/cron-runner/src/cronTime.ts +155 -0
- package/plugins/cron-runner/src/lock.ts +79 -0
- package/plugins/cron-runner/src/runs.ts +99 -0
- package/plugins/cron-runner/src/scheduleEngine.ts +76 -0
- package/plugins/cron-runner/src/scheduler.ts +376 -0
- package/plugins/cron-runner/src/schema.ts +139 -0
- package/plugins/cron-runner/src/service.ts +193 -0
- package/plugins/cron-runner/src/store.ts +333 -0
- package/plugins/cron-runner/src/types.ts +141 -0
- package/plugins/cron-runner/test/cronTime.test.ts +41 -0
- package/plugins/cron-runner/test/plugin-integration.test.ts +47 -0
- package/plugins/cron-runner/test/scheduleEngine.test.ts +41 -0
- package/plugins/cron-runner/test/service.test.ts +76 -0
- package/plugins/cron-runner/test/store-and-scheduler.test.ts +501 -0
- package/plugins/workflow-runner/plugin.js +56 -2
- package/plugins/workflow-runner/plugin.ts +113 -0
- package/plugins/workflow-runner/src/agentCommon.js +43 -4
- package/plugins/workflow-runner/src/agentCommon.ts +435 -0
- package/plugins/workflow-runner/src/controlFlow/branch.js +40 -0
- package/plugins/workflow-runner/src/controlFlow/branch.ts +46 -0
- package/plugins/workflow-runner/src/controlFlow/loop.js +211 -0
- package/plugins/workflow-runner/src/controlFlow/loop.ts +248 -0
- package/plugins/workflow-runner/src/controlFlow/pause.js +129 -0
- package/plugins/workflow-runner/src/controlFlow/pause.ts +141 -0
- package/plugins/workflow-runner/src/controlFlow/signal.js +21 -0
- package/plugins/workflow-runner/src/controlFlow/signal.ts +29 -0
- package/plugins/workflow-runner/src/controlFlow/types.js +18 -0
- package/plugins/workflow-runner/src/controlFlow/types.ts +63 -0
- package/plugins/workflow-runner/src/dslManifest.ts +127 -0
- package/plugins/workflow-runner/src/expressions.ts +622 -0
- package/plugins/workflow-runner/src/index.js +13 -4
- package/plugins/workflow-runner/src/index.ts +338 -0
- package/plugins/workflow-runner/src/jsonPayload.ts +84 -0
- package/plugins/workflow-runner/src/loader.js +23 -0
- package/plugins/workflow-runner/src/loader.ts +721 -0
- package/plugins/workflow-runner/src/multimodal.js +2 -1
- package/plugins/workflow-runner/src/multimodal.ts +64 -0
- package/plugins/workflow-runner/src/recovery.ts +149 -0
- package/plugins/workflow-runner/src/runner.js +75 -659
- package/plugins/workflow-runner/src/runner.ts +604 -0
- package/plugins/workflow-runner/src/stepExecutors/agent.ts +234 -0
- package/plugins/workflow-runner/src/stepExecutors/assert.ts +50 -0
- package/plugins/workflow-runner/src/stepExecutors/echo.js +31 -0
- package/plugins/workflow-runner/src/stepExecutors/echo.ts +38 -0
- package/plugins/workflow-runner/src/stepExecutors/llm.ts +133 -0
- package/plugins/workflow-runner/src/stepExecutors/set.js +49 -0
- package/plugins/workflow-runner/src/stepExecutors/set.ts +56 -0
- package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
- package/plugins/workflow-runner/src/stepExecutors/skill.ts +140 -0
- package/plugins/workflow-runner/src/stepExecutors/tool.js +80 -8
- package/plugins/workflow-runner/src/stepExecutors/tool.ts +256 -0
- package/plugins/workflow-runner/src/stepExecutors/verify.ts +68 -0
- package/plugins/workflow-runner/src/stepPipeline.js +277 -0
- package/plugins/workflow-runner/src/stepPipeline.ts +366 -0
- package/plugins/workflow-runner/src/taskIdentity.ts +405 -0
- package/plugins/workflow-runner/src/toolRuntime.js +48 -0
- package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
- package/plugins/workflow-runner/src/types.js +37 -1
- package/plugins/workflow-runner/src/types.ts +602 -0
- package/plugins/workflow-runner/src/workflowState.ts +733 -0
- package/plugins/workflow-runner/test/agent.test.ts +587 -0
- package/plugins/workflow-runner/test/agentLlmError.test.ts +373 -0
- package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +65 -0
- package/plugins/workflow-runner/test/captureMisbind.test.ts +99 -0
- package/plugins/workflow-runner/test/cli.e2e.test.ts +147 -0
- package/plugins/workflow-runner/test/context-files.test.ts +320 -0
- package/plugins/workflow-runner/test/e2e.test.ts +370 -0
- package/plugins/workflow-runner/test/engineRobustness.test.ts +226 -0
- package/plugins/workflow-runner/test/expressions.test.ts +397 -0
- package/plugins/workflow-runner/test/foundation.test.ts +126 -0
- package/plugins/workflow-runner/test/graceful.test.ts +139 -0
- package/plugins/workflow-runner/test/greedyInputs.load.test.ts +47 -0
- package/plugins/workflow-runner/test/hostCapability.test.ts +108 -0
- package/plugins/workflow-runner/test/illustrate.load.test.ts +183 -0
- package/plugins/workflow-runner/test/jsonPayload.test.ts +83 -0
- package/plugins/workflow-runner/test/loader.test.ts +617 -0
- package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +33 -0
- package/plugins/workflow-runner/test/multimodal.test.ts +342 -0
- package/plugins/workflow-runner/test/output-schema.test.ts +213 -0
- package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +87 -0
- package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +269 -0
- package/plugins/workflow-runner/test/ppt.load.test.ts +1220 -0
- package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +220 -0
- package/plugins/workflow-runner/test/recovery.test.ts +265 -0
- package/plugins/workflow-runner/test/runner.test.ts +911 -0
- package/plugins/workflow-runner/test/runnerPreflight.test.ts +379 -0
- package/plugins/workflow-runner/test/skillTurnDone.test.ts +71 -0
- package/plugins/workflow-runner/test/stateLifecycle.test.ts +150 -0
- package/plugins/workflow-runner/test/stepPipeline.test.ts +114 -0
- package/plugins/workflow-runner/test/taskArbitration.test.ts +338 -0
- package/plugins/workflow-runner/test/taskIdentity.test.ts +237 -0
- package/plugins/workflow-runner/test/taskLifecycle.test.ts +270 -0
- package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +221 -0
- package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +29 -0
- package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
- package/plugins/workflow-runner/test/webppt.load.test.ts +250 -0
- package/plugins/workflow-runner/test/word.load.test.ts +208 -0
- package/plugins/workflow-runner/test/workflows.smoke.test.ts +76 -0
- package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +207 -0
- package/skills/browser-automation/SKILL.md +9 -19
- package/skills/web-crawler/SKILL.md +9 -11
- package/src/askBridge.ts +249 -0
- package/src/bootstrap/cwdArg.js +10 -3
- package/src/bootstrap/cwdArg.ts +31 -0
- package/src/bootstrap/workingDir.ts +48 -0
- package/src/cli/args.js +70 -7
- package/src/cli/args.ts +146 -0
- package/src/cli/computerUse.js +185 -0
- package/src/cli/computerUse.ts +221 -0
- package/src/cli/configMenu.js +274 -202
- package/src/cli/configMenu.tsx +521 -0
- package/src/cli/memoryAccess.js +45 -0
- package/src/cli/memoryAccess.ts +53 -0
- package/src/cli/print.js +119 -5
- package/src/cli/print.ts +597 -0
- package/src/cli/quickModelSetup.js +60 -0
- package/src/cli/quickModelSetup.tsx +96 -0
- package/src/cli/streamJson.js +80 -4
- package/src/cli/streamJson.ts +433 -0
- package/src/cli/wizards/advisorWizard.js +1 -0
- package/src/cli/wizards/advisorWizard.tsx +195 -0
- package/src/cli/wizards/agentRuntimeWizard.js +84 -0
- package/src/cli/wizards/agentRuntimeWizard.tsx +134 -0
- package/src/cli/wizards/browserWizard.js +55 -0
- package/src/cli/wizards/browserWizard.tsx +77 -0
- package/src/cli/wizards/contextAdvisorWizard.js +84 -0
- package/src/cli/wizards/contextAdvisorWizard.tsx +124 -0
- package/src/cli/wizards/fieldForm.js +7 -4
- package/src/cli/wizards/fieldForm.tsx +250 -0
- package/src/cli/wizards/imageWizard.js +4 -5
- package/src/cli/wizards/imageWizard.tsx +96 -0
- package/src/cli/wizards/openRouterWizard.tsx +48 -0
- package/src/cli/wizards/providerPresets.js +1 -8
- package/src/cli/wizards/providerPresets.ts +106 -0
- package/src/cli/wizards/providerWizard.js +152 -205
- package/src/cli/wizards/providerWizard.tsx +266 -0
- package/src/cli/wizards/searchWizard.tsx +47 -0
- package/src/cli/wizards/ttsWizard.js +4 -3
- package/src/cli/wizards/ttsWizard.tsx +61 -0
- package/src/config/configDefaults.js +25 -0
- package/src/config/configDefaults.ts +33 -0
- package/src/config/configDiagnostics.js +117 -0
- package/src/config/configDiagnostics.ts +166 -0
- package/src/config/configFile.js +52 -32
- package/src/config/configFile.ts +633 -0
- package/src/config/configManagement.js +126 -0
- package/src/config/configManagement.ts +159 -0
- package/src/config/configService.js +66 -11
- package/src/config/configService.ts +554 -0
- package/src/config/numericLimits.js +61 -0
- package/src/config/numericLimits.ts +80 -0
- package/src/config.ts +109 -0
- package/src/context/agentHome.ts +11 -0
- package/src/context/archive.ts +144 -0
- package/src/context/budgetPlan.js +54 -0
- package/src/context/budgetPlan.ts +88 -0
- package/src/context/compact.js +179 -106
- package/src/context/compact.ts +584 -0
- package/src/context/contextBundle.js +119 -0
- package/src/context/contextBundle.ts +176 -0
- package/src/context/contextLock.ts +84 -0
- package/src/context/microCompactLite.ts +218 -0
- package/src/context/persistContext.ts +177 -0
- package/src/context/reactiveCompact.js +19 -4
- package/src/context/reactiveCompact.ts +240 -0
- package/src/context/recentDirs.ts +42 -0
- package/src/context/sessionPath.ts +206 -0
- package/src/context/sessionRegistry.js +8 -2
- package/src/context/sessionRegistry.ts +414 -0
- package/src/context/snipCompact.ts +163 -0
- package/src/context/tokenCounter.ts +106 -0
- package/src/context/workspaceIndex.js +2 -2
- package/src/context/workspaceIndex.ts +751 -0
- package/src/entry.compiled.tsx +20 -0
- package/src/harness/claimValidation.js +9 -0
- package/src/harness/claimValidation.ts +22 -0
- package/src/harness/evidenceLedger.js +92 -0
- package/src/harness/evidenceLedger.ts +96 -0
- package/src/harness/stallGuard.js +60 -0
- package/src/harness/stallGuard.ts +81 -0
- package/src/humanIntervention.js +129 -0
- package/src/humanIntervention.ts +216 -0
- package/src/infra/verification.ts +295 -0
- package/src/irreversible/rules.js +216 -0
- package/src/irreversible/rules.ts +261 -0
- package/src/llm/client.js +40 -3
- package/src/llm/client.ts +621 -0
- package/src/llm/promptCache.js +27 -0
- package/src/llm/promptCache.ts +41 -0
- package/src/llm/providers/anthropicFormat.js +41 -5
- package/src/llm/providers/anthropicFormat.ts +290 -0
- package/src/llm/providers/openaiFormat.js +186 -8
- package/src/llm/providers/openaiFormat.ts +428 -0
- package/src/loop.js +614 -63
- package/src/loop.ts +1454 -0
- package/src/main.js +67 -10
- package/src/main.tsx +344 -0
- package/src/memory/codec.js +204 -0
- package/src/memory/codec.ts +249 -0
- package/src/memory/constants.js +34 -0
- package/src/memory/constants.ts +50 -0
- package/src/memory/episodicMemory.js +684 -0
- package/src/memory/episodicMemory.ts +815 -0
- package/src/memory/fileStore.js +148 -0
- package/src/memory/fileStore.ts +184 -0
- package/src/memory/memoryService.js +570 -0
- package/src/memory/memoryService.ts +859 -0
- package/src/memory/migration.js +128 -0
- package/src/memory/migration.ts +160 -0
- package/src/memory/repository.js +789 -0
- package/src/memory/repository.ts +893 -0
- package/src/memory/retrieval.js +108 -0
- package/src/memory/retrieval.ts +145 -0
- package/src/memory/searchIndex.js +107 -0
- package/src/memory/searchIndex.ts +153 -0
- package/src/memory/topicView.js +82 -0
- package/src/memory/topicView.ts +95 -0
- package/src/memory/turnJournal.js +95 -0
- package/src/memory/turnJournal.ts +120 -0
- package/src/memory/types.js +2 -0
- package/src/memory/types.ts +186 -0
- package/src/messageQueue.ts +123 -0
- package/src/multimodal.js +128 -46
- package/src/multimodal.ts +349 -0
- package/src/plugin-sdk.js +21 -1
- package/src/plugin-sdk.ts +134 -0
- package/src/plugins/builtinPluginIds.js +47 -0
- package/src/plugins/builtinPluginIds.ts +51 -0
- package/src/plugins/builtinRegistry.ts +43 -0
- package/src/plugins/commandRouter.js +40 -26
- package/src/plugins/commandRouter.ts +261 -0
- package/src/plugins/hookEngine.ts +341 -0
- package/src/plugins/pluginApi.ts +133 -0
- package/src/plugins/pluginLifecycle.ts +34 -0
- package/src/plugins/pluginLoader.ts +147 -0
- package/src/plugins/pluginManifest.js +127 -0
- package/src/plugins/pluginManifest.ts +152 -0
- package/src/plugins/pluginRunner.js +47 -2
- package/src/plugins/pluginRunner.ts +207 -0
- package/src/plugins/transcript.ts +208 -0
- package/src/prompts/lint.js +169 -0
- package/src/prompts/lint.ts +220 -0
- package/src/prompts/pluginList.js +32 -16
- package/src/prompts/pluginList.ts +86 -0
- package/src/prompts/policyRegistry.js +318 -0
- package/src/prompts/policyRegistry.ts +358 -0
- package/src/prompts/projectInstructions.js +24 -0
- package/src/prompts/projectInstructions.ts +81 -0
- package/src/prompts/promptAssembly.js +311 -202
- package/src/prompts/promptAssembly.ts +510 -0
- package/src/prompts/skillList.js +106 -45
- package/src/prompts/skillList.ts +198 -0
- package/src/prompts/system.js +31 -6
- package/src/prompts/system.ts +81 -0
- package/src/runtime/agentRuntimeContext.js +53 -0
- package/src/runtime/agentRuntimeContext.ts +112 -0
- package/src/session/runAgentTurn.js +71 -12
- package/src/session/runAgentTurn.ts +181 -0
- package/src/session/runTurn.js +29 -0
- package/src/session/runTurn.ts +160 -0
- package/src/session/runtimeStore.js +149 -0
- package/src/session/runtimeStore.ts +197 -0
- package/src/session/sessionState.js +79 -3
- package/src/session/sessionState.ts +134 -0
- package/src/toolGate.ts +50 -0
- package/src/tools/advisor/advisor.js +76 -15
- package/src/tools/advisor/advisor.ts +512 -0
- package/src/tools/agent/agent.js +245 -29
- package/src/tools/agent/agent.ts +837 -0
- package/src/tools/agent/agentTaskService.js +60 -0
- package/src/tools/agent/agentTaskService.ts +113 -0
- package/src/tools/agent/agentTypes.js +20 -8
- package/src/tools/agent/agentTypes.ts +94 -0
- package/src/tools/agent/coordinator.ts +111 -0
- package/src/tools/agent/worktree.ts +296 -0
- package/src/tools/ask/ask.js +17 -0
- package/src/tools/ask/ask.ts +122 -0
- package/src/tools/bash/attachImage.js +223 -0
- package/src/tools/bash/attachImage.ts +281 -0
- package/src/tools/bash/bash.js +132 -14
- package/src/tools/bash/bash.ts +642 -0
- package/src/tools/bash/semantics.ts +103 -0
- package/src/tools/bash/warnings.js +17 -11
- package/src/tools/bash/warnings.ts +117 -0
- package/src/tools/capabilities.js +42 -0
- package/src/tools/capabilities.ts +69 -0
- package/src/tools/computeruse/accessibilityPermission.js +261 -0
- package/src/tools/computeruse/accessibilityPermission.ts +294 -0
- package/src/tools/computeruse/axSearch.js +96 -0
- package/src/tools/computeruse/axSearch.ts +120 -0
- package/src/tools/computeruse/axSnap.js +272 -0
- package/src/tools/computeruse/axSnap.ts +349 -0
- package/src/tools/computeruse/capabilityLabels.js +95 -0
- package/src/tools/computeruse/capabilityLabels.ts +115 -0
- package/src/tools/computeruse/computerUseService.js +2235 -0
- package/src/tools/computeruse/computerUseService.ts +2686 -0
- package/src/tools/computeruse/computeruse.js +2742 -0
- package/src/tools/computeruse/computeruse.ts +3265 -0
- package/src/tools/computeruse/diagnosticTrace.js +154 -0
- package/src/tools/computeruse/diagnosticTrace.ts +195 -0
- package/src/tools/computeruse/diagnostics.js +369 -0
- package/src/tools/computeruse/diagnostics.ts +453 -0
- package/src/tools/computeruse/grants.js +53 -0
- package/src/tools/computeruse/grants.ts +70 -0
- package/src/tools/computeruse/humanBoundary.js +159 -0
- package/src/tools/computeruse/humanBoundary.ts +199 -0
- package/src/tools/computeruse/intervention.js +77 -0
- package/src/tools/computeruse/intervention.ts +110 -0
- package/src/tools/computeruse/manualSchema.js +709 -0
- package/src/tools/computeruse/manualSchema.ts +916 -0
- package/src/tools/computeruse/observationImages.js +705 -0
- package/src/tools/computeruse/observationImages.ts +889 -0
- package/src/tools/computeruse/protocol.js +60 -0
- package/src/tools/computeruse/protocol.ts +515 -0
- package/src/tools/computeruse/telemetryLog.js +57 -0
- package/src/tools/computeruse/telemetryLog.ts +67 -0
- package/src/tools/computeruse/vision/appGuide.js +325 -0
- package/src/tools/computeruse/vision/appGuide.ts +482 -0
- package/src/tools/computeruse/vision/focus.js +291 -0
- package/src/tools/computeruse/vision/focus.ts +382 -0
- package/src/tools/computeruse/vision/frames.js +248 -0
- package/src/tools/computeruse/vision/frames.ts +329 -0
- package/src/tools/computeruse/vision/geometry.js +131 -0
- package/src/tools/computeruse/vision/geometry.ts +163 -0
- package/src/tools/computeruse/vision/imaging.js +201 -0
- package/src/tools/computeruse/vision/imaging.ts +281 -0
- package/src/tools/computeruse/vision/png.js +274 -0
- package/src/tools/computeruse/vision/png.ts +317 -0
- package/src/tools/computeruse/vision/raster.js +320 -0
- package/src/tools/computeruse/vision/raster.ts +408 -0
- package/src/tools/computeruse/vision/settle.js +131 -0
- package/src/tools/computeruse/vision/settle.ts +220 -0
- package/src/tools/computeruse/vision/telemetry.js +196 -0
- package/src/tools/computeruse/vision/telemetry.ts +241 -0
- package/src/tools/computeruse/visionOcr.js +115 -0
- package/src/tools/computeruse/visionOcr.ts +128 -0
- package/src/tools/computeruse/waitFor.js +237 -0
- package/src/tools/computeruse/waitFor.ts +291 -0
- package/src/tools/download/download.js +10 -6
- package/src/tools/download/download.ts +187 -0
- package/src/tools/edit/edit.js +30 -18
- package/src/tools/edit/edit.ts +349 -0
- package/src/tools/edit/multi-edit.js +25 -14
- package/src/tools/edit/multi-edit.ts +223 -0
- package/src/tools/effectiveToolSet.js +73 -0
- package/src/tools/effectiveToolSet.ts +91 -0
- package/src/tools/genimage/genimage.ts +257 -0
- package/src/tools/genspeech/genspeech.ts +83 -0
- package/src/tools/glob/glob.js +176 -29
- package/src/tools/glob/glob.ts +283 -0
- package/src/tools/grep/grep.js +61 -19
- package/src/tools/grep/grep.ts +239 -0
- package/src/tools/grep/rgPath.ts +206 -0
- package/src/tools/index.js +99 -5
- package/src/tools/index.ts +293 -0
- package/src/tools/lsp/config.js +113 -0
- package/src/tools/lsp/config.ts +113 -0
- package/src/tools/lsp/lsp.js +256 -0
- package/src/tools/lsp/lsp.ts +274 -0
- package/src/tools/lsp/service.js +303 -0
- package/src/tools/lsp/service.ts +296 -0
- package/src/tools/memory/memory.js +520 -0
- package/src/tools/memory/memory.ts +625 -0
- package/src/tools/memory/policy.js +53 -0
- package/src/tools/memory/policy.ts +72 -0
- package/src/tools/notebook/notebookEdit.js +114 -0
- package/src/tools/notebook/notebookEdit.ts +126 -0
- package/src/tools/powershell/powershell.js +210 -0
- package/src/tools/powershell/powershell.ts +239 -0
- package/src/tools/presentresult/presentresult.js +145 -0
- package/src/tools/presentresult/presentresult.ts +156 -0
- package/src/tools/read/read.js +371 -163
- package/src/tools/read/read.ts +558 -0
- package/src/tools/shared/diffSummary.js +44 -0
- package/src/tools/shared/diffSummary.ts +63 -0
- package/src/tools/shared/fileActivity.js +51 -0
- package/src/tools/shared/fileActivity.ts +66 -0
- package/src/tools/shared/fileMutationBus.js +13 -0
- package/src/tools/shared/fileMutationBus.ts +14 -0
- package/src/tools/shared/fileState.js +73 -65
- package/src/tools/shared/fileState.ts +145 -0
- package/src/tools/shared/fileUtils.js +81 -4
- package/src/tools/shared/fileUtils.ts +504 -0
- package/src/tools/shared/killTree.ts +50 -0
- package/src/tools/shared/permanentDeleteGuard.js +26 -0
- package/src/tools/shared/permanentDeleteGuard.ts +34 -0
- package/src/tools/shared/schemas.ts +20 -0
- package/src/tools/shared/toolOutputStore.js +97 -0
- package/src/tools/shared/toolOutputStore.ts +110 -0
- package/src/tools/skill/skill.js +86 -0
- package/src/tools/skill/skill.ts +94 -0
- package/src/tools/snip/snip.js +67 -0
- package/src/tools/snip/snip.ts +80 -0
- package/src/tools/tasks/backgroundTaskService.js +275 -0
- package/src/tools/tasks/backgroundTaskService.ts +369 -0
- package/src/tools/tasks/processEvidence.js +24 -0
- package/src/tools/tasks/processEvidence.ts +34 -0
- package/src/tools/tasks/taskManagement.js +163 -0
- package/src/tools/tasks/taskManagement.ts +180 -0
- package/src/tools/tasks/taskOutput.js +113 -0
- package/src/tools/tasks/taskOutput.ts +145 -0
- package/src/tools/tasks/taskStop.js +74 -0
- package/src/tools/tasks/taskStop.ts +99 -0
- package/src/tools/tasks/taskStore.js +46 -0
- package/src/tools/tasks/taskStore.ts +77 -0
- package/src/tools/terminal/terminalCapture.js +167 -0
- package/src/tools/terminal/terminalCapture.ts +179 -0
- package/src/tools/trash/trash.js +233 -0
- package/src/tools/trash/trash.ts +283 -0
- package/src/tools/types.js +1 -1
- package/src/tools/types.ts +24 -0
- package/src/tools/webbrowser/agentBrowserPath.ts +286 -0
- package/src/tools/webbrowser/browser.js +214 -11
- package/src/tools/webbrowser/browser.ts +293 -0
- package/src/tools/webbrowser/browserControl.js +153 -48
- package/src/tools/webbrowser/browserControl.ts +262 -0
- package/src/tools/webbrowser/browserDaemon.js +147 -39
- package/src/tools/webbrowser/browserDaemon.ts +270 -0
- package/src/tools/webbrowser/browserOutcome.js +273 -0
- package/src/tools/webbrowser/browserOutcome.ts +306 -0
- package/src/tools/webbrowser/browserRunRegistry.js +150 -0
- package/src/tools/webbrowser/browserRunRegistry.ts +179 -0
- package/src/tools/webbrowser/browserService.js +20 -6
- package/src/tools/webbrowser/browserService.ts +56 -0
- package/src/tools/webbrowser/browserStream.js +30 -1
- package/src/tools/webbrowser/browserStream.ts +216 -0
- package/src/tools/webbrowser/browserTabs.js +143 -0
- package/src/tools/webbrowser/browserTabs.ts +210 -0
- package/src/tools/webbrowser/webbrowser.js +831 -150
- package/src/tools/webbrowser/webbrowser.ts +1537 -0
- package/src/tools/webfetch/preapproved.ts +274 -0
- package/src/tools/webfetch/webfetch.js +24 -23
- package/src/tools/webfetch/webfetch.ts +383 -0
- package/src/tools/websearch/websearch.js +12 -11
- package/src/tools/websearch/websearch.ts +292 -0
- package/src/tools/worktree/sessionWorktree.js +128 -0
- package/src/tools/worktree/sessionWorktree.ts +158 -0
- package/src/tools/write/write.js +27 -44
- package/src/tools/write/write.ts +136 -0
- package/src/types.ts +960 -0
- package/src/ui/App.js +216 -12
- package/src/ui/App.tsx +879 -0
- package/src/ui/AskQuestion.tsx +300 -0
- package/src/ui/InputBox.js +77 -1
- package/src/ui/InputBox.tsx +567 -0
- package/src/ui/LiveArea.tsx +344 -0
- package/src/ui/MessageList.js +27 -6
- package/src/ui/MessageList.tsx +559 -0
- package/src/ui/ModelPicker.tsx +107 -0
- package/src/ui/QueuedMessagesBanner.tsx +51 -0
- package/src/ui/Root.js +6 -8
- package/src/ui/Root.tsx +100 -0
- package/src/ui/SessionPicker.tsx +169 -0
- package/src/ui/StatusLine.js +22 -1
- package/src/ui/StatusLine.tsx +145 -0
- package/src/ui/WorkspacePicker.tsx +84 -0
- package/src/ui/advisorCommand.js +54 -0
- package/src/ui/advisorCommand.ts +63 -0
- package/src/ui/computerCommand.js +19 -0
- package/src/ui/computerCommand.ts +35 -0
- package/src/ui/figures.ts +45 -0
- package/src/ui/hooks/askSlot.ts +112 -0
- package/src/ui/hooks/useChat.js +271 -7
- package/src/ui/hooks/useChat.ts +1578 -0
- package/src/ui/hooks/useInputHistory.ts +235 -0
- package/src/ui/hooks/usePasteHandler.ts +220 -0
- package/src/ui/hooks/useTerminalSize.ts +41 -0
- package/src/ui/hooks/useTextBuffer.ts +108 -0
- package/src/ui/hooks/useTokenUsage.ts +44 -0
- package/src/ui/liveViewport.ts +189 -0
- package/src/ui/markdown.ts +230 -0
- package/src/ui/textBuffer.ts +239 -0
- package/src/ui/theme.ts +35 -0
- package/src/utils/clipboardImage.js +358 -0
- package/src/utils/clipboardImage.ts +420 -0
- package/src/utils/debugLog.ts +50 -0
- package/src/utils/greenRoot.ts +35 -0
- package/src/utils/packageRoot.ts +40 -0
- package/src/utils/pathContains.js +28 -0
- package/src/utils/pathContains.ts +31 -0
- package/src/utils/resourcePaths.ts +71 -0
- package/src/utils/stripThink.ts +49 -0
- package/src/utils/zodToJson.ts +73 -0
- package/src/web/browserBridge.js +365 -66
- package/src/web/browserBridge.ts +672 -0
- package/src/web/protocol.ts +1804 -0
- package/vendor/computer-use/arm64-darwin/cu-helperd +0 -0
- package/workflows/ppt.yaml +13 -2
- package/workflows/wechat-reading-shots.yaml +315 -0
- package/workflows/word.yaml +11 -1
- package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
- package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
- package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
- package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
- /package/skills/ai-image/scripts/{generate_test.mjs → generate.selftest.mjs} +0 -0
- /package/skills/ai-image/scripts/{generate_from_plan_test.mjs → generate_from_plan.selftest.mjs} +0 -0
package/src/web/browserBridge.js
CHANGED
|
@@ -2,16 +2,12 @@ import { randomUUID } from 'node:crypto';
|
|
|
2
2
|
import { rm } from 'node:fs/promises';
|
|
3
3
|
import { configService } from '../config/configService.js';
|
|
4
4
|
import { resolveAgentBrowserPath } from '../tools/webbrowser/agentBrowserPath.js';
|
|
5
|
-
import { browserProfilePath, sessionArgs, spawnRunner } from '../tools/webbrowser/browser.js';
|
|
5
|
+
import { browserProfilePath, normalizeUrl, sessionArgs, spawnRunner } from '../tools/webbrowser/browser.js';
|
|
6
6
|
import { ensureDaemon, stopDaemon } from '../tools/webbrowser/browserDaemon.js';
|
|
7
7
|
import { browserService } from '../tools/webbrowser/browserService.js';
|
|
8
|
+
import { browserRunRegistry } from '../tools/webbrowser/browserRunRegistry.js';
|
|
9
|
+
import { createConversationTab, ensureConversationTab, listBrowserTabs, } from '../tools/webbrowser/browserTabs.js';
|
|
8
10
|
import { getBrowserStream, } from '../tools/webbrowser/browserStream.js';
|
|
9
|
-
function normalizeUrl(value) {
|
|
10
|
-
const input = value.trim();
|
|
11
|
-
if (/^[a-z][a-z0-9+.-]*:/i.test(input))
|
|
12
|
-
return input;
|
|
13
|
-
return `https://${input}`;
|
|
14
|
-
}
|
|
15
11
|
function requireAllowedDeveloperOrigin(url, allowedOrigins) {
|
|
16
12
|
let origin;
|
|
17
13
|
try {
|
|
@@ -89,6 +85,24 @@ function mapStreamEvent(event) {
|
|
|
89
85
|
return { id: String(item.tabId ?? item.id ?? ''), url: String(item.url ?? ''), title: typeof item.title === 'string' ? item.title : undefined, active: Boolean(item.active), favicon: typeof item.favicon === 'string' ? item.favicon : undefined };
|
|
90
86
|
}) };
|
|
91
87
|
}
|
|
88
|
+
case 'agent_candidates': {
|
|
89
|
+
const list = Array.isArray(event.candidates) ? event.candidates : [];
|
|
90
|
+
return {
|
|
91
|
+
t: 'browser/agent/candidates',
|
|
92
|
+
candidates: list.map((item) => {
|
|
93
|
+
const c = item;
|
|
94
|
+
return { ref: String(c.ref ?? ''), line: String(c.line ?? '') };
|
|
95
|
+
}),
|
|
96
|
+
...(typeof event.selector === 'string' ? { selector: event.selector } : {}),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
case 'agent_outcome': return {
|
|
100
|
+
t: 'browser/agent/outcome',
|
|
101
|
+
action: String(event.action ?? ''),
|
|
102
|
+
effect: event.effect === 'unknown' ? 'unknown' : 'unchanged',
|
|
103
|
+
...(typeof event.selector === 'string' ? { selector: event.selector } : {}),
|
|
104
|
+
...(typeof event.maskedLines === 'number' ? { maskedLines: event.maskedLines } : {}),
|
|
105
|
+
};
|
|
92
106
|
case 'url': return { t: 'browser/url', url: String(event.url ?? ''), tabId: typeof event.tabId === 'string' ? event.tabId : undefined };
|
|
93
107
|
case 'title': return { t: 'browser/title', title: String(event.title ?? ''), tabId: typeof event.tabId === 'string' ? event.tabId : undefined };
|
|
94
108
|
case 'navigation': return { t: 'browser/navigation', url: String(event.url ?? ''), state: (event.state === 'start' || event.state === 'commit' || event.state === 'domcontentloaded') ? event.state : 'load' };
|
|
@@ -99,37 +113,151 @@ function mapStreamEvent(event) {
|
|
|
99
113
|
case 'mode': return { t: 'browser/mode', mode: event.mode };
|
|
100
114
|
case 'marked_elements': return { t: 'browser/marked/elements', elements: (event.elements ?? []) };
|
|
101
115
|
case 'agent_acting': return { t: 'browser/agent/acting', acting: Boolean(event.acting), action: typeof event.action === 'string' ? event.action : undefined, target: typeof event.target === 'string' ? event.target : undefined };
|
|
116
|
+
case 'agent_pointer': return { t: 'browser/agent/pointer', x: Number(event.x ?? 0), y: Number(event.y ?? 0), visible: Boolean(event.visible), action: (typeof event.action === 'string' ? event.action : undefined), elementRef: typeof event.elementRef === 'string' ? event.elementRef : undefined };
|
|
102
117
|
case 'control_state': return { t: 'browser/control/changed', state: event.state };
|
|
103
118
|
default: return null;
|
|
104
119
|
}
|
|
105
120
|
}
|
|
121
|
+
function mapHumanInterventionEvent(event) {
|
|
122
|
+
if (event.type === 'started') {
|
|
123
|
+
return {
|
|
124
|
+
t: 'human-intervention/started',
|
|
125
|
+
intervention: event.intervention,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
t: 'human-intervention/resolved',
|
|
130
|
+
resolution: event.resolution,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export function createPointerRouteState() {
|
|
134
|
+
return { dragging: false, dragButton: 'left', pendingPress: null, lastDragMoveAt: 0 };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 纯函数:按持久路由状态决定一个用户鼠标帧怎么走。就地更新 state,返回待下发的快通路帧
|
|
138
|
+
* 与待入队的命令通路 argv。抽成纯函数便于单测拖拽判定/单击缓冲/节流,不碰真实 spawn。
|
|
139
|
+
*/
|
|
140
|
+
export function routeUserMouse(state, frame, now, dragMoveThrottleMs = 40) {
|
|
141
|
+
const plan = { stream: [], commands: [] };
|
|
142
|
+
const eventType = String(frame.eventType ?? '');
|
|
143
|
+
const x = Math.round(Number(frame.x ?? 0));
|
|
144
|
+
const y = Math.round(Number(frame.y ?? 0));
|
|
145
|
+
const fast = (f = frame) => plan.stream.push({ type: 'input_mouse', ...f, t: undefined });
|
|
146
|
+
if (eventType === 'mousePressed') {
|
|
147
|
+
// 缓冲按下:还不知道是单击还是拖拽——先不派发,等下一帧揭晓。
|
|
148
|
+
state.pendingPress = frame;
|
|
149
|
+
state.dragging = false;
|
|
150
|
+
return plan;
|
|
151
|
+
}
|
|
152
|
+
if (eventType === 'mouseMoved') {
|
|
153
|
+
if (state.pendingPress && !state.dragging) {
|
|
154
|
+
// 按下后首次移动 = 拖拽:在命令通路上建立「按住」状态(mouse down 令 daemon 记住 buttons)。
|
|
155
|
+
const px = Math.round(Number(state.pendingPress.x ?? x));
|
|
156
|
+
const py = Math.round(Number(state.pendingPress.y ?? y));
|
|
157
|
+
state.dragButton = String(state.pendingPress.button ?? 'left') || 'left';
|
|
158
|
+
state.dragging = true;
|
|
159
|
+
state.pendingPress = null;
|
|
160
|
+
state.lastDragMoveAt = now;
|
|
161
|
+
plan.commands.push(['move', String(px), String(py)], ['down', state.dragButton], ['move', String(x), String(y)]);
|
|
162
|
+
return plan;
|
|
163
|
+
}
|
|
164
|
+
if (state.dragging) {
|
|
165
|
+
// 拖拽中间帧:节流下发命令通路(spawn 昂贵),不再走 input_mouse 避免双通路重复派发。
|
|
166
|
+
if (now - state.lastDragMoveAt >= dragMoveThrottleMs) {
|
|
167
|
+
state.lastDragMoveAt = now;
|
|
168
|
+
plan.commands.push(['move', String(x), String(y)]);
|
|
169
|
+
}
|
|
170
|
+
return plan;
|
|
171
|
+
}
|
|
172
|
+
fast(); // 普通悬停 → 快通路
|
|
173
|
+
return plan;
|
|
174
|
+
}
|
|
175
|
+
if (eventType === 'mouseReleased') {
|
|
176
|
+
if (state.dragging) {
|
|
177
|
+
// 收尾:先补末帧到真实抬起坐标(节流可能丢了它),再抬起清 buttons。
|
|
178
|
+
plan.commands.push(['move', String(x), String(y)], ['up', state.dragButton]);
|
|
179
|
+
state.dragging = false;
|
|
180
|
+
return plan;
|
|
181
|
+
}
|
|
182
|
+
if (state.pendingPress) {
|
|
183
|
+
// 纯单击(按下后无移动):快通路补发缓冲的按下 + 本次抬起,语义仍是一次点击。
|
|
184
|
+
fast(state.pendingPress);
|
|
185
|
+
fast();
|
|
186
|
+
state.pendingPress = null;
|
|
187
|
+
return plan;
|
|
188
|
+
}
|
|
189
|
+
fast();
|
|
190
|
+
return plan;
|
|
191
|
+
}
|
|
192
|
+
// mouseWheel / 其它鼠标事件 → 快通路(不涉及按住拖拽)。
|
|
193
|
+
fast();
|
|
194
|
+
return plan;
|
|
195
|
+
}
|
|
106
196
|
export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
107
197
|
let disposed = false;
|
|
108
198
|
let activeTabId = '';
|
|
109
199
|
let pageRevision = randomUUID();
|
|
200
|
+
let runContext = null;
|
|
110
201
|
const stream = getBrowserStream(sessionName);
|
|
111
202
|
const unsubscribe = stream.subscribe((event) => {
|
|
112
203
|
if (disposed)
|
|
113
204
|
return;
|
|
205
|
+
if (event.type === 'control_state') {
|
|
206
|
+
const control = event.state;
|
|
207
|
+
if (control && control.status !== 'idle' && control.conversationKey) {
|
|
208
|
+
runContext = browserRunRegistry.find(control.conversationKey, control.runId)
|
|
209
|
+
?? browserRunRegistry.ensure({
|
|
210
|
+
conversationKey: control.conversationKey,
|
|
211
|
+
runId: control.runId,
|
|
212
|
+
profileId: 'default',
|
|
213
|
+
grants: ['observe', 'interact'],
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (event.type === 'human_intervention_started' || event.type === 'human_intervention_resolved') {
|
|
218
|
+
const interventionEvent = event.event;
|
|
219
|
+
if (interventionEvent)
|
|
220
|
+
send(mapHumanInterventionEvent(interventionEvent));
|
|
221
|
+
}
|
|
114
222
|
if (event.type === 'url' || event.type === 'navigation')
|
|
115
223
|
pageRevision = randomUUID();
|
|
116
224
|
if (event.type === 'tabs' && Array.isArray(event.tabs)) {
|
|
117
225
|
const active = event.tabs.find((tab) => Boolean(tab.active));
|
|
118
226
|
activeTabId = String(active?.tabId ?? active?.id ?? activeTabId);
|
|
119
227
|
}
|
|
120
|
-
|
|
228
|
+
let mapped = mapStreamEvent(event);
|
|
229
|
+
const activeOwner = activeTabId ? browserRunRegistry.ownerOf(activeTabId) : undefined;
|
|
230
|
+
if (runContext && activeTabId && activeOwner !== runContext.conversationKey
|
|
231
|
+
&& mapped && ['browser/frame', 'browser/url', 'browser/title', 'browser/navigation'].includes(mapped.t)) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (runContext && mapped?.t === 'browser/tabs') {
|
|
235
|
+
const claimed = new Set(browserRunRegistry.claimedTabs(runContext.conversationKey).map(String));
|
|
236
|
+
mapped = { ...mapped, tabs: mapped.tabs.filter((tab) => claimed.has(tab.id)) };
|
|
237
|
+
}
|
|
121
238
|
if (mapped?.t === 'browser/frame')
|
|
122
|
-
send({
|
|
239
|
+
send({
|
|
240
|
+
...mapped,
|
|
241
|
+
tabId: activeTabId || mapped.tabId,
|
|
242
|
+
pageRevision,
|
|
243
|
+
...(runContext ? { conversationKey: runContext.conversationKey, runId: runContext.runId } : {}),
|
|
244
|
+
});
|
|
123
245
|
else if (mapped)
|
|
124
246
|
send(mapped);
|
|
125
247
|
if (event.type === 'control_state') {
|
|
126
248
|
const state = event.state;
|
|
249
|
+
// 控制权移交给用户(手动接管或验证挑战)时淡出 AI 指针,避免“谁在操作”的混淆。
|
|
250
|
+
if (state?.owner === 'user')
|
|
251
|
+
stream.setAgentPointer({ x: 0, y: 0, visible: false });
|
|
127
252
|
if (state?.status === 'waiting_human' && state.reason !== 'manual') {
|
|
128
253
|
const summary = state.reason === 'captcha' ? '页面需要人工完成安全验证'
|
|
129
254
|
: state.reason === 'otp' ? '页面需要人工输入一次性验证码'
|
|
130
|
-
: state.reason === '
|
|
131
|
-
: state.reason === '
|
|
132
|
-
: '
|
|
255
|
+
: state.reason === 'password' ? '页面需要人工输入密码'
|
|
256
|
+
: state.reason === 'qr_login' ? '页面需要人工扫码登录'
|
|
257
|
+
: state.reason === 'login' ? '页面需要人工登录'
|
|
258
|
+
: state.reason === 'permission' ? '页面需要人工确认权限'
|
|
259
|
+
: state.reason === 'security_warning' ? '页面需要人工处理安全警告'
|
|
260
|
+
: '网站已暂停或拦截当前访问';
|
|
133
261
|
send({
|
|
134
262
|
t: 'browser/challenge/detected',
|
|
135
263
|
reason: state.reason,
|
|
@@ -151,6 +279,63 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
151
279
|
throw new Error((result.stderr || result.stdout || `exit ${result.code}`).trim());
|
|
152
280
|
return result.stdout.trim();
|
|
153
281
|
};
|
|
282
|
+
const requireContext = () => {
|
|
283
|
+
if (!runContext)
|
|
284
|
+
throw new Error('浏览器尚未绑定当前会话,请重新打开工作台');
|
|
285
|
+
return runContext;
|
|
286
|
+
};
|
|
287
|
+
const claimContextTab = async () => {
|
|
288
|
+
const context = requireContext();
|
|
289
|
+
const bin = await resolveAgentBrowserPath();
|
|
290
|
+
if (!bin)
|
|
291
|
+
throw new Error('未找到内置 agent-browser');
|
|
292
|
+
await ensureDaemon(sessionName);
|
|
293
|
+
const tabId = await ensureConversationTab({
|
|
294
|
+
context,
|
|
295
|
+
sessionName,
|
|
296
|
+
bin,
|
|
297
|
+
globals: sessionArgs(sessionName),
|
|
298
|
+
runner: spawnRunner,
|
|
299
|
+
});
|
|
300
|
+
activeTabId = tabId;
|
|
301
|
+
return tabId;
|
|
302
|
+
};
|
|
303
|
+
const createContextTab = async (url = 'about:blank') => {
|
|
304
|
+
const context = requireContext();
|
|
305
|
+
const bin = await resolveAgentBrowserPath();
|
|
306
|
+
if (!bin)
|
|
307
|
+
throw new Error('未找到内置 agent-browser');
|
|
308
|
+
await ensureDaemon(sessionName);
|
|
309
|
+
const tabId = await createConversationTab({
|
|
310
|
+
context,
|
|
311
|
+
sessionName,
|
|
312
|
+
bin,
|
|
313
|
+
globals: sessionArgs(sessionName),
|
|
314
|
+
runner: spawnRunner,
|
|
315
|
+
}, url);
|
|
316
|
+
activeTabId = tabId;
|
|
317
|
+
return tabId;
|
|
318
|
+
};
|
|
319
|
+
const runOnContextTab = async (args) => {
|
|
320
|
+
const tabId = await claimContextTab();
|
|
321
|
+
const bin = await resolveAgentBrowserPath();
|
|
322
|
+
if (!bin)
|
|
323
|
+
throw new Error('未找到内置 agent-browser');
|
|
324
|
+
const output = await browserService.exclusive({
|
|
325
|
+
sessionName,
|
|
326
|
+
bin,
|
|
327
|
+
runner: spawnRunner,
|
|
328
|
+
}, async (execute) => {
|
|
329
|
+
const switched = await execute([...sessionArgs(sessionName), 'tab', tabId]);
|
|
330
|
+
if (switched.code !== 0)
|
|
331
|
+
return switched;
|
|
332
|
+
return execute([...sessionArgs(sessionName), ...args]);
|
|
333
|
+
});
|
|
334
|
+
if (output.code !== 0) {
|
|
335
|
+
throw new Error((output.stderr || output.stdout || `exit ${output.code}`).trim());
|
|
336
|
+
}
|
|
337
|
+
return output.stdout.trim();
|
|
338
|
+
};
|
|
154
339
|
const ensureStarted = async () => {
|
|
155
340
|
const config = await configService.browser();
|
|
156
341
|
if (!config.enabled)
|
|
@@ -159,29 +344,41 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
159
344
|
await stream.connect();
|
|
160
345
|
return info;
|
|
161
346
|
};
|
|
347
|
+
// 改视口后重连查看者,让下一帧按新尺寸编码(screencast 尺寸绑定在查看者连接时刻)。
|
|
348
|
+
// 注意:标签切换/新建/关闭/导航不需要在这里重连——agent-browser daemon 在这些命令后会自己
|
|
349
|
+
// set_cdp_session_id + notify、让 screencast 重定向到新活动标签(见 actions.rs / stream/cdp_loop.rs)。
|
|
350
|
+
// 真正的坑是「链接点击开的新标签」不在 daemon 的同步清单里,那条路由前端「活动标签变化 → 补发 tab/switch」兜住(useBrowser.ts)。
|
|
351
|
+
const reconnectViewer = async () => {
|
|
352
|
+
if (stream.isConnected()) {
|
|
353
|
+
stream.disconnect();
|
|
354
|
+
await stream.connect();
|
|
355
|
+
}
|
|
356
|
+
};
|
|
162
357
|
const applyViewport = async (widthValue, heightValue) => {
|
|
163
358
|
const width = Math.max(320, Math.round(Number(widthValue)));
|
|
164
359
|
const height = Math.max(240, Math.round(Number(heightValue)));
|
|
165
360
|
if (!Number.isFinite(width) || !Number.isFinite(height))
|
|
166
361
|
throw new Error('无效的浏览器视口尺寸');
|
|
167
|
-
await
|
|
168
|
-
|
|
169
|
-
// active when the viewer connected. Reconnect only the viewer so the next
|
|
170
|
-
// frame is encoded at the new viewport without touching tabs or profile.
|
|
171
|
-
if (stream.isConnected()) {
|
|
172
|
-
stream.disconnect();
|
|
173
|
-
await stream.connect();
|
|
174
|
-
}
|
|
362
|
+
await runOnContextTab(['set', 'viewport', String(width), String(height)]);
|
|
363
|
+
await reconnectViewer();
|
|
175
364
|
};
|
|
176
365
|
const pick = async (x, y) => {
|
|
177
|
-
const value = parseJsonOutput(await
|
|
366
|
+
const value = parseJsonOutput(await runOnContextTab(['eval', pickScript(x, y)]));
|
|
178
367
|
if (!value || typeof value !== 'object')
|
|
179
368
|
return null;
|
|
180
369
|
return value;
|
|
181
370
|
};
|
|
182
371
|
stream.setPicker(pick);
|
|
372
|
+
// 用户指针输入的双通路路由状态 + 命令通路串行队列(见 routeUserMouse 头注)。
|
|
373
|
+
const pointerRoute = createPointerRouteState();
|
|
374
|
+
let mouseCmdChain = Promise.resolve();
|
|
375
|
+
const enqueueMouseCmd = (args) => {
|
|
376
|
+
// 串行保序:逐条 await 上一条再跑下一条;失败吞掉(拖拽单帧丢失不该中断整段手势)。
|
|
377
|
+
mouseCmdChain = mouseCmdChain.then(() => runOnContextTab(['mouse', ...args])).catch(() => { });
|
|
378
|
+
};
|
|
183
379
|
const result = (frame, ok, data, error) => send({
|
|
184
380
|
t: 'browser/result', requestId: frame.requestId, action: frame.t, ok,
|
|
381
|
+
...(runContext ? { conversationKey: runContext.conversationKey, runId: runContext.runId, tabId: activeTabId || undefined } : {}),
|
|
185
382
|
...(typeof data === 'string' ? { content: data } : data === undefined ? {} : { data }),
|
|
186
383
|
...(error ? { error } : {}),
|
|
187
384
|
});
|
|
@@ -191,12 +388,42 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
191
388
|
return;
|
|
192
389
|
try {
|
|
193
390
|
switch (frame.t) {
|
|
391
|
+
case 'browser/context/set': {
|
|
392
|
+
const conversationKey = String(frame.conversationKey ?? '').trim();
|
|
393
|
+
if (!conversationKey)
|
|
394
|
+
throw new Error('缺少浏览器会话标识');
|
|
395
|
+
runContext = browserRunRegistry.ensure({
|
|
396
|
+
conversationKey,
|
|
397
|
+
runId: typeof frame.runId === 'string' ? frame.runId : 'workbench',
|
|
398
|
+
profileId: 'default',
|
|
399
|
+
grants: ['observe', 'interact'],
|
|
400
|
+
});
|
|
401
|
+
const tabId = await claimContextTab();
|
|
402
|
+
send({
|
|
403
|
+
t: 'browser/context/changed',
|
|
404
|
+
requestId: frame.requestId,
|
|
405
|
+
conversationKey: runContext.conversationKey,
|
|
406
|
+
runId: runContext.runId,
|
|
407
|
+
tabId,
|
|
408
|
+
});
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
194
411
|
case 'browser/start': {
|
|
412
|
+
requireContext();
|
|
195
413
|
const info = await ensureStarted();
|
|
414
|
+
await claimContextTab();
|
|
196
415
|
const viewport = frame.viewport;
|
|
197
416
|
if (viewport?.width && viewport?.height)
|
|
198
417
|
await applyViewport(viewport.width, viewport.height);
|
|
199
|
-
send({
|
|
418
|
+
send({
|
|
419
|
+
t: 'browser/started',
|
|
420
|
+
requestId: frame.requestId,
|
|
421
|
+
streamPort: info.streamPort,
|
|
422
|
+
pid: info.pid,
|
|
423
|
+
sessionId: sessionName,
|
|
424
|
+
conversationKey: runContext?.conversationKey,
|
|
425
|
+
runId: runContext?.runId,
|
|
426
|
+
});
|
|
200
427
|
result(frame, true, info);
|
|
201
428
|
return;
|
|
202
429
|
}
|
|
@@ -217,10 +444,15 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
217
444
|
result(frame, true);
|
|
218
445
|
return;
|
|
219
446
|
case 'browser/control/get':
|
|
447
|
+
requireContext();
|
|
220
448
|
send({ t: 'browser/control/changed', state: stream.getControlState() });
|
|
221
449
|
return;
|
|
222
450
|
case 'browser/control/takeover':
|
|
223
|
-
stream.requestHuman('manual'
|
|
451
|
+
stream.requestHuman('manual', {
|
|
452
|
+
runId: runContext?.runId,
|
|
453
|
+
conversationKey: runContext?.conversationKey,
|
|
454
|
+
ownerId: 'local-owner',
|
|
455
|
+
});
|
|
224
456
|
result(frame, true, stream.getControlState());
|
|
225
457
|
return;
|
|
226
458
|
case 'browser/control/resume': {
|
|
@@ -228,53 +460,119 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
228
460
|
result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器接管请求已失效');
|
|
229
461
|
return;
|
|
230
462
|
}
|
|
231
|
-
case 'browser/control/stop':
|
|
232
|
-
stream.stopControl(typeof frame.resumeToken === 'string' ? frame.resumeToken : undefined);
|
|
233
|
-
result(frame,
|
|
463
|
+
case 'browser/control/stop': {
|
|
464
|
+
const ok = stream.stopControl(typeof frame.resumeToken === 'string' ? frame.resumeToken : undefined);
|
|
465
|
+
result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器接管请求已失效');
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
case 'human-intervention/resume': {
|
|
469
|
+
const ok = stream.resumeIntervention({
|
|
470
|
+
id: String(frame.interventionId ?? ''),
|
|
471
|
+
resumeToken: String(frame.resumeToken ?? ''),
|
|
472
|
+
ownerId: String(frame.ownerId ?? ''),
|
|
473
|
+
conversationKey: String(frame.conversationKey ?? ''),
|
|
474
|
+
runId: String(frame.runId ?? ''),
|
|
475
|
+
});
|
|
476
|
+
result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器人工介入请求已失效');
|
|
234
477
|
return;
|
|
478
|
+
}
|
|
479
|
+
case 'human-intervention/cancel': {
|
|
480
|
+
const ok = stream.cancelIntervention({
|
|
481
|
+
id: String(frame.interventionId ?? ''),
|
|
482
|
+
resumeToken: String(frame.resumeToken ?? ''),
|
|
483
|
+
ownerId: String(frame.ownerId ?? ''),
|
|
484
|
+
conversationKey: String(frame.conversationKey ?? ''),
|
|
485
|
+
runId: String(frame.runId ?? ''),
|
|
486
|
+
});
|
|
487
|
+
result(frame, ok, stream.getControlState(), ok ? undefined : '浏览器人工介入请求已失效');
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
235
490
|
case 'browser/user/input': {
|
|
491
|
+
requireContext();
|
|
492
|
+
await claimContextTab();
|
|
236
493
|
const type = String(frame.eventType ?? '');
|
|
237
|
-
if (type.startsWith('mouse'))
|
|
238
|
-
stream.send({ type: 'input_mouse', ...frame, t: undefined });
|
|
239
|
-
else
|
|
494
|
+
if (!type.startsWith('mouse')) {
|
|
240
495
|
stream.send({ type: 'input_keyboard', ...frame, t: undefined });
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
// 鼠标:hover/单击/滚轮走快通路 input_mouse;拖拽手势改走 daemon 带 buttons 的命令通路。
|
|
499
|
+
const plan = routeUserMouse(pointerRoute, frame, Date.now());
|
|
500
|
+
for (const f of plan.stream)
|
|
501
|
+
stream.send(f);
|
|
502
|
+
for (const args of plan.commands)
|
|
503
|
+
enqueueMouseCmd(args);
|
|
241
504
|
return;
|
|
242
505
|
}
|
|
243
506
|
case 'browser/navigate': {
|
|
507
|
+
requireContext();
|
|
244
508
|
await ensureStarted();
|
|
245
509
|
const url = normalizeUrl(String(frame.url ?? ''));
|
|
246
|
-
|
|
510
|
+
if (frame.newTab)
|
|
511
|
+
await createContextTab(url);
|
|
512
|
+
else {
|
|
513
|
+
await claimContextTab();
|
|
514
|
+
await run(['open', url]);
|
|
515
|
+
}
|
|
247
516
|
stream.setCurrentUrl(url);
|
|
248
517
|
result(frame, true);
|
|
249
518
|
return;
|
|
250
519
|
}
|
|
251
520
|
case 'browser/back':
|
|
252
|
-
await
|
|
521
|
+
await runOnContextTab(['back']);
|
|
253
522
|
result(frame, true);
|
|
254
523
|
return;
|
|
255
524
|
case 'browser/forward':
|
|
256
|
-
await
|
|
525
|
+
await runOnContextTab(['forward']);
|
|
257
526
|
result(frame, true);
|
|
258
527
|
return;
|
|
259
528
|
case 'browser/reload':
|
|
260
|
-
await
|
|
529
|
+
await runOnContextTab(['reload']);
|
|
261
530
|
result(frame, true);
|
|
262
531
|
return;
|
|
263
|
-
case 'browser/tab/new':
|
|
264
|
-
await
|
|
265
|
-
result(frame, true);
|
|
532
|
+
case 'browser/tab/new': {
|
|
533
|
+
const tabId = await createContextTab(frame.url ? normalizeUrl(String(frame.url)) : 'about:blank');
|
|
534
|
+
result(frame, true, { tabId });
|
|
266
535
|
return;
|
|
267
|
-
|
|
268
|
-
|
|
536
|
+
}
|
|
537
|
+
case 'browser/tab/close': {
|
|
538
|
+
const context = requireContext();
|
|
539
|
+
const tabId = String(frame.tabId ?? context.activeTabId ?? '');
|
|
540
|
+
if (!tabId)
|
|
541
|
+
throw new Error('无效的标签标识');
|
|
542
|
+
browserRunRegistry.assertTab(context, tabId);
|
|
543
|
+
await run(['tab', 'close', tabId]);
|
|
544
|
+
browserRunRegistry.releaseTab(context.conversationKey, tabId);
|
|
545
|
+
activeTabId = context.activeTabId ?? '';
|
|
269
546
|
result(frame, true);
|
|
270
547
|
return;
|
|
271
|
-
|
|
272
|
-
|
|
548
|
+
}
|
|
549
|
+
case 'browser/tab/switch': {
|
|
550
|
+
const context = requireContext();
|
|
551
|
+
const tabId = String(frame.tabId ?? '');
|
|
552
|
+
if (!tabId)
|
|
553
|
+
throw new Error('无效的标签标识');
|
|
554
|
+
browserRunRegistry.assertTab(context, tabId);
|
|
555
|
+
await run(['tab', tabId]);
|
|
556
|
+
context.activeTabId = tabId;
|
|
557
|
+
activeTabId = tabId;
|
|
273
558
|
result(frame, true);
|
|
274
559
|
return;
|
|
275
|
-
|
|
276
|
-
|
|
560
|
+
}
|
|
561
|
+
case 'browser/tabs': {
|
|
562
|
+
const context = requireContext();
|
|
563
|
+
const bin = await resolveAgentBrowserPath();
|
|
564
|
+
if (!bin)
|
|
565
|
+
throw new Error('未找到内置 agent-browser');
|
|
566
|
+
const tabs = await listBrowserTabs({
|
|
567
|
+
sessionName,
|
|
568
|
+
bin,
|
|
569
|
+
globals: sessionArgs(sessionName),
|
|
570
|
+
runner: spawnRunner,
|
|
571
|
+
});
|
|
572
|
+
const claimed = new Set(browserRunRegistry.claimedTabs(context.conversationKey));
|
|
573
|
+
result(frame, true, tabs.filter((tab) => claimed.has(tab.id)));
|
|
277
574
|
return;
|
|
575
|
+
}
|
|
278
576
|
case 'browser/pick': {
|
|
279
577
|
const element = await pick(Number(frame.x), Number(frame.y));
|
|
280
578
|
if (!element) {
|
|
@@ -291,7 +589,7 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
291
589
|
return;
|
|
292
590
|
}
|
|
293
591
|
case 'browser/mark/element': {
|
|
294
|
-
const raw = parseJsonOutput(await
|
|
592
|
+
const raw = parseJsonOutput(await runOnContextTab(['eval', `(() => { const el=document.querySelector(${JSON.stringify(String(frame.selector))}); if(!el)return null; const r=el.getBoundingClientRect(); return {ref:${JSON.stringify(String(frame.selector))},tag:el.tagName.toLowerCase(),text:String(el.innerText||el.textContent||'').trim().slice(0,1000),boundingBox:{x:r.x,y:r.y,width:r.width,height:r.height}} })()`]));
|
|
295
593
|
if (!raw || typeof raw !== 'object')
|
|
296
594
|
throw new Error('未找到该元素');
|
|
297
595
|
stream.markElement({ ...raw, label: typeof frame.label === 'string' ? frame.label : undefined, color: typeof frame.color === 'string' ? frame.color : undefined });
|
|
@@ -308,100 +606,100 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
308
606
|
result(frame, true);
|
|
309
607
|
return;
|
|
310
608
|
case 'browser/dialog/accept':
|
|
311
|
-
await
|
|
609
|
+
await runOnContextTab(frame.text ? ['dialog', 'accept', '--text', String(frame.text)] : ['dialog', 'accept']);
|
|
312
610
|
result(frame, true);
|
|
313
611
|
return;
|
|
314
612
|
case 'browser/dialog/dismiss':
|
|
315
|
-
await
|
|
613
|
+
await runOnContextTab(['dialog', 'dismiss']);
|
|
316
614
|
result(frame, true);
|
|
317
615
|
return;
|
|
318
616
|
case 'browser/snapshot': {
|
|
319
|
-
const tree = await
|
|
617
|
+
const tree = await runOnContextTab(['snapshot']);
|
|
320
618
|
send({ t: 'browser/snapshot', requestId: frame.requestId, tree });
|
|
321
619
|
return;
|
|
322
620
|
}
|
|
323
621
|
case 'browser/getContent': {
|
|
324
|
-
const text = await
|
|
622
|
+
const text = await runOnContextTab(['get', 'text', String(frame.selector ?? 'body')]);
|
|
325
623
|
send({ t: 'browser/content', requestId: frame.requestId, text });
|
|
326
624
|
return;
|
|
327
625
|
}
|
|
328
626
|
case 'browser/click':
|
|
329
|
-
await
|
|
627
|
+
await runOnContextTab(['click', String(frame.selector)]);
|
|
330
628
|
result(frame, true);
|
|
331
629
|
return;
|
|
332
630
|
case 'browser/fill':
|
|
333
|
-
await
|
|
631
|
+
await runOnContextTab(['fill', String(frame.selector), String(frame.value ?? '')]);
|
|
334
632
|
result(frame, true);
|
|
335
633
|
return;
|
|
336
634
|
case 'browser/type':
|
|
337
|
-
await
|
|
635
|
+
await runOnContextTab(['type', String(frame.selector), String(frame.value ?? '')]);
|
|
338
636
|
result(frame, true);
|
|
339
637
|
return;
|
|
340
638
|
case 'browser/hover':
|
|
341
|
-
await
|
|
639
|
+
await runOnContextTab(['hover', String(frame.selector)]);
|
|
342
640
|
result(frame, true);
|
|
343
641
|
return;
|
|
344
642
|
case 'browser/scroll': {
|
|
345
643
|
const args = frame.selector ? ['scrollintoview', String(frame.selector)] : ['scroll', String(frame.direction ?? 'down'), String(Math.abs(Number(frame.y ?? 600)))];
|
|
346
|
-
await
|
|
644
|
+
await runOnContextTab(args);
|
|
347
645
|
result(frame, true);
|
|
348
646
|
return;
|
|
349
647
|
}
|
|
350
648
|
case 'browser/select':
|
|
351
|
-
await
|
|
649
|
+
await runOnContextTab(['select', String(frame.selector), ...(Array.isArray(frame.value) ? frame.value.map(String) : [String(frame.value ?? '')])]);
|
|
352
650
|
result(frame, true);
|
|
353
651
|
return;
|
|
354
652
|
case 'browser/press':
|
|
355
|
-
await
|
|
653
|
+
await runOnContextTab(['press', String(frame.key)]);
|
|
356
654
|
result(frame, true);
|
|
357
655
|
return;
|
|
358
656
|
case 'browser/wait':
|
|
359
|
-
await
|
|
657
|
+
await runOnContextTab(frame.selector ? ['wait', String(frame.selector)] : frame.text ? ['wait', '--text', String(frame.text)] : ['wait', String(frame.ms ?? 500)]);
|
|
360
658
|
result(frame, true);
|
|
361
659
|
return;
|
|
362
660
|
case 'browser/eval':
|
|
363
|
-
result(frame, true, parseJsonOutput(await
|
|
661
|
+
result(frame, true, parseJsonOutput(await runOnContextTab(['eval', String(frame.js ?? '')])));
|
|
364
662
|
return;
|
|
365
663
|
case 'browser/upload':
|
|
366
|
-
await
|
|
664
|
+
await runOnContextTab(['upload', String(frame.selector), ...(Array.isArray(frame.files) ? frame.files.map(String) : [])]);
|
|
367
665
|
result(frame, true);
|
|
368
666
|
return;
|
|
369
667
|
case 'browser/drag':
|
|
370
|
-
await
|
|
668
|
+
await runOnContextTab(['drag', String(frame.fromSelector), String(frame.toSelector)]);
|
|
371
669
|
result(frame, true);
|
|
372
670
|
return;
|
|
373
671
|
case 'browser/screenshot': {
|
|
374
672
|
const args = ['screenshot', ...(frame.path ? [String(frame.path)] : []), ...(frame.annotate ? ['--annotate'] : []), ...(frame.fullPage ? ['--full'] : [])];
|
|
375
|
-
const output = await
|
|
673
|
+
const output = await runOnContextTab(args);
|
|
376
674
|
send({ t: 'browser/screenshot', requestId: frame.requestId, path: typeof frame.path === 'string' ? frame.path : undefined, data: output });
|
|
377
675
|
return;
|
|
378
676
|
}
|
|
379
677
|
case 'browser/pdf': {
|
|
380
|
-
const output = await
|
|
678
|
+
const output = await runOnContextTab(['pdf', String(frame.path ?? '')]);
|
|
381
679
|
result(frame, true, output);
|
|
382
680
|
return;
|
|
383
681
|
}
|
|
384
682
|
case 'browser/cookies/get':
|
|
385
|
-
send({ t: 'browser/cookies', requestId: frame.requestId, cookies: parseJsonOutput(await
|
|
683
|
+
send({ t: 'browser/cookies', requestId: frame.requestId, cookies: parseJsonOutput(await runOnContextTab(['cookies', 'get'])) ?? [] });
|
|
386
684
|
return;
|
|
387
685
|
case 'browser/cookies/clear':
|
|
388
|
-
await
|
|
686
|
+
await runOnContextTab(['cookies', 'clear']);
|
|
389
687
|
result(frame, true);
|
|
390
688
|
return;
|
|
391
689
|
case 'browser/device':
|
|
392
|
-
await
|
|
690
|
+
await runOnContextTab(frame.preset ? ['set', 'device', String(frame.preset)] : ['set', 'viewport', String(frame.width), String(frame.height)]);
|
|
393
691
|
result(frame, true);
|
|
394
692
|
return;
|
|
395
693
|
case 'browser/media':
|
|
396
|
-
await
|
|
694
|
+
await runOnContextTab(['set', 'media', String(frame.scheme ?? 'no-preference')]);
|
|
397
695
|
result(frame, true);
|
|
398
696
|
return;
|
|
399
697
|
case 'browser/record/start':
|
|
400
|
-
await
|
|
698
|
+
await runOnContextTab(['record', 'start', String(frame.path ?? '')]);
|
|
401
699
|
result(frame, true);
|
|
402
700
|
return;
|
|
403
701
|
case 'browser/record/stop':
|
|
404
|
-
result(frame, true, await
|
|
702
|
+
result(frame, true, await runOnContextTab(['record', 'stop']));
|
|
405
703
|
return;
|
|
406
704
|
case 'browser/debug/console':
|
|
407
705
|
case 'browser/debug/errors':
|
|
@@ -410,6 +708,7 @@ export function createBrowserBridge(send, sessionName = 'minimal-agent') {
|
|
|
410
708
|
case 'browser/debug/vitals':
|
|
411
709
|
case 'browser/debug/trace/start':
|
|
412
710
|
case 'browser/debug/trace/stop': {
|
|
711
|
+
await claimContextTab();
|
|
413
712
|
const browserConfig = await configService.browser();
|
|
414
713
|
if (!browserConfig.developerMode)
|
|
415
714
|
throw new Error('请先在“设置 → 浏览器”开启完整 CDP Developer Mode');
|