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
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* src/tools/webbrowser/agentBrowserPath.ts —— 解析 agent-browser 可执行文件 + 内置浏览器
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 内置 agent 浏览器底座(Step1):WebBrowser 工具 / skill 脚本 / 工作流 bash 步
|
|
6
|
+
* 共用同一份「二进制定位 + 浏览器降级」逻辑 —— 单一事实源,完全对标
|
|
7
|
+
* ripgrep 的 `src/tools/grep/rgPath.ts`。
|
|
8
|
+
*
|
|
9
|
+
* 引擎 = vercel-labs/agent-browser(原生 Rust CLI + CDP,已是 kakadeai 子模块,
|
|
10
|
+
* 只读引用)。它的原生二进制按 `agent-browser-<os>-<arch>[.exe]` 命名、从 GitHub
|
|
11
|
+
* releases 下载;我们像 vendor/ripgrep 一样把它放进 vendor/agent-browser/<arch>-<platform>/。
|
|
12
|
+
*
|
|
13
|
+
* ── agent-browser 二进制定位(按优先级,全程 existsSync 过滤)──
|
|
14
|
+
* ① MINIMAL_AGENT_BROWSER_PATH 环境变量(手动指定,调试最高优先)
|
|
15
|
+
* ② 项目自带 vendor/agent-browser/<arch>-<platform>/agent-browser(.exe)(默认,开箱即用)
|
|
16
|
+
* ③ 绿色版(bun --compile):exe 同级 vendor/agent-browser/...(compile 后 import.meta.url
|
|
17
|
+
* 是虚拟路径、② 命不中,绿色目录把 vendor/ 摆 exe 旁边从这捞回)
|
|
18
|
+
* ④ 系统 PATH 上的 agent-browser(用户自己 npm i -g / brew / cargo 装的)
|
|
19
|
+
* ⑤ 都没有 → null(调用方降级:返回可操作错误并提示回退 WebFetch)
|
|
20
|
+
*
|
|
21
|
+
* ── 浏览器(Chrome)分层降级(落实「opt2+opt3 融合」)──
|
|
22
|
+
* agent-browser 自己会:读 AGENT_BROWSER_EXECUTABLE_PATH → 自动探测系统
|
|
23
|
+
* Chrome/Brave/Edge/Playwright/Puppeteer → 缺则可 `agent-browser install` 下完整
|
|
24
|
+
* Chrome for Testing。我们只补**离线兜底**:当无系统浏览器且无法联网安装时,
|
|
25
|
+
* 用绿色版内置的轻量 chromium(resolveBundledChromium)保证「插上永远有浏览器」。
|
|
26
|
+
* dev/npm 下 vendor/chromium 不存在 → 返回 null → 不影响 agent-browser 原生探测。
|
|
27
|
+
*
|
|
28
|
+
* dev/npm 模式零副作用:execPath 指向 node/bun 二进制,其同级没有 vendor/;
|
|
29
|
+
* findPackageRoot 在源码/安装态下指向真实包根,vendor/agent-browser 不存在时
|
|
30
|
+
* existsSync 过滤掉 —— 与 rgPath/greenRoot 同一套「加性、命不中即丢弃」铁律。
|
|
31
|
+
*
|
|
32
|
+
* 可测性:核心解析 detectAgentBrowser / resolveBundledChromium 都接受可注入依赖
|
|
33
|
+
* (env/exists/siblingDir/packageRoot/trySpawn),默认走真实实现;单测注入假依赖
|
|
34
|
+
* 确定性覆盖每条优先级分支,不碰真实 fs、不用 mock.module(见项目测试约定)。
|
|
35
|
+
* ============================================================
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import { spawn } from 'node:child_process';
|
|
39
|
+
import { chmodSync, existsSync } from 'node:fs';
|
|
40
|
+
import { dirname, isAbsolute, resolve, win32 } from 'node:path';
|
|
41
|
+
|
|
42
|
+
import { execSiblingDir } from '../../utils/greenRoot.js';
|
|
43
|
+
import { findPackageRoot } from '../../utils/packageRoot.js';
|
|
44
|
+
import { sanitizeCredentialEnv } from '../../config/configService.js';
|
|
45
|
+
|
|
46
|
+
/** 可注入依赖(默认走真实实现,单测注入假实现)。 */
|
|
47
|
+
export interface ResolveDeps {
|
|
48
|
+
env: NodeJS.ProcessEnv;
|
|
49
|
+
exists: (p: string) => boolean;
|
|
50
|
+
/** 绿色版 exe 同级目录。 */
|
|
51
|
+
siblingDir: () => string;
|
|
52
|
+
/** 包根目录;找不到(compile 虚拟路径)返回 null。 */
|
|
53
|
+
packageRoot: () => string | null;
|
|
54
|
+
/** 试跑 `<cmd> --version`,退出码 0 即 true。 */
|
|
55
|
+
trySpawn: (cmd: string) => Promise<boolean>;
|
|
56
|
+
/** 平台/架构(注入便于测试跨平台命名)。 */
|
|
57
|
+
platform: NodeJS.Platform;
|
|
58
|
+
arch: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function realDeps(): ResolveDeps {
|
|
62
|
+
return {
|
|
63
|
+
env: process.env,
|
|
64
|
+
exists: existsSync,
|
|
65
|
+
siblingDir: execSiblingDir,
|
|
66
|
+
packageRoot: () => {
|
|
67
|
+
try {
|
|
68
|
+
return findPackageRoot(import.meta.url);
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
trySpawn: defaultTrySpawn,
|
|
74
|
+
platform: process.platform,
|
|
75
|
+
arch: process.arch,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let cachedBin: string | null | undefined;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 解析一次 agent-browser 二进制路径,结果缓存(同进程复用)。
|
|
83
|
+
* 返回 null 表示找不到(调用方需降级)。
|
|
84
|
+
*/
|
|
85
|
+
export async function resolveAgentBrowserPath(): Promise<string | null> {
|
|
86
|
+
if (cachedBin !== undefined) return cachedBin;
|
|
87
|
+
cachedBin = await detectAgentBrowser(realDeps());
|
|
88
|
+
return cachedBin;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** 仅供测试重置缓存。 */
|
|
92
|
+
export function _resetAgentBrowserCache(): void {
|
|
93
|
+
cachedBin = undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 把已解析到的 agent-browser 二进制所在目录前置进 PATH —— 让子进程(Bash 工具 /
|
|
98
|
+
* skill 脚本 / 工作流 bash 步)也能直接 `agent-browser ...`,实现 tools/skills/工作流
|
|
99
|
+
* **共用同一内置浏览器底座**。仅当解析到**绝对路径**(vendored/sibling/env)时生效;
|
|
100
|
+
* 解析到裸 'agent-browser'(已在 PATH)或 null(没装)时 no-op —— dev/npm 无 vendored
|
|
101
|
+
* 二进制时天然 no-op,与 greenRoot 同一套加性铁律。可纯函数化测试:注入 path/env。
|
|
102
|
+
*
|
|
103
|
+
* 注意:离线兜底的轻量 chromium 仅 WebBrowser 工具自动补 --executable-path 用;直接
|
|
104
|
+
* 经 CLI 调 agent-browser 的 skill/bash 走 agent-browser 自身的自动探测/在线安装。
|
|
105
|
+
*/
|
|
106
|
+
export async function ensureAgentBrowserOnPath(): Promise<void> {
|
|
107
|
+
applyBinToPath(await resolveAgentBrowserPath(), process.env, process.platform);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** 纯函数:把 bin 所在目录前置进 env.PATH(已含则跳过;非绝对路径/null 不动)。 */
|
|
111
|
+
export function applyBinToPath(
|
|
112
|
+
bin: string | null,
|
|
113
|
+
env: NodeJS.ProcessEnv,
|
|
114
|
+
platform: NodeJS.Platform,
|
|
115
|
+
): void {
|
|
116
|
+
if (!bin || bin === 'agent-browser') return;
|
|
117
|
+
const pathApi = platform === 'win32' ? win32 : { dirname, isAbsolute };
|
|
118
|
+
if (!pathApi.isAbsolute(bin)) return;
|
|
119
|
+
const dir = pathApi.dirname(bin);
|
|
120
|
+
const sep = platform === 'win32' ? ';' : ':';
|
|
121
|
+
const cur = env.PATH ?? '';
|
|
122
|
+
if (cur.split(sep).includes(dir)) return;
|
|
123
|
+
env.PATH = cur ? `${dir}${sep}${cur}` : dir;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** 纯解析(可注入依赖):按 ①→⑤ 优先级返回 agent-browser 二进制路径或 null。 */
|
|
127
|
+
export async function detectAgentBrowser(deps: ResolveDeps): Promise<string | null> {
|
|
128
|
+
const sub = subdir(deps);
|
|
129
|
+
const bin = binName(deps);
|
|
130
|
+
|
|
131
|
+
// ① 显式 env 覆盖
|
|
132
|
+
const fromEnv = deps.env.MINIMAL_AGENT_BROWSER_PATH;
|
|
133
|
+
if (fromEnv && deps.exists(fromEnv)) return fromEnv;
|
|
134
|
+
|
|
135
|
+
// ② 项目自带 vendored(默认路径,开箱即用)
|
|
136
|
+
const root = deps.packageRoot();
|
|
137
|
+
if (root) {
|
|
138
|
+
const vendored = resolve(root, 'vendor', 'agent-browser', sub, bin);
|
|
139
|
+
if (deps.exists(vendored)) {
|
|
140
|
+
ensureExecutable(vendored, deps.platform);
|
|
141
|
+
return vendored;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ③ 绿色版 exe 同级
|
|
146
|
+
const sibling = resolve(deps.siblingDir(), 'vendor', 'agent-browser', sub, bin);
|
|
147
|
+
if (deps.exists(sibling)) {
|
|
148
|
+
ensureExecutable(sibling, deps.platform);
|
|
149
|
+
return sibling;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ④ PATH 上的 agent-browser
|
|
153
|
+
if (await deps.trySpawn('agent-browser')) return 'agent-browser';
|
|
154
|
+
|
|
155
|
+
// ⑤ 找不到
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 绿色版离线兜底:内置轻量 chromium 的可执行路径。返回 null 表示没带
|
|
161
|
+
* (dev/npm 常态,或绿色版未打包 chromium)—— 此时交回 agent-browser 自动探测/在线安装。
|
|
162
|
+
*
|
|
163
|
+
* 约定布局:vendor/chromium/<arch>-<platform>/ 下放该平台 chromium,可执行名按平台
|
|
164
|
+
* 探测一组常见相对路径(不同 chromium 构建解包名不一,宁可多探几个)。
|
|
165
|
+
*/
|
|
166
|
+
export function resolveBundledChromium(deps: ResolveDeps = realDeps()): string | null {
|
|
167
|
+
const sub = subdir(deps);
|
|
168
|
+
const roots: string[] = [resolve(deps.siblingDir(), 'vendor', 'chromium', sub)];
|
|
169
|
+
const root = deps.packageRoot();
|
|
170
|
+
if (root) roots.push(resolve(root, 'vendor', 'chromium', sub));
|
|
171
|
+
|
|
172
|
+
for (const r of roots) {
|
|
173
|
+
for (const rel of chromiumExeCandidates(deps.platform)) {
|
|
174
|
+
const p = resolve(r, rel);
|
|
175
|
+
if (deps.exists(p)) {
|
|
176
|
+
ensureExecutable(p, deps.platform);
|
|
177
|
+
return p;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Prefer a user-installed stable browser executable while keeping KakadeAI's
|
|
186
|
+
* own profile directory. This improves site compatibility without touching
|
|
187
|
+
* the user's normal Chrome profile or attempting fingerprint evasion.
|
|
188
|
+
*/
|
|
189
|
+
export function resolveSystemBrowser(deps: ResolveDeps = realDeps()): string | null {
|
|
190
|
+
const explicit = deps.env.MINIMAL_AGENT_BROWSER_EXECUTABLE_PATH
|
|
191
|
+
?? deps.env.AGENT_BROWSER_EXECUTABLE_PATH;
|
|
192
|
+
if (explicit && deps.exists(explicit)) return explicit;
|
|
193
|
+
|
|
194
|
+
const home = deps.env.HOME ?? deps.env.USERPROFILE ?? '';
|
|
195
|
+
const candidates = deps.platform === 'darwin'
|
|
196
|
+
? [
|
|
197
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
198
|
+
'/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
|
199
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
200
|
+
home ? resolve(home, 'Applications/Google Chrome.app/Contents/MacOS/Google Chrome') : '',
|
|
201
|
+
]
|
|
202
|
+
: deps.platform === 'win32'
|
|
203
|
+
? [
|
|
204
|
+
deps.env.PROGRAMFILES ? resolve(deps.env.PROGRAMFILES, 'Google/Chrome/Application/chrome.exe') : '',
|
|
205
|
+
deps.env['PROGRAMFILES(X86)'] ? resolve(deps.env['PROGRAMFILES(X86)'], 'Microsoft/Edge/Application/msedge.exe') : '',
|
|
206
|
+
deps.env.LOCALAPPDATA ? resolve(deps.env.LOCALAPPDATA, 'Google/Chrome/Application/chrome.exe') : '',
|
|
207
|
+
]
|
|
208
|
+
: [
|
|
209
|
+
'/usr/bin/google-chrome-stable',
|
|
210
|
+
'/usr/bin/google-chrome',
|
|
211
|
+
'/usr/bin/microsoft-edge-stable',
|
|
212
|
+
'/usr/bin/chromium',
|
|
213
|
+
'/usr/bin/chromium-browser',
|
|
214
|
+
];
|
|
215
|
+
return candidates.find((candidate) => candidate && deps.exists(candidate)) ?? null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** vendor 子目录名 = <arch>-<platform>(对齐 rgPath.ts / build-green.ts 的 vendor 约定)。 */
|
|
219
|
+
function subdir(deps: Pick<ResolveDeps, 'arch' | 'platform'>): string {
|
|
220
|
+
return `${deps.arch}-${deps.platform}`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function binName(deps: Pick<ResolveDeps, 'platform'>): string {
|
|
224
|
+
return deps.platform === 'win32' ? 'agent-browser.exe' : 'agent-browser';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** 各平台 chromium 可执行的候选相对路径(解包布局因构建而异,逐个探)。 */
|
|
228
|
+
function chromiumExeCandidates(platform: NodeJS.Platform): string[] {
|
|
229
|
+
switch (platform) {
|
|
230
|
+
case 'win32':
|
|
231
|
+
return ['chrome.exe', 'chrome-headless-shell.exe'];
|
|
232
|
+
case 'darwin':
|
|
233
|
+
return [
|
|
234
|
+
'Chromium.app/Contents/MacOS/Chromium',
|
|
235
|
+
'Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing',
|
|
236
|
+
'chrome',
|
|
237
|
+
'chrome-headless-shell',
|
|
238
|
+
];
|
|
239
|
+
default: // linux
|
|
240
|
+
return ['chrome', 'chrome-headless-shell', 'chromium'];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Unix 上 git/tarball/cp 偶尔丢可执行位;Windows 不需要。失败忽略(后续 spawn 会响亮报错)。
|
|
246
|
+
*/
|
|
247
|
+
function ensureExecutable(path: string, platform: NodeJS.Platform): void {
|
|
248
|
+
if (platform === 'win32') return;
|
|
249
|
+
try {
|
|
250
|
+
chmodSync(path, 0o755);
|
|
251
|
+
} catch {
|
|
252
|
+
/* ignore */
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* 试 spawn `<cmd> --version`,退出码 0 即认为可用。
|
|
258
|
+
* 传命令名(非绝对路径)让 OS 解析 PATH;windowsHide 防弹窗;5s 兜底超时。
|
|
259
|
+
*/
|
|
260
|
+
function defaultTrySpawn(cmd: string): Promise<boolean> {
|
|
261
|
+
return new Promise((resolveP) => {
|
|
262
|
+
let settled = false;
|
|
263
|
+
const done = (ok: boolean) => {
|
|
264
|
+
if (settled) return;
|
|
265
|
+
settled = true;
|
|
266
|
+
resolveP(ok);
|
|
267
|
+
};
|
|
268
|
+
try {
|
|
269
|
+
const child = spawn(cmd, ['--version'], {
|
|
270
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
271
|
+
env: sanitizeCredentialEnv(),
|
|
272
|
+
windowsHide: true,
|
|
273
|
+
});
|
|
274
|
+
child.on('error', () => done(false));
|
|
275
|
+
child.on('close', (code) => done(code === 0));
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
try {
|
|
278
|
+
child.kill();
|
|
279
|
+
} catch {}
|
|
280
|
+
done(false);
|
|
281
|
+
}, 5_000);
|
|
282
|
+
} catch {
|
|
283
|
+
done(false);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
* ============================================================
|
|
11
11
|
*/
|
|
12
12
|
import { spawn } from 'node:child_process';
|
|
13
|
-
import {
|
|
13
|
+
import { randomUUID } from 'node:crypto';
|
|
14
|
+
import { chmod, mkdir, readdir, realpath, rm, stat } from 'node:fs/promises';
|
|
14
15
|
import os from 'node:os';
|
|
15
16
|
import path from 'node:path';
|
|
16
17
|
import { sanitizeCredentialEnv } from '../../config/configService.js';
|
|
18
|
+
import { pathContains, pathContainedByAny } from '../../utils/pathContains.js';
|
|
17
19
|
/**
|
|
18
20
|
* minimal-agent 进程级固定 session 名:隔离机器上其它 agent-browser 用法,
|
|
19
21
|
* 同时让本进程多次调用复用同一浏览器(与原 playwright「一 session 一 page」语义一致)。
|
|
@@ -38,11 +40,40 @@ export async function ensureBrowserProfile(profileId = 'default') {
|
|
|
38
40
|
export async function browserGlobalArgs(sessionName = BROWSER_SESSION, profileId = 'default') {
|
|
39
41
|
return [...sessionArgs(sessionName), '--profile', await ensureBrowserProfile(profileId)];
|
|
40
42
|
}
|
|
41
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* 默认 spawn 运行器:收集 stdout/stderr 后结算;spawn 抛错也 resolve 成失败。
|
|
45
|
+
*
|
|
46
|
+
* ⚠️ 以 **'exit'(进程退出)为准结算,而非死等 'close'(全部 stdio 流关闭)**——这是「桌面首次
|
|
47
|
+
* 用浏览器卡死」的真根因修复:agent-browser 首次 `open` 会拉起一个 **detached daemon**,daemon
|
|
48
|
+
* 继承并长期攥着本进程给 client 的 stdout/stderr **pipe** 写端 → Node 的 `'close'` 事件**永不触发**
|
|
49
|
+
* → 若死等 'close',spawnRunner 永久挂起(实测 client 已 `exit code=0 @800ms`,`close` 却 never),
|
|
50
|
+
* 连 AbortSignal 杀了 client 都没用(close 仍在等被 daemon 攥着的 pipe)。
|
|
51
|
+
* 正常命令(连既有 daemon、不派生)'close' 紧随 'exit' → 走 'close' 拿完整输出;只有拉 daemon 的
|
|
52
|
+
* 命令走 'exit' + 短宽限兜底(此时输出已写完、daemon 只是攥着空 pipe)。abort 同理经 'exit' 及时结算。
|
|
53
|
+
*/
|
|
42
54
|
export const spawnRunner = (bin, args, signal) => new Promise((resolveP) => {
|
|
43
55
|
let stdout = '';
|
|
44
56
|
let stderr = '';
|
|
57
|
+
let settled = false;
|
|
58
|
+
let graceTimer = null;
|
|
45
59
|
let child;
|
|
60
|
+
const finish = (code, errMsg) => {
|
|
61
|
+
if (settled)
|
|
62
|
+
return;
|
|
63
|
+
settled = true;
|
|
64
|
+
if (graceTimer)
|
|
65
|
+
clearTimeout(graceTimer);
|
|
66
|
+
// 主动释放父侧 pipe 读端(daemon 攥着写端、我们已拿到结果,不再依赖它关闭)。
|
|
67
|
+
try {
|
|
68
|
+
child?.stdout?.destroy();
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
71
|
+
try {
|
|
72
|
+
child?.stderr?.destroy();
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
resolveP({ code: code ?? -1, stdout, stderr: stderr || errMsg || '' });
|
|
76
|
+
};
|
|
46
77
|
try {
|
|
47
78
|
child = spawn(bin, args, {
|
|
48
79
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -59,14 +90,186 @@ export const spawnRunner = (bin, args, signal) => new Promise((resolveP) => {
|
|
|
59
90
|
child.stdout?.on('data', (c) => (stdout += c));
|
|
60
91
|
child.stderr?.setEncoding('utf8');
|
|
61
92
|
child.stderr?.on('data', (c) => (stderr += c));
|
|
62
|
-
child.on('error', (e) =>
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
child.on('
|
|
93
|
+
child.on('error', (e) => finish(-1, e instanceof Error ? e.message : String(e)));
|
|
94
|
+
// 正常路径:'close' 紧随 'exit'(pipe 关闭)→ 以完整输出立即结算,并清掉宽限计时器。
|
|
95
|
+
child.on('close', (code) => finish(code));
|
|
96
|
+
// 拉 daemon 的命令:daemon 继承 pipe → 'close' 永不来。以 'exit' 为准,给一小段宽限等 'close'
|
|
97
|
+
// (正常命令会在宽限内更早经 'close' 结算,不丢输出);超时则强制结算,不再无限等 pipe。
|
|
98
|
+
child.on('exit', (code) => {
|
|
99
|
+
if (settled)
|
|
100
|
+
return;
|
|
101
|
+
graceTimer = setTimeout(() => finish(code), 500);
|
|
102
|
+
});
|
|
68
103
|
});
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
104
|
+
/**
|
|
105
|
+
* 有界执行一次 agent-browser 命令:在 spawnRunner 之上加「超时 + 可中断」。
|
|
106
|
+
* 到 timeoutMs 或父 signal abort 即掐断子进程(spawnRunner 拿到 aborted signal → kill →
|
|
107
|
+
* close → resolve,不会挂),返回结果额外带 timedOut/aborted 标记,供调用方产出可操作错误
|
|
108
|
+
* 而不是把「被超时/中断杀掉」误当普通失败。timeoutMs 省略或 ≤0 则只受父 signal 约束。
|
|
109
|
+
*/
|
|
110
|
+
export async function runBounded(bin, args, opts = {}, runner = spawnRunner) {
|
|
111
|
+
const ac = new AbortController();
|
|
112
|
+
let timedOut = false;
|
|
113
|
+
const onParent = () => ac.abort(opts.signal?.reason);
|
|
114
|
+
const timer = opts.timeoutMs && opts.timeoutMs > 0
|
|
115
|
+
? setTimeout(() => {
|
|
116
|
+
timedOut = true;
|
|
117
|
+
ac.abort();
|
|
118
|
+
}, opts.timeoutMs)
|
|
119
|
+
: null;
|
|
120
|
+
if (opts.signal) {
|
|
121
|
+
if (opts.signal.aborted)
|
|
122
|
+
ac.abort(opts.signal.reason);
|
|
123
|
+
else
|
|
124
|
+
opts.signal.addEventListener('abort', onParent, { once: true });
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const r = await runner(bin, args, ac.signal);
|
|
128
|
+
const abortedByParent = Boolean(opts.signal?.aborted) && !timedOut;
|
|
129
|
+
return {
|
|
130
|
+
...r,
|
|
131
|
+
...(timedOut ? { timedOut: true } : {}),
|
|
132
|
+
...(abortedByParent ? { aborted: true } : {}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
if (timer)
|
|
137
|
+
clearTimeout(timer);
|
|
138
|
+
opts.signal?.removeEventListener('abort', onParent);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 浏览器产物(截图 / PDF / 录像 / trace)的托管目录。
|
|
143
|
+
*
|
|
144
|
+
* 单独一层目录而不是直接扔 `os.tmpdir()`,是为了让「这些文件归我们管」这件事成立:
|
|
145
|
+
* 有明确边界才谈得上定期清理,也才谈得上把它当成输出路径的默认允许根。
|
|
146
|
+
*/
|
|
147
|
+
export function browserArtifactDir() {
|
|
148
|
+
return path.join(os.tmpdir(), 'kakadeai-browser-artifacts');
|
|
149
|
+
}
|
|
150
|
+
/** 产物保留时长。超过就在下一次生成产物时顺手清掉。 */
|
|
151
|
+
const ARTIFACT_TTL_MS = 30 * 60_000;
|
|
152
|
+
/**
|
|
153
|
+
* 清掉过期产物。
|
|
154
|
+
*
|
|
155
|
+
* 在**生成前**做而不是退出时做:进程可能被 kill、可能崩,「退出时清理」恰好在这些情况下
|
|
156
|
+
* 不执行,于是磁盘上留下的正是最不该留的那批。失败一律忽略——清理问题绝不能让一次截图失败。
|
|
157
|
+
*
|
|
158
|
+
* ⚠️ 这里之前**完全没有清理**:开了识图后每次 navigate/snapshot 都写一张 PNG 到 tmp,
|
|
159
|
+
* 永不删除。而浏览器截图拍的是用户已登录的页面,敏感度不低于桌面截图。
|
|
160
|
+
*/
|
|
161
|
+
async function pruneStaleArtifacts(dir) {
|
|
162
|
+
try {
|
|
163
|
+
const cutoff = Date.now() - ARTIFACT_TTL_MS;
|
|
164
|
+
const entries = await readdir(dir);
|
|
165
|
+
await Promise.all(entries.map(async (name) => {
|
|
166
|
+
const target = path.join(dir, name);
|
|
167
|
+
try {
|
|
168
|
+
const info = await stat(target);
|
|
169
|
+
if (info.mtimeMs < cutoff)
|
|
170
|
+
await rm(target, { force: true, recursive: true });
|
|
171
|
+
}
|
|
172
|
+
catch { /* 单个文件清不掉不影响其它 */ }
|
|
173
|
+
}));
|
|
174
|
+
}
|
|
175
|
+
catch { /* 目录不存在或不可读:没什么可清的 */ }
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 生成一个托管的产物输出路径,并确保目录存在、旧产物已清理。
|
|
179
|
+
*
|
|
180
|
+
* 文件名带 pid + 随机数:`Date.now()` 单独用会在同一毫秒内两次调用时撞名
|
|
181
|
+
* (两个并发截图互相覆盖,症状是「截出来的图不是那一刻的画面」)。
|
|
182
|
+
*/
|
|
183
|
+
export async function createArtifactPath(prefix = 'browser', ext = 'png') {
|
|
184
|
+
const dir = browserArtifactDir();
|
|
185
|
+
await mkdir(dir, { recursive: true, mode: 0o700 });
|
|
186
|
+
if (process.platform !== 'win32')
|
|
187
|
+
await chmod(dir, 0o700).catch(() => undefined);
|
|
188
|
+
await pruneStaleArtifacts(dir);
|
|
189
|
+
const unique = `${Date.now()}-${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
190
|
+
return path.join(dir, `${prefix}-${unique}.${ext}`);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* 允许 `navigate` / `tab new` 打开的 scheme。
|
|
194
|
+
*
|
|
195
|
+
* 白名单而不是黑名单:新 scheme 层出不穷,漏一个就等于放行。
|
|
196
|
+
* 明确拒绝的两类各有理由——
|
|
197
|
+
* · `javascript:` 是在页面里执行代码,那条路必须走 `eval`(受 Developer Mode 约束),
|
|
198
|
+
* 不能靠一个看起来像"打开网址"的动作绕过去;
|
|
199
|
+
* · `data:` 可以直接构造一个带脚本的文档,等价于同一件事。
|
|
200
|
+
*/
|
|
201
|
+
const ALLOWED_URL_SCHEMES = new Set(['http', 'https', 'about', 'file']);
|
|
202
|
+
/**
|
|
203
|
+
* 校验模型给的**输出**路径(截图 / PDF / 录像 / trace 落在哪)。
|
|
204
|
+
*
|
|
205
|
+
* ⚠️ 这里之前完全没有校验:`input.path` 由模型给出、直达子进程,等于一个不受限的
|
|
206
|
+
* 任意文件写入原语——可以覆盖项目文件、写进 `~/.ssh/`、覆盖配置。刺眼的是**同一个
|
|
207
|
+
* 文件里读方向做得很好**(`upload` 有 realpath + 包含判定),写方向一点没管。这个
|
|
208
|
+
* 不对称是无意的:防的时候只想到了"读进来"。
|
|
209
|
+
*
|
|
210
|
+
* 两道判据:
|
|
211
|
+
* ① 必须落在允许根之内(托管产物目录 / 工作目录 / 本次任务批准的文件范围);
|
|
212
|
+
* ② **不允许静默覆盖托管目录之外的已有文件**——把截图写成 `package.json` 不该是
|
|
213
|
+
* 一次工具调用能顺手做到的事。
|
|
214
|
+
*
|
|
215
|
+
* 目标文件通常还不存在,所以 realpath 走的是**父目录**;父目录不存在直接拒绝,
|
|
216
|
+
* 而不是替调用方创建——凭一个路径参数就造目录树同样是越权。
|
|
217
|
+
*/
|
|
218
|
+
export async function validateArtifactOutputPath(candidate, allowedRoots) {
|
|
219
|
+
const absolute = path.isAbsolute(candidate) ? candidate : path.resolve(candidate);
|
|
220
|
+
const parent = path.dirname(absolute);
|
|
221
|
+
let realParent;
|
|
222
|
+
try {
|
|
223
|
+
realParent = await realpath(parent);
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return { ok: false, error: `输出目录不存在:${parent}` };
|
|
227
|
+
}
|
|
228
|
+
const roots = await Promise.all(allowedRoots.map(async (root) => {
|
|
229
|
+
try {
|
|
230
|
+
return await realpath(root);
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return path.resolve(root);
|
|
234
|
+
}
|
|
235
|
+
}));
|
|
236
|
+
if (!pathContainedByAny(roots, realParent)) {
|
|
237
|
+
return {
|
|
238
|
+
ok: false,
|
|
239
|
+
error: `输出路径超出允许范围:${absolute}\n`
|
|
240
|
+
+ `允许写入:${roots.join('、')}\n`
|
|
241
|
+
+ '省略 path 参数即可写到托管的临时目录。',
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
const managed = await realpath(browserArtifactDir()).catch(() => browserArtifactDir());
|
|
245
|
+
if (!pathContains(managed, realParent)) {
|
|
246
|
+
const exists = await stat(path.join(realParent, path.basename(absolute)))
|
|
247
|
+
.then(() => true)
|
|
248
|
+
.catch(() => false);
|
|
249
|
+
if (exists) {
|
|
250
|
+
return {
|
|
251
|
+
ok: false,
|
|
252
|
+
error: `目标文件已存在,拒绝静默覆盖:${absolute}。请换一个文件名,或省略 path 写到临时目录。`,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return { ok: true, path: path.join(realParent, path.basename(absolute)) };
|
|
257
|
+
}
|
|
258
|
+
export function isAllowedBrowserScheme(value) {
|
|
259
|
+
const match = /^([a-z][a-z0-9+.-]*):/i.exec(value.trim());
|
|
260
|
+
if (!match)
|
|
261
|
+
return true; // 无 scheme → normalizeUrl 会补 https://
|
|
262
|
+
return ALLOWED_URL_SCHEMES.has(match[1].toLowerCase());
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* 把用户/模型给的地址归一化成 agent-browser `open`/`tab new` 能吃的完整 URL:
|
|
266
|
+
* 已带 scheme(http:/https:/about:/file: 等)原样返回;否则补 `https://`。
|
|
267
|
+
* 工具(navigate/tabNew)与 web 桥(browser/navigate)共用这一份,杜绝「两处两套行为」
|
|
268
|
+
* ——曾出现桥归一化、工具原样透传 `open www.baidu.com` 导致无 scheme 不导航。
|
|
269
|
+
*/
|
|
270
|
+
export function normalizeUrl(value) {
|
|
271
|
+
const input = value.trim();
|
|
272
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(input))
|
|
273
|
+
return input;
|
|
274
|
+
return `https://${input}`;
|
|
72
275
|
}
|