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,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/skill.ts —— skill 步骤执行器
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* v0.9 重构:不再使用独立 subHistory 隔离子循环,而是委托主 TAOR 引擎
|
|
6
|
+
* (runQuery / src/loop.ts)在共享 ctx.history 上执行。
|
|
7
|
+
*
|
|
8
|
+
* 实现要点:
|
|
9
|
+
* - 双源查找:cwd/skills/<name>/SKILL.md 优先,packageRoot/skills/ fallback
|
|
10
|
+
* - SKILL.md body 作为用户提示的一部分(系统提示词已在 history[0])
|
|
11
|
+
* - 执行结果直接写入共享 ctx.history,上下文自然积累
|
|
12
|
+
* - 流式转发:runQuery yield 的事件直接透传给 UI
|
|
13
|
+
* - maxTurns 可在 step 里覆盖(默认 25)
|
|
14
|
+
*
|
|
15
|
+
* capture:{ text: var_name } / { result: var_name }
|
|
16
|
+
* ============================================================
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { readFile, readdir } from 'node:fs/promises';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
type LoopEvent,
|
|
24
|
+
getResourceSearchPaths,
|
|
25
|
+
} from '../../../../src/plugin-sdk.js';
|
|
26
|
+
import {
|
|
27
|
+
describeLlmFailure,
|
|
28
|
+
describeMaxTurnsCutoff,
|
|
29
|
+
effectiveGoalAnchor,
|
|
30
|
+
runStepQuery,
|
|
31
|
+
} from '../agentCommon.js';
|
|
32
|
+
import { interpolate } from '../expressions.js';
|
|
33
|
+
import { effectiveWorkflowCwd } from '../toolRuntime.js';
|
|
34
|
+
import type { RunContext, StepDef, StepResult, VarStack } from '../types.js';
|
|
35
|
+
|
|
36
|
+
function stripFrontmatter(content: string): string {
|
|
37
|
+
return content.replace(/^---\n[\s\S]*?\n---\n?/, '');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseFrontmatterName(content: string): string | null {
|
|
41
|
+
const m = content.match(/^---\n([\s\S]*?)\n---/);
|
|
42
|
+
if (!m) return null;
|
|
43
|
+
const nm = m[1].match(/^name:\s*(.+)$/m);
|
|
44
|
+
if (!nm) return null;
|
|
45
|
+
return nm[1].trim().replace(/^["']|["']$/g, '');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function findSkillFile(
|
|
49
|
+
skillName: string,
|
|
50
|
+
cwd: string,
|
|
51
|
+
): Promise<string | null> {
|
|
52
|
+
const roots = getResourceSearchPaths('skills', import.meta.url, cwd);
|
|
53
|
+
|
|
54
|
+
for (const root of roots) {
|
|
55
|
+
let entries: { name: string; isDirectory: () => boolean }[];
|
|
56
|
+
try {
|
|
57
|
+
entries = await readdir(root, { withFileTypes: true });
|
|
58
|
+
} catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
for (const e of entries) {
|
|
62
|
+
if (!e.isDirectory()) continue;
|
|
63
|
+
const skillFile = join(root, e.name, 'SKILL.md');
|
|
64
|
+
if (e.name === skillName) return skillFile;
|
|
65
|
+
try {
|
|
66
|
+
const md = await readFile(skillFile, 'utf8');
|
|
67
|
+
if (parseFrontmatterName(md) === skillName) return skillFile;
|
|
68
|
+
} catch {}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function* execSkillStep(
|
|
75
|
+
step: StepDef,
|
|
76
|
+
vars: VarStack,
|
|
77
|
+
ctx: RunContext,
|
|
78
|
+
): AsyncGenerator<LoopEvent, StepResult, void> {
|
|
79
|
+
if (!step.skill) throw new Error(`step ${step.id}: 缺少 skill 字段`);
|
|
80
|
+
const skillName = interpolate(step.skill, vars);
|
|
81
|
+
|
|
82
|
+
const skillFile = await findSkillFile(skillName, effectiveWorkflowCwd(ctx));
|
|
83
|
+
if (!skillFile) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`step ${step.id}: 未找到 skill "${skillName}"(cwd/skills/ 与 packageRoot/skills/ 双源均未命中)`,
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const md = await readFile(skillFile, 'utf8');
|
|
89
|
+
const body = stripFrontmatter(md).trim();
|
|
90
|
+
|
|
91
|
+
// 构造用户提示:skill 指令 + 步骤 input
|
|
92
|
+
// 系统提示词已在 history[0] 中(含完整 skill 列表和描述),
|
|
93
|
+
// 这里不需要再拼 system message——把 SKILL.md body 作为操作指令即可
|
|
94
|
+
const missing: string[] = [];
|
|
95
|
+
const userInput = step.input
|
|
96
|
+
? interpolate(step.input, vars, { onMissing: (e) => missing.push(e) })
|
|
97
|
+
: `请按以下 SKILL "${skillName}" 的指示完成任务。`;
|
|
98
|
+
|
|
99
|
+
const fullPrompt = `【执行 Skill:${skillName}】\n\n${body}\n\n---\n\n当前任务:\n${userInput}`;
|
|
100
|
+
|
|
101
|
+
// 通用目标锚定(原始目标 + 补充要求):确保 skill 执行时也不偏离
|
|
102
|
+
const anchor = effectiveGoalAnchor(ctx);
|
|
103
|
+
const effectivePrompt = anchor ? `${anchor}\n\n${fullPrompt}` : fullPrompt;
|
|
104
|
+
|
|
105
|
+
const maxTurns = step.maxTurns ?? 25;
|
|
106
|
+
|
|
107
|
+
if (missing.length > 0) {
|
|
108
|
+
yield {
|
|
109
|
+
type: 'warning',
|
|
110
|
+
message: `step "${step.id}": 模板变量未定义,已按空串插值:${[...new Set(missing)].map((m) => `\${${m}}`).join('、')}(裸名请用 inputs.<name> 或先 capture/set)`,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 委托 TAOR 引擎在共享 history 上执行(共享消费层 runStepQuery)。
|
|
115
|
+
// suppressTurnDone:turn_done 是 runQuery 单次调用的终结标记,不是 workflow 终结,
|
|
116
|
+
// 外泄会导致 gateway broker / -p json 模式误判 workflow 中途结束。
|
|
117
|
+
const { rawText, aborted, sawLlmError, sawMaxTurns, llmErrorDetail } =
|
|
118
|
+
yield* runStepQuery(effectivePrompt, step, ctx, {
|
|
119
|
+
maxTurns,
|
|
120
|
+
suppressTurnDone: true,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const trimmed = rawText.trim();
|
|
124
|
+
|
|
125
|
+
// P0-1:LLM 失败(超时/网络错)且本步无任何产出 → 抛异常,触发 runner 的 max_retries 重跑。
|
|
126
|
+
// 用户中断(aborted)不该被当成可重试失败,按现状返回空结果即可。
|
|
127
|
+
if (!trimmed && sawLlmError && !aborted) {
|
|
128
|
+
throw new Error(describeLlmFailure(step.id, llmErrorDetail));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 撞 maxTurns 截断 → 截断时产出不可信,抛可重试失败(续作语义,同 agent.ts)
|
|
132
|
+
if (sawMaxTurns && !aborted) {
|
|
133
|
+
throw new Error(describeMaxTurnsCutoff(step.id, maxTurns));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
raw: { text: trimmed, result: trimmed },
|
|
138
|
+
preview: trimmed.length > 200 ? `${trimmed.slice(0, 200)}...` : trimmed,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
@@ -25,12 +25,16 @@ import { existsSync } from 'node:fs';
|
|
|
25
25
|
import { resolve } from 'node:path';
|
|
26
26
|
import { executeTool, getToolByName, recordRead, } from '../../../../src/plugin-sdk.js';
|
|
27
27
|
import { interpolateDeep } from '../expressions.js';
|
|
28
|
+
import { buildWorkflowToolContext, effectiveWorkflowCwd, } from '../toolRuntime.js';
|
|
28
29
|
export async function* execToolStep(step, vars, ctx) {
|
|
29
30
|
if (!step.tool)
|
|
30
31
|
throw new Error(`step ${step.id}: 缺少 tool 字段`);
|
|
31
32
|
const tool = getToolByName(step.tool);
|
|
32
33
|
if (!tool)
|
|
33
34
|
throw new Error(`step ${step.id}: 未知工具 "${step.tool}"`);
|
|
35
|
+
if (!ctx.tools.some((available) => available.name === tool.name)) {
|
|
36
|
+
throw new Error(`step ${step.id}: 工具 "${tool.name}" 不在当前宿主授权的 Workflow 工具集中`);
|
|
37
|
+
}
|
|
34
38
|
// 未定义变量插值可见化(args 里静默空串会让工具拿到空路径/空内容)
|
|
35
39
|
const missing = [];
|
|
36
40
|
const args = interpolateDeep(step.args ?? {}, vars, {
|
|
@@ -53,20 +57,69 @@ export async function* execToolStep(step, vars, ctx) {
|
|
|
53
57
|
argsFriendly: friendlyToolDesc(tool.name, args),
|
|
54
58
|
};
|
|
55
59
|
// ════ 声明产物覆盖判定(解 Write/Edit 的 pre-read 守卫) ════
|
|
56
|
-
// 内核写类工具有「文件已存在必须先 Read」守卫(fileState
|
|
57
|
-
// 跨进程 / resume /
|
|
60
|
+
// 内核写类工具有「文件已存在必须先 Read」守卫(fileState 按会话隔离,
|
|
61
|
+
// 跨进程 / resume / 残留旧产物时可能为空)。确定性 tool 步的 args 是 yaml 作者
|
|
58
62
|
// 写死的,模型没有机会先 Read —— 目标文件若是工作流**声明的产物**
|
|
59
63
|
// (def 级 + step 级 artifacts:,= 工作流自己拥有、本就要覆盖的文件),
|
|
60
64
|
// 这里自动 pre-Read 一次解除守卫(管线动作,不 yield 事件、结果丢弃)。
|
|
61
65
|
// 非声明产物的盲写保护原样生效;pre-Read 失败也不拦,让写工具自己报错。
|
|
62
66
|
await preReadDeclaredArtifact(tool, args, step, ctx);
|
|
63
|
-
|
|
67
|
+
// 宿主能力按 `uses:` 切片后转发。`executeTool` 的第四参此前从未传过 ——
|
|
68
|
+
// 这正是「workflow 里 ComputerUse 恒失败」的末端表现。
|
|
69
|
+
const pendingProgress = [];
|
|
70
|
+
let wakeProgress;
|
|
71
|
+
const toolContext = buildWorkflowToolContext(step, ctx, toolCallId, (message, detail) => {
|
|
72
|
+
pendingProgress.push({
|
|
73
|
+
type: 'tool_progress',
|
|
74
|
+
toolName: tool.name,
|
|
75
|
+
toolCallId,
|
|
76
|
+
message,
|
|
77
|
+
detail,
|
|
78
|
+
});
|
|
79
|
+
wakeProgress?.();
|
|
80
|
+
});
|
|
81
|
+
if ('error' in toolContext) {
|
|
82
|
+
throw new Error(`step ${step.id}: ${toolContext.error}`);
|
|
83
|
+
}
|
|
84
|
+
const dispatch = ctx.executeTool ?? executeTool;
|
|
85
|
+
let settled = false;
|
|
86
|
+
let result;
|
|
87
|
+
void dispatch(tool.name, argsJson, ctx.signal, toolContext)
|
|
88
|
+
.then((value) => {
|
|
89
|
+
result = value;
|
|
90
|
+
})
|
|
91
|
+
.catch((error) => {
|
|
92
|
+
result = {
|
|
93
|
+
ok: false,
|
|
94
|
+
error: error instanceof Error ? error.message : String(error),
|
|
95
|
+
};
|
|
96
|
+
})
|
|
97
|
+
.finally(() => {
|
|
98
|
+
settled = true;
|
|
99
|
+
wakeProgress?.();
|
|
100
|
+
});
|
|
101
|
+
while (!settled || pendingProgress.length > 0) {
|
|
102
|
+
const progress = pendingProgress.shift();
|
|
103
|
+
if (progress) {
|
|
104
|
+
yield progress;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
await new Promise((resolveWake) => {
|
|
108
|
+
wakeProgress = resolveWake;
|
|
109
|
+
if (settled || pendingProgress.length > 0)
|
|
110
|
+
resolveWake();
|
|
111
|
+
});
|
|
112
|
+
wakeProgress = undefined;
|
|
113
|
+
}
|
|
114
|
+
if (!result)
|
|
115
|
+
throw new Error(`step ${step.id}: 工具执行未返回结果`);
|
|
64
116
|
yield {
|
|
65
117
|
type: 'tool_end',
|
|
66
118
|
toolName: tool.name,
|
|
67
119
|
toolCallId,
|
|
68
120
|
ok: result.ok,
|
|
69
121
|
content: result.ok ? result.content : result.error,
|
|
122
|
+
metadata: result.metadata,
|
|
70
123
|
};
|
|
71
124
|
if (!result.ok) {
|
|
72
125
|
throw new Error(result.error);
|
|
@@ -85,8 +138,24 @@ export async function* execToolStep(step, vars, ctx) {
|
|
|
85
138
|
timestamp: Date.now(),
|
|
86
139
|
id: crypto.randomUUID(),
|
|
87
140
|
});
|
|
141
|
+
// ⚠️ 工具返回的图片**不能丢**。此前这里只取 content,`visionImages` 被静默丢弃 ——
|
|
142
|
+
// 于是任何「截图/看图」类工作流都拿不到产物,而且不会报错,只是后面的评估步没图可看。
|
|
143
|
+
// 取路径而不是整个 ImageInputSpec:yaml 侧要的是能 capture、能传给 llm 步 `images:`
|
|
144
|
+
// 的字符串;结构体传下去反而要每个消费方各自解包。
|
|
145
|
+
const images = (result.visionImages ?? [])
|
|
146
|
+
.map((image) => (typeof image.source === 'string' ? image.source : ''))
|
|
147
|
+
.filter((path) => path.length > 0);
|
|
88
148
|
return {
|
|
89
|
-
raw: {
|
|
149
|
+
raw: {
|
|
150
|
+
content,
|
|
151
|
+
result: content,
|
|
152
|
+
args,
|
|
153
|
+
images,
|
|
154
|
+
metadata: result.metadata,
|
|
155
|
+
recovery: result.recovery,
|
|
156
|
+
sensitivity: result.sensitivity,
|
|
157
|
+
visionNote: result.visionNote,
|
|
158
|
+
},
|
|
90
159
|
preview: content.length > 200 ? `${content.slice(0, 200)}...` : content,
|
|
91
160
|
};
|
|
92
161
|
}
|
|
@@ -103,14 +172,17 @@ async function preReadDeclaredArtifact(tool, args, step, ctx) {
|
|
|
103
172
|
if (typeof args.file_path !== 'string')
|
|
104
173
|
return;
|
|
105
174
|
const norm = (p) => {
|
|
106
|
-
const abs = resolve(ctx
|
|
175
|
+
const abs = resolve(effectiveWorkflowCwd(ctx), p);
|
|
107
176
|
return process.platform === 'win32' ? abs.toLowerCase() : abs;
|
|
108
177
|
};
|
|
109
178
|
const target = norm(args.file_path);
|
|
110
|
-
const declared = [
|
|
179
|
+
const declared = [
|
|
180
|
+
...(ctx.declaredArtifacts ?? []),
|
|
181
|
+
...(step.artifacts ?? []),
|
|
182
|
+
];
|
|
111
183
|
if (!declared.some((a) => norm(a) === target))
|
|
112
184
|
return;
|
|
113
|
-
const abs = resolve(ctx
|
|
185
|
+
const abs = resolve(effectiveWorkflowCwd(ctx), args.file_path);
|
|
114
186
|
if (!existsSync(abs))
|
|
115
187
|
return; // 新建文件不需要解守卫
|
|
116
188
|
// 直接登记一次「完整已读」状态解除内核 pre-read 守卫——不真正 Read 内容:
|
|
@@ -121,7 +193,7 @@ async function preReadDeclaredArtifact(tool, args, step, ctx) {
|
|
|
121
193
|
// (首轮新建 PLAN.md 不存在直接放行,审批反馈后回写已存在的大 PLAN.md 被挡死)。
|
|
122
194
|
// 两道守卫(never-read + truncated)必须一并解除,声明产物的整体覆盖才算真正授权。
|
|
123
195
|
// recordRead 内部自带 statSync 失败兜底(返回 1、不抛),无需再包 try/catch。
|
|
124
|
-
recordRead(abs, { truncated: false });
|
|
196
|
+
recordRead(abs, { truncated: false }, ctx.sessionState?.fileReads);
|
|
125
197
|
}
|
|
126
198
|
/**
|
|
127
199
|
* 给 tool_start 生成人话描述(LiveArea spinner 行用)。
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/tool.ts —— tool step 执行
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 把 step.args 递归 ${var} 插值后 JSON.stringify,转发到 executeTool。
|
|
6
|
+
* 失败(ok=false)抛 Error,让 runner 走 onError 处理。
|
|
7
|
+
*
|
|
8
|
+
* v2(P1 TUI 可见):本执行器改为 AsyncGenerator,在调 executeTool 前后
|
|
9
|
+
* yield 通用 tool_start / tool_end LoopEvent —— 这样 workflow 的 tool 步骤
|
|
10
|
+
* 在 TUI 里像普通 ReAct 工具调用一样显示(runningTools spinner + 人话描述)。
|
|
11
|
+
*
|
|
12
|
+
* v0.9.3(上下文统一修复):tool 步骤执行后把工具调用摘要写入 ctx.history,
|
|
13
|
+
* 让后续 agent/llm/skill 步骤(走 runQuery → LLM)能自然看到前面步骤的工作成果,
|
|
14
|
+
* 不再依赖 VarStack 变量插值作为唯一的信息传递通道。
|
|
15
|
+
* 这实现了"一套上下文"架构:workflow 的每一步都在共享的 TAOR history 中留痕。
|
|
16
|
+
*
|
|
17
|
+
* capture 字段(支持点路径):
|
|
18
|
+
* - `{ content: var_name }` 绑 ToolResult.content(工具回执文本)
|
|
19
|
+
* - `{ result: var_name }` 同义,给"无结构化字段"工具用
|
|
20
|
+
* - `{ args.content: var_name }` 绑插值后传给工具的入参(如真正写入的内容)
|
|
21
|
+
* - `{ args.<任意字段>: var_name }` 绑入参的具名字段
|
|
22
|
+
* ============================================================
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { existsSync } from 'node:fs';
|
|
26
|
+
import { resolve } from 'node:path';
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
type LoopEvent,
|
|
30
|
+
type ToolResult,
|
|
31
|
+
executeTool,
|
|
32
|
+
getToolByName,
|
|
33
|
+
recordRead,
|
|
34
|
+
} from '../../../../src/plugin-sdk.js';
|
|
35
|
+
import { interpolateDeep } from '../expressions.js';
|
|
36
|
+
import {
|
|
37
|
+
buildWorkflowToolContext,
|
|
38
|
+
effectiveWorkflowCwd,
|
|
39
|
+
} from '../toolRuntime.js';
|
|
40
|
+
import type { RunContext, StepDef, StepResult, VarStack } from '../types.js';
|
|
41
|
+
|
|
42
|
+
export async function* execToolStep(
|
|
43
|
+
step: StepDef,
|
|
44
|
+
vars: VarStack,
|
|
45
|
+
ctx: RunContext,
|
|
46
|
+
): AsyncGenerator<LoopEvent, StepResult, void> {
|
|
47
|
+
if (!step.tool) throw new Error(`step ${step.id}: 缺少 tool 字段`);
|
|
48
|
+
const tool = getToolByName(step.tool);
|
|
49
|
+
if (!tool) throw new Error(`step ${step.id}: 未知工具 "${step.tool}"`);
|
|
50
|
+
if (!ctx.tools.some((available) => available.name === tool.name)) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`step ${step.id}: 工具 "${tool.name}" 不在当前宿主授权的 Workflow 工具集中`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 未定义变量插值可见化(args 里静默空串会让工具拿到空路径/空内容)
|
|
57
|
+
const missing: string[] = [];
|
|
58
|
+
const args = interpolateDeep(step.args ?? {}, vars, {
|
|
59
|
+
onMissing: (e) => missing.push(e),
|
|
60
|
+
});
|
|
61
|
+
if (missing.length > 0) {
|
|
62
|
+
yield {
|
|
63
|
+
type: 'warning',
|
|
64
|
+
message: `step "${step.id}": 模板变量未定义,已按空串插值:${[...new Set(missing)].map((m) => `\${${m}}`).join('、')}(裸名请用 inputs.<name> 或先 capture/set)`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const argsJson = JSON.stringify(args);
|
|
68
|
+
const toolCallId = `wf_${step.id}`;
|
|
69
|
+
const argsPreview =
|
|
70
|
+
argsJson.length > 80 ? `${argsJson.slice(0, 80)}…` : argsJson;
|
|
71
|
+
|
|
72
|
+
yield {
|
|
73
|
+
type: 'tool_start',
|
|
74
|
+
toolName: tool.name,
|
|
75
|
+
toolCallId,
|
|
76
|
+
argsPreview,
|
|
77
|
+
argsFriendly: friendlyToolDesc(tool.name, args as Record<string, unknown>),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// ════ 声明产物覆盖判定(解 Write/Edit 的 pre-read 守卫) ════
|
|
81
|
+
// 内核写类工具有「文件已存在必须先 Read」守卫(fileState 按会话隔离,
|
|
82
|
+
// 跨进程 / resume / 残留旧产物时可能为空)。确定性 tool 步的 args 是 yaml 作者
|
|
83
|
+
// 写死的,模型没有机会先 Read —— 目标文件若是工作流**声明的产物**
|
|
84
|
+
// (def 级 + step 级 artifacts:,= 工作流自己拥有、本就要覆盖的文件),
|
|
85
|
+
// 这里自动 pre-Read 一次解除守卫(管线动作,不 yield 事件、结果丢弃)。
|
|
86
|
+
// 非声明产物的盲写保护原样生效;pre-Read 失败也不拦,让写工具自己报错。
|
|
87
|
+
await preReadDeclaredArtifact(
|
|
88
|
+
tool,
|
|
89
|
+
args as Record<string, unknown>,
|
|
90
|
+
step,
|
|
91
|
+
ctx,
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// 宿主能力按 `uses:` 切片后转发。`executeTool` 的第四参此前从未传过 ——
|
|
95
|
+
// 这正是「workflow 里 ComputerUse 恒失败」的末端表现。
|
|
96
|
+
const pendingProgress: LoopEvent[] = [];
|
|
97
|
+
let wakeProgress: (() => void) | undefined;
|
|
98
|
+
const toolContext = buildWorkflowToolContext(
|
|
99
|
+
step,
|
|
100
|
+
ctx,
|
|
101
|
+
toolCallId,
|
|
102
|
+
(message, detail) => {
|
|
103
|
+
pendingProgress.push({
|
|
104
|
+
type: 'tool_progress',
|
|
105
|
+
toolName: tool.name,
|
|
106
|
+
toolCallId,
|
|
107
|
+
message,
|
|
108
|
+
detail,
|
|
109
|
+
});
|
|
110
|
+
wakeProgress?.();
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
if ('error' in toolContext) {
|
|
114
|
+
throw new Error(`step ${step.id}: ${toolContext.error}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const dispatch = ctx.executeTool ?? executeTool;
|
|
118
|
+
let settled = false;
|
|
119
|
+
let result: ToolResult | undefined;
|
|
120
|
+
void dispatch(tool.name, argsJson, ctx.signal, toolContext)
|
|
121
|
+
.then((value) => {
|
|
122
|
+
result = value;
|
|
123
|
+
})
|
|
124
|
+
.catch((error: unknown) => {
|
|
125
|
+
result = {
|
|
126
|
+
ok: false,
|
|
127
|
+
error: error instanceof Error ? error.message : String(error),
|
|
128
|
+
};
|
|
129
|
+
})
|
|
130
|
+
.finally(() => {
|
|
131
|
+
settled = true;
|
|
132
|
+
wakeProgress?.();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
while (!settled || pendingProgress.length > 0) {
|
|
136
|
+
const progress = pendingProgress.shift();
|
|
137
|
+
if (progress) {
|
|
138
|
+
yield progress;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
await new Promise<void>((resolveWake) => {
|
|
142
|
+
wakeProgress = resolveWake;
|
|
143
|
+
if (settled || pendingProgress.length > 0) resolveWake();
|
|
144
|
+
});
|
|
145
|
+
wakeProgress = undefined;
|
|
146
|
+
}
|
|
147
|
+
if (!result) throw new Error(`step ${step.id}: 工具执行未返回结果`);
|
|
148
|
+
|
|
149
|
+
yield {
|
|
150
|
+
type: 'tool_end',
|
|
151
|
+
toolName: tool.name,
|
|
152
|
+
toolCallId,
|
|
153
|
+
ok: result.ok,
|
|
154
|
+
content: result.ok ? result.content : result.error,
|
|
155
|
+
metadata: result.metadata,
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (!result.ok) {
|
|
159
|
+
throw new Error(result.error);
|
|
160
|
+
}
|
|
161
|
+
const content = result.content;
|
|
162
|
+
|
|
163
|
+
// ════ v0.9.3:上下文统一 —— 把工具调用写入共享 history ════
|
|
164
|
+
// 后续 agent/llm/skill 步骤走 runQuery() 时,LLM 能在上下文中看到
|
|
165
|
+
// 这步做了什么(与正常 TAOR 循环中 tool_call → tool_result 的记录方式一致)。
|
|
166
|
+
// 只记录精简摘要(不把完整工具回执塞入 history,避免 token 浪费)。
|
|
167
|
+
const summary =
|
|
168
|
+
content.length > 500
|
|
169
|
+
? `${content.slice(0, 500)}…(已截断,共 ${content.length} 字符)`
|
|
170
|
+
: content;
|
|
171
|
+
ctx.history.push({
|
|
172
|
+
role: 'assistant',
|
|
173
|
+
content: `[workflow:${step.id}] ✅ ${tool.name} 执行完成:${summary}`,
|
|
174
|
+
timestamp: Date.now(),
|
|
175
|
+
id: crypto.randomUUID(),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// ⚠️ 工具返回的图片**不能丢**。此前这里只取 content,`visionImages` 被静默丢弃 ——
|
|
179
|
+
// 于是任何「截图/看图」类工作流都拿不到产物,而且不会报错,只是后面的评估步没图可看。
|
|
180
|
+
// 取路径而不是整个 ImageInputSpec:yaml 侧要的是能 capture、能传给 llm 步 `images:`
|
|
181
|
+
// 的字符串;结构体传下去反而要每个消费方各自解包。
|
|
182
|
+
const images = (result.visionImages ?? [])
|
|
183
|
+
.map((image) => (typeof image.source === 'string' ? image.source : ''))
|
|
184
|
+
.filter((path) => path.length > 0);
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
raw: {
|
|
188
|
+
content,
|
|
189
|
+
result: content,
|
|
190
|
+
args,
|
|
191
|
+
images,
|
|
192
|
+
metadata: result.metadata,
|
|
193
|
+
recovery: result.recovery,
|
|
194
|
+
sensitivity: result.sensitivity,
|
|
195
|
+
visionNote: result.visionNote,
|
|
196
|
+
},
|
|
197
|
+
preview: content.length > 200 ? `${content.slice(0, 200)}...` : content,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 写类 tool 步的目标文件若命中声明产物且已存在 → pre-Read 解除内核守卫。
|
|
203
|
+
*
|
|
204
|
+
* 路径归一化:artifacts 声明相对 cwd;args.file_path 可能是 ./相对 或 绝对,
|
|
205
|
+
* 双方都 resolve(cwd, …) 后比较(win32 文件系统大小写不敏感 → lowercase 比较;
|
|
206
|
+
* 其余平台保持大小写敏感,避免 Plan.md / plan.md 误判同文件)。
|
|
207
|
+
*/
|
|
208
|
+
async function preReadDeclaredArtifact(
|
|
209
|
+
tool: { name: string; isReadOnly?: boolean },
|
|
210
|
+
args: Record<string, unknown>,
|
|
211
|
+
step: StepDef,
|
|
212
|
+
ctx: RunContext,
|
|
213
|
+
): Promise<void> {
|
|
214
|
+
if (tool.isReadOnly !== false) return; // 只对写类工具生效
|
|
215
|
+
if (typeof args.file_path !== 'string') return;
|
|
216
|
+
|
|
217
|
+
const norm = (p: string): string => {
|
|
218
|
+
const abs = resolve(effectiveWorkflowCwd(ctx), p);
|
|
219
|
+
return process.platform === 'win32' ? abs.toLowerCase() : abs;
|
|
220
|
+
};
|
|
221
|
+
const target = norm(args.file_path);
|
|
222
|
+
const declared = [
|
|
223
|
+
...(ctx.declaredArtifacts ?? []),
|
|
224
|
+
...(step.artifacts ?? []),
|
|
225
|
+
];
|
|
226
|
+
if (!declared.some((a) => norm(a) === target)) return;
|
|
227
|
+
|
|
228
|
+
const abs = resolve(effectiveWorkflowCwd(ctx), args.file_path);
|
|
229
|
+
if (!existsSync(abs)) return; // 新建文件不需要解守卫
|
|
230
|
+
|
|
231
|
+
// 直接登记一次「完整已读」状态解除内核 pre-read 守卫——不真正 Read 内容:
|
|
232
|
+
// 1. 声明产物本就要被本步整体覆盖,旧内容无需进上下文/烧 token;
|
|
233
|
+
// 2. 真 Read 大文件会触发字符上限截断(read.ts → recordRead({truncated:true})),
|
|
234
|
+
// 反而踩中 Write 的「截断禁写」硬守卫(write.ts: existsSync && wasTruncated → 拒绝),
|
|
235
|
+
// 正是本步要解除的同一道墙——曾导致 plan.yaml 回写变长的 PLAN.md 时 halt
|
|
236
|
+
// (首轮新建 PLAN.md 不存在直接放行,审批反馈后回写已存在的大 PLAN.md 被挡死)。
|
|
237
|
+
// 两道守卫(never-read + truncated)必须一并解除,声明产物的整体覆盖才算真正授权。
|
|
238
|
+
// recordRead 内部自带 statSync 失败兜底(返回 1、不抛),无需再包 try/catch。
|
|
239
|
+
recordRead(abs, { truncated: false }, ctx.sessionState?.fileReads);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* 给 tool_start 生成人话描述(LiveArea spinner 行用)。
|
|
244
|
+
*/
|
|
245
|
+
function friendlyToolDesc(
|
|
246
|
+
toolName: string,
|
|
247
|
+
args: Record<string, unknown>,
|
|
248
|
+
): string {
|
|
249
|
+
const key = ['file_path', 'command', 'query', 'pattern', 'path', 'url'].find(
|
|
250
|
+
(k) => typeof args[k] === 'string',
|
|
251
|
+
);
|
|
252
|
+
if (!key) return toolName;
|
|
253
|
+
const val = String(args[key]);
|
|
254
|
+
const short = val.length > 60 ? `${val.slice(0, 60)}…` : val;
|
|
255
|
+
return `${toolName} ${short}`;
|
|
256
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/verify.ts —— verify step 执行
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 复用内核共享验证基础设施(经 plugin-sdk 门面取 runVerification/parseCheckString),
|
|
6
|
+
* 支持 shell / file_exists / file_contains / test_count 四种检查。
|
|
7
|
+
*
|
|
8
|
+
* 与 assert 的区别:
|
|
9
|
+
* - assert: evalExpr 表达式(轻量,适合简单文件存在判断)
|
|
10
|
+
* - verify: 完整检查器(重量,支持命令执行/正则匹配/测试计数)
|
|
11
|
+
* ============================================================
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { parseCheckString, runVerification, type Check } from '../../../../src/plugin-sdk.js';
|
|
15
|
+
import { interpolate } from '../expressions.js';
|
|
16
|
+
import type { StepDef, StepResult, VarStack } from '../types.js';
|
|
17
|
+
|
|
18
|
+
export async function execVerifyStep(
|
|
19
|
+
step: StepDef,
|
|
20
|
+
vars: VarStack,
|
|
21
|
+
): Promise<StepResult> {
|
|
22
|
+
// 兼容两种格式:YAML 数组 或逗号分隔字符串。
|
|
23
|
+
// 关键:【先插值再按逗号分割】。checks 可能是 "${verify_checks}" 这类模板,插值后才
|
|
24
|
+
// 展开成逗号分隔的多项(如 "shell:bun test,file_exists:x")。若先分割再插值,整段模板
|
|
25
|
+
// 会被当成一项,解析时 value 混入逗号、多项检查失效(ralph-loop 的 run_verify 即如此)。
|
|
26
|
+
let rawChecks: string[];
|
|
27
|
+
if (Array.isArray(step.checks) && step.checks.length > 0) {
|
|
28
|
+
rawChecks = (step.checks as string[])
|
|
29
|
+
.flatMap((s) => interpolate(s, vars).split(','))
|
|
30
|
+
.map((s) => s.trim())
|
|
31
|
+
.filter(Boolean);
|
|
32
|
+
} else if (typeof step.checks === 'string' && step.checks.trim() !== '') {
|
|
33
|
+
rawChecks = interpolate(step.checks as string, vars)
|
|
34
|
+
.split(',')
|
|
35
|
+
.map((s) => s.trim())
|
|
36
|
+
.filter(Boolean);
|
|
37
|
+
} else {
|
|
38
|
+
throw new Error(`step ${step.id}: verify 缺少 checks(需要数组或逗号分隔字符串)`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 解析每条已插值的 check 字符串(插值后若整体为空——如 ${verify_checks} 取到空串——
|
|
42
|
+
// 则 checks 为空,runVerification 视为"无检查项"通过;ralph-loop 另有 when 守卫不会走到这)
|
|
43
|
+
const checks: Check[] = [];
|
|
44
|
+
for (const raw of rawChecks) {
|
|
45
|
+
const check = parseCheckString(raw);
|
|
46
|
+
if (!check) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`step ${step.id}: 无法解析 check "${raw}",格式应为 "type:value"`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
checks.push(check);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 执行所有检查
|
|
55
|
+
const result = await runVerification(checks);
|
|
56
|
+
|
|
57
|
+
if (!result.passed) {
|
|
58
|
+
const msg = step.onFail
|
|
59
|
+
? interpolate(step.onFail, vars)
|
|
60
|
+
: `verify 失败: ${result.summary}`;
|
|
61
|
+
throw new Error(msg);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
raw: { passed: true, summary: result.summary, details: result.details },
|
|
66
|
+
preview: result.summary,
|
|
67
|
+
};
|
|
68
|
+
}
|