minimal-agent 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/package.json +62 -5
- package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
- package/plugins/cron-runner/src/commands.js +4 -4
- package/plugins/cron-runner/src/commands.ts +4 -4
- package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
- package/plugins/workflow-runner/commands/workflow.md +57 -90
- package/plugins/workflow-runner/commands/workflows.md +4 -4
- package/plugins/workflow-runner/plugin.js +24 -13
- package/plugins/workflow-runner/plugin.ts +28 -13
- package/plugins/workflow-runner/src/discovery.js +160 -0
- package/plugins/workflow-runner/src/discovery.ts +194 -0
- package/plugins/workflow-runner/src/goalAnchor.js +53 -0
- package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
- package/plugins/workflow-runner/src/index.js +204 -185
- package/plugins/workflow-runner/src/index.ts +249 -224
- package/plugins/workflow-runner/src/inputCoercion.js +40 -0
- package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
- package/plugins/workflow-runner/src/journal.js +224 -0
- package/plugins/workflow-runner/src/journal.ts +274 -0
- package/plugins/workflow-runner/src/jsonSchema.js +132 -0
- package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
- package/plugins/workflow-runner/src/moduleResolution.js +64 -0
- package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
- package/plugins/workflow-runner/src/resourceInputs.js +220 -0
- package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
- package/plugins/workflow-runner/src/runner.js +404 -467
- package/plugins/workflow-runner/src/runner.ts +491 -535
- package/plugins/workflow-runner/src/runtime/config.js +46 -0
- package/plugins/workflow-runner/src/runtime/config.ts +69 -0
- package/plugins/workflow-runner/src/runtime/context.js +1304 -0
- package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
- package/plugins/workflow-runner/src/runtime/exec.js +34 -0
- package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
- package/plugins/workflow-runner/src/runtime/flow.js +8 -0
- package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
- package/plugins/workflow-runner/src/runtime/fs.js +27 -0
- package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
- package/plugins/workflow-runner/src/runtime/model.js +6 -0
- package/plugins/workflow-runner/src/runtime/model.ts +8 -0
- package/plugins/workflow-runner/src/runtime/output.js +7 -0
- package/plugins/workflow-runner/src/runtime/output.ts +21 -0
- package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
- package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
- package/plugins/workflow-runner/src/runtime/state.js +16 -0
- package/plugins/workflow-runner/src/runtime/state.ts +19 -0
- package/plugins/workflow-runner/src/runtime/tools.js +3 -0
- package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
- package/plugins/workflow-runner/src/sandbox.js +141 -0
- package/plugins/workflow-runner/src/sandbox.ts +182 -0
- package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
- package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
- package/plugins/workflow-runner/src/taskIdentity.js +172 -152
- package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
- package/plugins/workflow-runner/src/toolRuntime.js +29 -8
- package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
- package/plugins/workflow-runner/src/types.js +7 -105
- package/plugins/workflow-runner/src/types.ts +155 -520
- package/plugins/workflow-runner/src/util.js +47 -0
- package/plugins/workflow-runner/src/util.ts +51 -0
- package/plugins/workflow-runner/src/workflowContext.js +20 -0
- package/plugins/workflow-runner/src/workflowContext.ts +58 -0
- package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
- package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
- package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
- package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
- package/plugins/workflow-runner/src/workflowState.js +542 -469
- package/plugins/workflow-runner/src/workflowState.ts +639 -589
- package/plugins/workflow-runner/test/api.test.ts +223 -0
- package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
- package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
- package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
- package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
- package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
- package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
- package/plugins/workflow-runner/test/discovery.test.ts +234 -0
- package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
- package/plugins/workflow-runner/test/goalController.test.ts +317 -0
- package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
- package/plugins/workflow-runner/test/listResources.test.ts +106 -0
- package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
- package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
- package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
- package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
- package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
- package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
- package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
- package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
- package/skills/pptx/examples/assets/cover-bg.svg +23 -0
- package/skills/pptx/examples/assets/icon-spark.svg +5 -0
- package/skills/skill-creator/scripts/run_eval.py +3 -2
- package/skills/ui-design/SKILL.md +5 -2
- package/skills/ui-design/references/layout-composition.md +1 -1
- package/skills/workflow-creator/SKILL.md +344 -0
- package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
- package/skills/workflow-creator/references/api.md +216 -0
- package/skills/workflow-creator/references/migration.md +103 -0
- package/skills/workflow-creator/references/patterns.md +779 -0
- package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
- package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
- package/skills/workflow-creator/scripts/validate.mjs +275 -0
- package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
- package/src/advisor/advisorCoordinator.js +503 -0
- package/src/advisor/advisorCoordinator.ts +657 -0
- package/src/cli/configMenu.tsx +0 -1
- package/src/cli/print.js +44 -6
- package/src/cli/print.ts +73 -4
- package/src/cli/streamJson.js +5 -6
- package/src/cli/streamJson.ts +8 -4
- package/src/cli/wizards/advisorWizard.js +4 -2
- package/src/cli/wizards/advisorWizard.tsx +8 -2
- package/src/cli/wizards/contextAdvisorWizard.js +5 -4
- package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
- package/src/collaboration/taskFlow.js +115 -0
- package/src/collaboration/taskFlow.ts +169 -0
- package/src/config/configDefaults.js +41 -1
- package/src/config/configDefaults.ts +43 -1
- package/src/config/configDiagnostics.ts +2 -2
- package/src/config/configFile.js +40 -9
- package/src/config/configFile.ts +60 -11
- package/src/config/configService.js +443 -74
- package/src/config/configService.ts +723 -142
- package/src/config/numericLimits.js +22 -0
- package/src/config/numericLimits.ts +24 -0
- package/src/config.js +1 -0
- package/src/config.ts +3 -2
- package/src/context/budgetPlan.js +1 -1
- package/src/context/budgetPlan.ts +1 -1
- package/src/context/compact.js +7 -2
- package/src/context/compact.ts +9 -2
- package/src/context/microCompactLite.js +212 -13
- package/src/context/microCompactLite.ts +261 -12
- package/src/context/sessionRegistry.js +8 -1
- package/src/context/sessionRegistry.ts +18 -5
- package/src/context/toolResultArchive.js +72 -0
- package/src/context/toolResultArchive.ts +95 -0
- package/src/goal/errors.js +8 -0
- package/src/goal/errors.ts +18 -0
- package/src/goal/goalRuntime.js +344 -0
- package/src/goal/goalRuntime.ts +466 -0
- package/src/goal/goalStore.js +200 -0
- package/src/goal/goalStore.ts +219 -0
- package/src/goal/index.js +4 -0
- package/src/goal/index.ts +4 -0
- package/src/goal/statusMapping.js +71 -0
- package/src/goal/statusMapping.ts +95 -0
- package/src/goal/types.js +7 -0
- package/src/goal/types.ts +179 -0
- package/src/goal/workflowController.js +306 -0
- package/src/goal/workflowController.ts +360 -0
- package/src/harness/evidenceLedger.js +2 -0
- package/src/harness/evidenceLedger.ts +1 -0
- package/src/harness/stallGuard.js +9 -3
- package/src/harness/stallGuard.ts +7 -3
- package/src/images/imageResolver.js +161 -0
- package/src/images/imageResolver.ts +189 -0
- package/src/infra/verification.js +56 -20
- package/src/infra/verification.ts +87 -20
- package/src/llm/client.js +79 -21
- package/src/llm/client.ts +182 -35
- package/src/llm/gatewayClient.js +201 -0
- package/src/llm/gatewayClient.ts +299 -0
- package/src/llm/messageProvenance.js +46 -0
- package/src/llm/messageProvenance.ts +58 -0
- package/src/llm/modelProvider.js +1 -0
- package/src/llm/modelProvider.ts +22 -0
- package/src/llm/providers/anthropicFormat.js +108 -1
- package/src/llm/providers/anthropicFormat.ts +115 -4
- package/src/llm/providers/openaiFormat.js +9 -0
- package/src/llm/providers/openaiFormat.ts +12 -3
- package/src/loop.js +319 -54
- package/src/loop.ts +373 -57
- package/src/main.js +4 -1
- package/src/main.tsx +4 -1
- package/src/managedExecution/index.js +2 -0
- package/src/managedExecution/index.ts +2 -0
- package/src/managedExecution/registry.js +15 -0
- package/src/managedExecution/registry.ts +20 -0
- package/src/managedExecution/types.js +1 -0
- package/src/managedExecution/types.ts +86 -0
- package/src/modelRef.js +9 -0
- package/src/modelRef.ts +31 -0
- package/src/multimodal.js +14 -28
- package/src/multimodal.ts +17 -33
- package/src/net/lanDiscovery.js +65 -0
- package/src/net/lanDiscovery.ts +82 -0
- package/src/plugin-sdk.js +28 -3
- package/src/plugin-sdk.ts +39 -6
- package/src/plugins/pluginApi.ts +16 -1
- package/src/plugins/pluginLoader.js +4 -0
- package/src/plugins/pluginLoader.ts +6 -0
- package/src/plugins/pluginRunner.js +152 -9
- package/src/plugins/pluginRunner.ts +186 -8
- package/src/plugins/slashFallback.js +113 -0
- package/src/plugins/slashFallback.ts +137 -0
- package/src/prompts/policyRegistry.js +15 -8
- package/src/prompts/policyRegistry.ts +18 -8
- package/src/prompts/promptAssembly.js +103 -12
- package/src/prompts/promptAssembly.ts +114 -12
- package/src/prompts/skillList.js +21 -3
- package/src/prompts/skillList.ts +27 -2
- package/src/prompts/stableSystemPrompt.js +18 -0
- package/src/prompts/stableSystemPrompt.ts +33 -0
- package/src/runtime/agentRuntimeContext.js +8 -2
- package/src/runtime/agentRuntimeContext.ts +17 -4
- package/src/session/runAgentTurn.js +78 -12
- package/src/session/runAgentTurn.ts +105 -23
- package/src/session/runTurn.js +10 -9
- package/src/session/runTurn.ts +17 -8
- package/src/session/sessionState.ts +2 -0
- package/src/team/auth.js +186 -0
- package/src/team/auth.ts +298 -0
- package/src/team/cli.js +105 -0
- package/src/team/cli.ts +122 -0
- package/src/team/onlineToolContract.js +64 -0
- package/src/team/onlineToolContract.ts +109 -0
- package/src/team/toolPolicy.js +36 -0
- package/src/team/toolPolicy.ts +75 -0
- package/src/tools/advisor/advisor.js +148 -37
- package/src/tools/advisor/advisor.ts +161 -38
- package/src/tools/advisor/advisorDecision.js +71 -0
- package/src/tools/advisor/advisorDecision.ts +85 -0
- package/src/tools/agent/agent.js +18 -5
- package/src/tools/agent/agent.ts +21 -7
- package/src/tools/agent/agentControl.js +246 -0
- package/src/tools/agent/agentControl.ts +284 -0
- package/src/tools/agent/agentTaskService.js +40 -1
- package/src/tools/agent/agentTaskService.ts +44 -1
- package/src/tools/agent/agentTypes.js +14 -2
- package/src/tools/agent/agentTypes.ts +15 -2
- package/src/tools/applypatch/applyPatch.js +362 -0
- package/src/tools/applypatch/applyPatch.ts +428 -0
- package/src/tools/bash/bash.js +70 -18
- package/src/tools/bash/bash.ts +75 -20
- package/src/tools/capabilities.js +10 -5
- package/src/tools/capabilities.ts +10 -5
- package/src/tools/computeruse/computerIntent.js +32 -0
- package/src/tools/computeruse/computerIntent.ts +46 -0
- package/src/tools/computeruse/telemetryLog.js +12 -0
- package/src/tools/computeruse/telemetryLog.ts +16 -0
- package/src/tools/computeruse/vision/telemetry.js +1 -0
- package/src/tools/computeruse/vision/telemetry.ts +1 -0
- package/src/tools/effectiveToolSet.js +4 -0
- package/src/tools/effectiveToolSet.ts +4 -0
- package/src/tools/index.js +21 -2
- package/src/tools/index.ts +33 -2
- package/src/tools/powershell/powershell.js +18 -1
- package/src/tools/powershell/powershell.ts +18 -2
- package/src/tools/presentresult/presentresult.js +6 -15
- package/src/tools/presentresult/presentresult.ts +6 -15
- package/src/tools/read/read.js +69 -11
- package/src/tools/read/read.ts +70 -11
- package/src/tools/shared/fileUtils.js +1 -2
- package/src/tools/shared/fileUtils.ts +1 -2
- package/src/tools/shared/permanentDeleteGuard.js +34 -3
- package/src/tools/shared/permanentDeleteGuard.ts +43 -6
- package/src/tools/shared/toolOutputStore.js +23 -1
- package/src/tools/shared/toolOutputStore.ts +22 -1
- package/src/tools/skill/skill.js +9 -3
- package/src/tools/skill/skill.ts +8 -4
- package/src/tools/toolPromptGuides.js +117 -0
- package/src/tools/toolPromptGuides.ts +137 -0
- package/src/tools/webbrowser/agentBrowserPath.js +19 -9
- package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
- package/src/tools/webbrowser/browser.js +27 -11
- package/src/tools/webbrowser/browser.ts +68 -24
- package/src/tools/webbrowser/browserAutomation.js +329 -0
- package/src/tools/webbrowser/browserAutomation.ts +467 -0
- package/src/tools/webbrowser/browserAxState.js +97 -0
- package/src/tools/webbrowser/browserAxState.ts +142 -0
- package/src/tools/webbrowser/browserBatch.js +1578 -0
- package/src/tools/webbrowser/browserBatch.ts +2382 -0
- package/src/tools/webbrowser/browserCdp.js +208 -0
- package/src/tools/webbrowser/browserCdp.ts +255 -0
- package/src/tools/webbrowser/browserConditions.js +24 -0
- package/src/tools/webbrowser/browserConditions.ts +45 -0
- package/src/tools/webbrowser/browserContent.js +281 -0
- package/src/tools/webbrowser/browserContent.ts +438 -0
- package/src/tools/webbrowser/browserControl.js +131 -30
- package/src/tools/webbrowser/browserControl.ts +210 -50
- package/src/tools/webbrowser/browserDaemon.js +22 -14
- package/src/tools/webbrowser/browserDaemon.ts +54 -21
- package/src/tools/webbrowser/browserFrames.js +47 -0
- package/src/tools/webbrowser/browserFrames.ts +54 -0
- package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
- package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
- package/src/tools/webbrowser/browserLocator.js +140 -0
- package/src/tools/webbrowser/browserLocator.ts +194 -0
- package/src/tools/webbrowser/browserOutcome.js +10 -17
- package/src/tools/webbrowser/browserOutcome.ts +48 -31
- package/src/tools/webbrowser/browserRecovery.js +58 -0
- package/src/tools/webbrowser/browserRecovery.ts +83 -0
- package/src/tools/webbrowser/browserRunRegistry.js +35 -3
- package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
- package/src/tools/webbrowser/browserService.js +28 -2
- package/src/tools/webbrowser/browserService.ts +49 -9
- package/src/tools/webbrowser/browserStream.js +132 -33
- package/src/tools/webbrowser/browserStream.ts +224 -50
- package/src/tools/webbrowser/browserTabs.js +48 -15
- package/src/tools/webbrowser/browserTabs.ts +178 -96
- package/src/tools/webbrowser/webbrowser.js +683 -144
- package/src/tools/webbrowser/webbrowser.ts +979 -236
- package/src/tools/webfetch/preapproved.js +0 -2
- package/src/tools/webfetch/preapproved.ts +0 -2
- package/src/tools/websearch/websearch.js +129 -8
- package/src/tools/websearch/websearch.ts +138 -6
- package/src/types.ts +450 -42
- package/src/ui/App.js +377 -58
- package/src/ui/App.tsx +576 -111
- package/src/ui/LiveArea.js +14 -8
- package/src/ui/LiveArea.tsx +14 -10
- package/src/ui/MessageList.js +63 -20
- package/src/ui/MessageList.tsx +101 -16
- package/src/ui/ModelPicker.js +7 -4
- package/src/ui/ModelPicker.tsx +55 -8
- package/src/ui/hooks/useChat.js +152 -163
- package/src/ui/hooks/useChat.ts +396 -334
- package/src/ui/loginCommand.js +56 -0
- package/src/ui/loginCommand.ts +63 -0
- package/src/ui/toolProgress.js +41 -0
- package/src/ui/toolProgress.ts +44 -0
- package/src/web/browserBridge.js +20 -2
- package/src/web/browserBridge.ts +20 -2
- package/src/web/protocol.ts +1897 -194
- package/workflows/adaptive-research/workflow.mjs +86 -0
- package/workflows/e2e-capabilities/workflow.mjs +102 -0
- package/workflows/e2e-llm/workflow.mjs +52 -0
- package/workflows/e2e-smoke/workflow.mjs +59 -0
- package/workflows/e2e-vision-schema/README.md +48 -0
- package/workflows/e2e-vision-schema/workflow.mjs +149 -0
- package/workflows/e2e-write-greet/workflow.mjs +37 -0
- package/workflows/file-census/README.md +14 -0
- package/workflows/file-census/scripts/.gitkeep +2 -0
- package/workflows/file-census/workflow.mjs +110 -0
- package/workflows/goal/README.md +166 -0
- package/workflows/goal/prompts/audit.md +57 -0
- package/workflows/goal/prompts/contract.md +56 -0
- package/workflows/goal/prompts/iterate.md +37 -0
- package/workflows/goal/workflow.mjs +501 -0
- package/workflows/illustrate/README.md +90 -0
- package/workflows/illustrate/assets/engines.json +20 -0
- package/workflows/illustrate/assets/extract-baidu.js +21 -0
- package/workflows/illustrate/assets/extract-bing.js +33 -0
- package/workflows/illustrate/assets/extract-google.js +31 -0
- package/workflows/illustrate/workflow.mjs +301 -0
- package/workflows/plan/workflow.mjs +389 -0
- package/workflows/question-crops/README.md +35 -0
- package/workflows/question-crops/prompts/inventory.md +23 -0
- package/workflows/question-crops/scripts/image-ops.mjs +305 -0
- package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
- package/workflows/question-crops/workflow.mjs +172 -0
- package/workflows/ralph-loop/workflow.mjs +162 -0
- package/workflows/research/DESIGN.md +449 -0
- package/workflows/research/README.md +74 -0
- package/workflows/research/prompts/s0-goal.md +43 -0
- package/workflows/research/prompts/s1-early-exit.md +22 -0
- package/workflows/research/prompts/s1-map.md +58 -0
- package/workflows/research/prompts/s2-options.md +53 -0
- package/workflows/research/prompts/s3-deep-dive.md +56 -0
- package/workflows/research/prompts/s4-verify.md +74 -0
- package/workflows/research/prompts/s5-synthesis.md +81 -0
- package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
- package/workflows/research/prompts/s6-package.md +32 -0
- package/workflows/research/scripts/build-report.mjs +98 -0
- package/workflows/research/workflow.mjs +288 -0
- package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
- package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
- package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
- package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
- package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
- package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
- package/workflows/wechat-reading-shots/workflow.mjs +266 -0
- package/workflows/wrong-question-docx/README.md +55 -0
- package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
- package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
- package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
- package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
- package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
- package/workflows/wrong-question-docx/workflow.mjs +485 -0
- package/plugins/workflow-runner/src/agentCommon.js +0 -354
- package/plugins/workflow-runner/src/agentCommon.ts +0 -435
- package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
- package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
- package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
- package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
- package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
- package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
- package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
- package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
- package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
- package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
- package/plugins/workflow-runner/src/dslManifest.js +0 -72
- package/plugins/workflow-runner/src/dslManifest.ts +0 -127
- package/plugins/workflow-runner/src/expressions.js +0 -618
- package/plugins/workflow-runner/src/expressions.ts +0 -622
- package/plugins/workflow-runner/src/loader.js +0 -573
- package/plugins/workflow-runner/src/loader.ts +0 -721
- package/plugins/workflow-runner/src/multimodal.js +0 -38
- package/plugins/workflow-runner/src/multimodal.ts +0 -64
- package/plugins/workflow-runner/src/recovery.js +0 -119
- package/plugins/workflow-runner/src/recovery.ts +0 -149
- package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
- package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
- package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
- package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
- package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
- package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
- package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
- package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
- package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
- package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
- package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
- package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
- package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
- package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
- package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
- package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
- package/plugins/workflow-runner/src/stepPipeline.js +0 -277
- package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
- package/plugins/workflow-runner/test/agent.test.ts +0 -587
- package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
- package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
- package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
- package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
- package/plugins/workflow-runner/test/context-files.test.ts +0 -320
- package/plugins/workflow-runner/test/e2e.test.ts +0 -370
- package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
- package/plugins/workflow-runner/test/expressions.test.ts +0 -397
- package/plugins/workflow-runner/test/foundation.test.ts +0 -126
- package/plugins/workflow-runner/test/graceful.test.ts +0 -139
- package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
- package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
- package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
- package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
- package/plugins/workflow-runner/test/loader.test.ts +0 -617
- package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
- package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
- package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
- package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
- package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
- package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
- package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
- package/plugins/workflow-runner/test/recovery.test.ts +0 -265
- package/plugins/workflow-runner/test/runner.test.ts +0 -911
- package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
- package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
- package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
- package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
- package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
- package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
- package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
- package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
- package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
- package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
- package/plugins/workflow-runner/test/word.load.test.ts +0 -208
- package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
- package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
- package/src/advisorState.js +0 -22
- package/src/cli/configWizard.js +0 -293
- package/src/tools/toolProgressBridge.js +0 -48
- package/workflows/adaptive-research.yaml +0 -50
- package/workflows/book-review-short.yaml +0 -125
- package/workflows/e2e-write-greet.yaml +0 -31
- package/workflows/illustrate.yaml +0 -227
- package/workflows/plan.yaml +0 -470
- package/workflows/ppt.yaml +0 -1670
- package/workflows/ralph-loop.yaml +0 -199
- package/workflows/schema.json +0 -176
- package/workflows/webppt.yaml +0 -496
- package/workflows/wechat-reading-shots.yaml +0 -315
- package/workflows/word.yaml +0 -720
- package/workflows/youtube-shorts.yaml +0 -202
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* plugins/workflow-runner/src/util.ts —— 引擎内共用小件
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 只放「多处要用、又不值得单开文件」的纯函数。有任何状态或 IO 的都不该进这里。
|
|
6
|
+
* ============================================================
|
|
7
|
+
*/
|
|
8
|
+
import { resolve, sep } from 'node:path';
|
|
9
|
+
/** 截断到 n 个字符,超出补省略号。 */
|
|
10
|
+
export function truncate(s, n) {
|
|
11
|
+
return s.length > n ? `${s.slice(0, n)}…` : s;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 把一个声明产物路径收敛成「相对 workingDir 的安全相对路径」;越界返回 null。
|
|
15
|
+
*
|
|
16
|
+
* 自 legacy `types.ts` 原样移植,两处判据都是踩出来的,改之前先读:
|
|
17
|
+
*
|
|
18
|
+
* ① **前缀匹配必须带路径分隔符边界**。裸 `startsWith(base)` 会让 `/repo` 匹配上
|
|
19
|
+
* `/repo-hack/evil` —— 一个只差几个字符的兄弟目录就能骗过越界检查。
|
|
20
|
+
*
|
|
21
|
+
* ② **Windows 上比较前要统一大小写**。NTFS 不区分大小写,`D:\Code` 与 `D:\code`
|
|
22
|
+
* 是同一个目录,逐字节比较会把合法路径判成越界。(相关教训见记忆
|
|
23
|
+
* `project_windows_path_separator_gotcha`:同一类判据写死 `/` 分隔符时,
|
|
24
|
+
* Windows 上条件恒为 false,缓存清理曾因此静默失效。)
|
|
25
|
+
*/
|
|
26
|
+
export function safeArtifactPath(workingDir, rawPath) {
|
|
27
|
+
if (!rawPath || typeof rawPath !== 'string')
|
|
28
|
+
return null;
|
|
29
|
+
const base = resolve(workingDir);
|
|
30
|
+
const baseWithSep = base.endsWith(sep) ? base : base + sep;
|
|
31
|
+
let abs;
|
|
32
|
+
try {
|
|
33
|
+
abs = resolve(workingDir, rawPath);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const sameCase = (p) => process.platform === 'win32' ? p.toLowerCase() : p;
|
|
39
|
+
const nAbs = sameCase(abs);
|
|
40
|
+
const nBase = sameCase(base);
|
|
41
|
+
const nBaseSep = sameCase(baseWithSep);
|
|
42
|
+
// 恰好等于 base 本身(rawPath='.' 这种极端情形)也算合法。
|
|
43
|
+
if (nAbs !== nBase && !nAbs.startsWith(nBaseSep))
|
|
44
|
+
return null;
|
|
45
|
+
const rel = abs.slice(base.length).replace(/^[/\\]/, '');
|
|
46
|
+
return rel.length === 0 ? '.' : rel;
|
|
47
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ============================================================
|
|
3
|
+
* plugins/workflow-runner/src/util.ts —— 引擎内共用小件
|
|
4
|
+
* ------------------------------------------------------------
|
|
5
|
+
* 只放「多处要用、又不值得单开文件」的纯函数。有任何状态或 IO 的都不该进这里。
|
|
6
|
+
* ============================================================
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { resolve, sep } from 'node:path';
|
|
10
|
+
|
|
11
|
+
/** 截断到 n 个字符,超出补省略号。 */
|
|
12
|
+
export function truncate(s: string, n: number): string {
|
|
13
|
+
return s.length > n ? `${s.slice(0, n)}…` : s;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 把一个声明产物路径收敛成「相对 workingDir 的安全相对路径」;越界返回 null。
|
|
18
|
+
*
|
|
19
|
+
* 自 legacy `types.ts` 原样移植,两处判据都是踩出来的,改之前先读:
|
|
20
|
+
*
|
|
21
|
+
* ① **前缀匹配必须带路径分隔符边界**。裸 `startsWith(base)` 会让 `/repo` 匹配上
|
|
22
|
+
* `/repo-hack/evil` —— 一个只差几个字符的兄弟目录就能骗过越界检查。
|
|
23
|
+
*
|
|
24
|
+
* ② **Windows 上比较前要统一大小写**。NTFS 不区分大小写,`D:\Code` 与 `D:\code`
|
|
25
|
+
* 是同一个目录,逐字节比较会把合法路径判成越界。(相关教训见记忆
|
|
26
|
+
* `project_windows_path_separator_gotcha`:同一类判据写死 `/` 分隔符时,
|
|
27
|
+
* Windows 上条件恒为 false,缓存清理曾因此静默失效。)
|
|
28
|
+
*/
|
|
29
|
+
export function safeArtifactPath(
|
|
30
|
+
workingDir: string,
|
|
31
|
+
rawPath: string,
|
|
32
|
+
): string | null {
|
|
33
|
+
if (!rawPath || typeof rawPath !== 'string') return null;
|
|
34
|
+
const base = resolve(workingDir);
|
|
35
|
+
const baseWithSep = base.endsWith(sep) ? base : base + sep;
|
|
36
|
+
let abs: string;
|
|
37
|
+
try {
|
|
38
|
+
abs = resolve(workingDir, rawPath);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const sameCase = (p: string): string =>
|
|
43
|
+
process.platform === 'win32' ? p.toLowerCase() : p;
|
|
44
|
+
const nAbs = sameCase(abs);
|
|
45
|
+
const nBase = sameCase(base);
|
|
46
|
+
const nBaseSep = sameCase(baseWithSep);
|
|
47
|
+
// 恰好等于 base 本身(rawPath='.' 这种极端情形)也算合法。
|
|
48
|
+
if (nAbs !== nBase && !nAbs.startsWith(nBaseSep)) return null;
|
|
49
|
+
const rel = abs.slice(base.length).replace(/^[/\\]/, '');
|
|
50
|
+
return rel.length === 0 ? '.' : rel;
|
|
51
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import capabilities from './workflowContextCapabilities.json' with { type: 'json' };
|
|
2
|
+
export const WORKFLOW_CONTEXT_CAPABILITIES = capabilities;
|
|
3
|
+
export function assertWorkflowContextShape(value) {
|
|
4
|
+
const context = value;
|
|
5
|
+
for (const [group, names] of Object.entries(WORKFLOW_CONTEXT_CAPABILITIES)) {
|
|
6
|
+
const actual = context[group];
|
|
7
|
+
if (!actual || typeof actual !== 'object') {
|
|
8
|
+
throw new Error(`WorkflowContext 缺少能力组 wf.${group}`);
|
|
9
|
+
}
|
|
10
|
+
const keys = Object.keys(actual).sort();
|
|
11
|
+
const expected = [...names].sort();
|
|
12
|
+
const missing = expected.filter((name) => !keys.includes(name));
|
|
13
|
+
const extra = keys.filter((name) => !expected.includes(name));
|
|
14
|
+
if (missing.length || extra.length) {
|
|
15
|
+
throw new Error(`WorkflowContext wf.${group} 与能力注册表不同步` +
|
|
16
|
+
`${missing.length ? `;缺少 ${missing.join(', ')}` : ''}` +
|
|
17
|
+
`${extra.length ? `;多出 ${extra.join(', ')}` : ''}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import capabilities from './workflowContextCapabilities.json' with { type: 'json' };
|
|
2
|
+
|
|
3
|
+
export const WORKFLOW_CONTEXT_CAPABILITIES = capabilities as Readonly<
|
|
4
|
+
Record<string, readonly string[]>
|
|
5
|
+
>;
|
|
6
|
+
|
|
7
|
+
export interface WorkflowPipelineSuccess<T = unknown> {
|
|
8
|
+
ok: true;
|
|
9
|
+
index: number;
|
|
10
|
+
value: T;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface WorkflowPipelineFailure {
|
|
14
|
+
ok: false;
|
|
15
|
+
index: number;
|
|
16
|
+
error: { name: string; message: string; code?: string };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface WorkflowPipelineResult<T = unknown> {
|
|
20
|
+
results: (WorkflowPipelineSuccess<T> | WorkflowPipelineFailure)[];
|
|
21
|
+
succeeded: number;
|
|
22
|
+
failed: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Public V2 contract. Function signatures remain structural so the registry is the key truth. */
|
|
26
|
+
export interface WorkflowContext {
|
|
27
|
+
input: { values: Record<string, unknown>; resources: Record<string, unknown> };
|
|
28
|
+
runtime: Record<string, unknown>;
|
|
29
|
+
model: Record<string, (...args: any[]) => any>;
|
|
30
|
+
tools: Record<string, (...args: any[]) => any>;
|
|
31
|
+
exec: Record<string, (...args: any[]) => any>;
|
|
32
|
+
fs: Record<string, (...args: any[]) => any>;
|
|
33
|
+
flow: Record<string, (...args: any[]) => any>;
|
|
34
|
+
check: Record<string, (...args: any[]) => any>;
|
|
35
|
+
state: Record<string, (...args: any[]) => any>;
|
|
36
|
+
output: Record<string, (...args: any[]) => any>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function assertWorkflowContextShape(value: object): void {
|
|
40
|
+
const context = value as Record<string, unknown>;
|
|
41
|
+
for (const [group, names] of Object.entries(WORKFLOW_CONTEXT_CAPABILITIES)) {
|
|
42
|
+
const actual = context[group];
|
|
43
|
+
if (!actual || typeof actual !== 'object') {
|
|
44
|
+
throw new Error(`WorkflowContext 缺少能力组 wf.${group}`);
|
|
45
|
+
}
|
|
46
|
+
const keys = Object.keys(actual).sort();
|
|
47
|
+
const expected = [...names].sort();
|
|
48
|
+
const missing = expected.filter((name) => !keys.includes(name));
|
|
49
|
+
const extra = keys.filter((name) => !expected.includes(name));
|
|
50
|
+
if (missing.length || extra.length) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`WorkflowContext wf.${group} 与能力注册表不同步` +
|
|
53
|
+
`${missing.length ? `;缺少 ${missing.join(', ')}` : ''}` +
|
|
54
|
+
`${extra.length ? `;多出 ${extra.join(', ')}` : ''}`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { discoverWorkflows } from './discovery.js';
|
|
2
|
+
import { fingerprint } from './journal.js';
|
|
3
|
+
import { workflowFingerprint } from './workflowFingerprint.js';
|
|
4
|
+
/** Resolve once per root execution using the same override precedence as /workflow. */
|
|
5
|
+
export async function resolveWorkflowBundle(root, cwd) {
|
|
6
|
+
const discovered = root.meta.dependencies?.length
|
|
7
|
+
? await discoverWorkflows(cwd)
|
|
8
|
+
: { workflows: [], failures: [] };
|
|
9
|
+
const scripts = new Map(discovered.workflows.map((s) => [s.name, s]));
|
|
10
|
+
scripts.set(root.name, root);
|
|
11
|
+
async function visit(script, ancestors) {
|
|
12
|
+
if (ancestors.includes(script.name))
|
|
13
|
+
throw new Error(`工作流依赖环:${[...ancestors, script.name].join(' → ')}`);
|
|
14
|
+
if (ancestors.length >= 8)
|
|
15
|
+
throw new Error('子工作流嵌套超过8层');
|
|
16
|
+
if (ancestors.length && script.meta.managedRuntime)
|
|
17
|
+
throw new Error(`不能把 managedRuntime 工作流 ${script.name} 作为子流程调用`);
|
|
18
|
+
const children = new Map();
|
|
19
|
+
for (const name of script.meta.dependencies ?? []) {
|
|
20
|
+
const child = scripts.get(name);
|
|
21
|
+
if (!child)
|
|
22
|
+
throw new Error(`依赖工作流 ${name} 不可用:${discovered.failures.find((f) => f.name === name)?.errors.join('; ') ?? '未找到'}`);
|
|
23
|
+
children.set(name, await visit(child, [...ancestors, script.name]));
|
|
24
|
+
}
|
|
25
|
+
const own = await workflowFingerprint(script.source, script.dir, script.meta.packages ?? []);
|
|
26
|
+
// Keep legacy leaf fingerprints, avoiding unrelated invalidations.
|
|
27
|
+
const hash = children.size
|
|
28
|
+
? fingerprint('workflow-tree-v1', {
|
|
29
|
+
own,
|
|
30
|
+
children: [...children].map(([name, b]) => [name, b.hash]),
|
|
31
|
+
})
|
|
32
|
+
: own;
|
|
33
|
+
return { script, hash, children };
|
|
34
|
+
}
|
|
35
|
+
return visit(root, []);
|
|
36
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { discoverWorkflows } from './discovery.js';
|
|
2
|
+
import { fingerprint } from './journal.js';
|
|
3
|
+
import type { WorkflowScript } from './types.js';
|
|
4
|
+
import { workflowFingerprint } from './workflowFingerprint.js';
|
|
5
|
+
|
|
6
|
+
export interface WorkflowBundle {
|
|
7
|
+
script: WorkflowScript;
|
|
8
|
+
hash: string;
|
|
9
|
+
children: Map<string, WorkflowBundle>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Resolve once per root execution using the same override precedence as /workflow. */
|
|
13
|
+
export async function resolveWorkflowBundle(
|
|
14
|
+
root: WorkflowScript,
|
|
15
|
+
cwd: string,
|
|
16
|
+
): Promise<WorkflowBundle> {
|
|
17
|
+
const discovered = root.meta.dependencies?.length
|
|
18
|
+
? await discoverWorkflows(cwd)
|
|
19
|
+
: { workflows: [], failures: [] };
|
|
20
|
+
const scripts = new Map(discovered.workflows.map((s) => [s.name, s]));
|
|
21
|
+
scripts.set(root.name, root);
|
|
22
|
+
async function visit(
|
|
23
|
+
script: WorkflowScript,
|
|
24
|
+
ancestors: string[],
|
|
25
|
+
): Promise<WorkflowBundle> {
|
|
26
|
+
if (ancestors.includes(script.name))
|
|
27
|
+
throw new Error(
|
|
28
|
+
`工作流依赖环:${[...ancestors, script.name].join(' → ')}`,
|
|
29
|
+
);
|
|
30
|
+
if (ancestors.length >= 8) throw new Error('子工作流嵌套超过8层');
|
|
31
|
+
if (ancestors.length && script.meta.managedRuntime)
|
|
32
|
+
throw new Error(
|
|
33
|
+
`不能把 managedRuntime 工作流 ${script.name} 作为子流程调用`,
|
|
34
|
+
);
|
|
35
|
+
const children = new Map<string, WorkflowBundle>();
|
|
36
|
+
for (const name of script.meta.dependencies ?? []) {
|
|
37
|
+
const child = scripts.get(name);
|
|
38
|
+
if (!child)
|
|
39
|
+
throw new Error(
|
|
40
|
+
`依赖工作流 ${name} 不可用:${discovered.failures.find((f) => f.name === name)?.errors.join('; ') ?? '未找到'}`,
|
|
41
|
+
);
|
|
42
|
+
children.set(name, await visit(child, [...ancestors, script.name]));
|
|
43
|
+
}
|
|
44
|
+
const own = await workflowFingerprint(
|
|
45
|
+
script.source,
|
|
46
|
+
script.dir,
|
|
47
|
+
script.meta.packages ?? [],
|
|
48
|
+
);
|
|
49
|
+
// Keep legacy leaf fingerprints, avoiding unrelated invalidations.
|
|
50
|
+
const hash = children.size
|
|
51
|
+
? fingerprint('workflow-tree-v1', {
|
|
52
|
+
own,
|
|
53
|
+
children: [...children].map(([name, b]) => [name, b.hash]),
|
|
54
|
+
})
|
|
55
|
+
: own;
|
|
56
|
+
return { script, hash, children };
|
|
57
|
+
}
|
|
58
|
+
return visit(root, []);
|
|
59
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { readFile, readdir, lstat } from 'node:fs/promises';
|
|
4
|
+
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
5
|
+
import { pathContains } from '../../../src/plugin-sdk.js';
|
|
6
|
+
import { moduleImports, packageName, resolveRelativeModule } from './moduleResolution.js';
|
|
7
|
+
/**
|
|
8
|
+
* 宿主引擎自身的 npm 包名(`package.json::name`)。硬编码、人工同步,**不**在
|
|
9
|
+
* 这里动态读 `package.json`:这个文件会被绿色版 `bun --compile` 编译进单文件
|
|
10
|
+
* exe,届时 `import.meta.url` 变成虚拟路径——用相对路径去定位磁盘上的
|
|
11
|
+
* `package.json` 会复现 CLAUDE.md 反复警告过的那类绿色版地雷。改包名时要与
|
|
12
|
+
* `scriptGuard.mjs::HOST_PACKAGE_NAME` 一起改。
|
|
13
|
+
*/
|
|
14
|
+
const HOST_PACKAGE_NAME = 'minimal-agent';
|
|
15
|
+
async function packageVersion(entry, name) {
|
|
16
|
+
let cursor = dirname(entry);
|
|
17
|
+
for (;;) {
|
|
18
|
+
const manifest = join(cursor, 'package.json');
|
|
19
|
+
try {
|
|
20
|
+
const value = JSON.parse(await readFile(manifest, 'utf8'));
|
|
21
|
+
if (value.name === name && value.version)
|
|
22
|
+
return value.version;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// continue upwards
|
|
26
|
+
}
|
|
27
|
+
const parent = dirname(cursor);
|
|
28
|
+
if (parent === cursor)
|
|
29
|
+
break;
|
|
30
|
+
cursor = parent;
|
|
31
|
+
}
|
|
32
|
+
return 'unknown';
|
|
33
|
+
}
|
|
34
|
+
/** Fingerprint executable ESM graph, prompts/assets, and declared package versions. */
|
|
35
|
+
export async function workflowFingerprint(source, dir, packages = []) {
|
|
36
|
+
const hash = createHash('sha256').update('workflow-bundle-v2\0');
|
|
37
|
+
const entry = join(dir, 'workflow.mjs');
|
|
38
|
+
const seen = new Set();
|
|
39
|
+
const importedPackages = new Set();
|
|
40
|
+
async function addModule(path, knownSource) {
|
|
41
|
+
const absolute = resolve(path);
|
|
42
|
+
if (!pathContains(dir, absolute)) {
|
|
43
|
+
throw new Error(`工作流相对模块越出工作流目录:${absolute}`);
|
|
44
|
+
}
|
|
45
|
+
if (seen.has(absolute))
|
|
46
|
+
return;
|
|
47
|
+
seen.add(absolute);
|
|
48
|
+
const text = knownSource ?? (await readFile(absolute, 'utf8'));
|
|
49
|
+
const name = relative(dir, absolute).split(sep).join('/');
|
|
50
|
+
hash.update(JSON.stringify(['module', name, Buffer.byteLength(text)])).update(text);
|
|
51
|
+
for (const specifier of moduleImports(text)) {
|
|
52
|
+
if (specifier.startsWith('.')) {
|
|
53
|
+
await addModule(await resolveRelativeModule(absolute, specifier));
|
|
54
|
+
}
|
|
55
|
+
else if (specifier.startsWith('node:')) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
else if (specifier.startsWith('/') || specifier.startsWith('file:')) {
|
|
59
|
+
throw new Error(`工作流 ESM import 不得使用绝对路径:${specifier}`);
|
|
60
|
+
}
|
|
61
|
+
else if (packageName(specifier) === HOST_PACKAGE_NAME) {
|
|
62
|
+
// 第二道闸,对齐 scriptGuard.mjs 的同名检查:包自引用 +
|
|
63
|
+
// package.json::exports 的 "./src/*"/"./plugins/*" 通配符会让
|
|
64
|
+
// `minimal-agent/src/xxx` 解析到真实内核文件,完全绕开 wf 分组能力
|
|
65
|
+
// 对象。声明进 meta.packages 也无法绕过这条——即使调用顺序以后变了、
|
|
66
|
+
// discovery.ts 没能先跑 scriptGuard 校验,这里仍然拦得住。
|
|
67
|
+
throw new Error(`工作流禁止 import 宿主引擎自身(${specifier}):一切对内核的访问必须经 wf 分组能力对象。`);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
importedPackages.add(packageName(specifier));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
await addModule(entry, source);
|
|
75
|
+
async function visit(relativeDir) {
|
|
76
|
+
let entries;
|
|
77
|
+
try {
|
|
78
|
+
if ((await lstat(join(dir, relativeDir))).isSymbolicLink())
|
|
79
|
+
throw new Error(`工作流随包资源不能是符号链接:${relativeDir}`);
|
|
80
|
+
entries = await readdir(join(dir, relativeDir), { withFileTypes: true });
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error.code === 'ENOENT')
|
|
84
|
+
return;
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
for (const item of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
88
|
+
const name = `${relativeDir}/${item.name}`;
|
|
89
|
+
if (item.isSymbolicLink())
|
|
90
|
+
throw new Error(`工作流随包资源不能是符号链接:${name}`);
|
|
91
|
+
if (item.isDirectory())
|
|
92
|
+
await visit(name);
|
|
93
|
+
else if (item.isFile() && !seen.has(resolve(dir, name))) {
|
|
94
|
+
const bytes = await readFile(join(dir, name));
|
|
95
|
+
hash.update(JSON.stringify(['resource', name, bytes.length])).update(bytes);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (const folder of ['prompts', 'scripts', 'assets'])
|
|
100
|
+
await visit(folder);
|
|
101
|
+
const require = createRequire(entry);
|
|
102
|
+
for (const name of importedPackages) {
|
|
103
|
+
if (!packages.includes(name)) {
|
|
104
|
+
throw new Error(`运行时包 ${name} 必须声明在 meta.packages 中。`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const name of [...packages].sort()) {
|
|
108
|
+
let resolved;
|
|
109
|
+
try {
|
|
110
|
+
resolved = require.resolve(name);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
throw new Error(`无法解析 meta.packages 中的 ${name}:${error instanceof Error ? error.message : String(error)}`);
|
|
114
|
+
}
|
|
115
|
+
hash.update(JSON.stringify(['package', name, await packageVersion(resolved, name)]));
|
|
116
|
+
}
|
|
117
|
+
return hash.digest('hex').slice(0, 16);
|
|
118
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { readFile, readdir, lstat } from 'node:fs/promises';
|
|
4
|
+
import type { Dirent } from 'node:fs';
|
|
5
|
+
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
6
|
+
|
|
7
|
+
import { pathContains } from '../../../src/plugin-sdk.js';
|
|
8
|
+
import { moduleImports, packageName, resolveRelativeModule } from './moduleResolution.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 宿主引擎自身的 npm 包名(`package.json::name`)。硬编码、人工同步,**不**在
|
|
12
|
+
* 这里动态读 `package.json`:这个文件会被绿色版 `bun --compile` 编译进单文件
|
|
13
|
+
* exe,届时 `import.meta.url` 变成虚拟路径——用相对路径去定位磁盘上的
|
|
14
|
+
* `package.json` 会复现 CLAUDE.md 反复警告过的那类绿色版地雷。改包名时要与
|
|
15
|
+
* `scriptGuard.mjs::HOST_PACKAGE_NAME` 一起改。
|
|
16
|
+
*/
|
|
17
|
+
const HOST_PACKAGE_NAME = 'minimal-agent';
|
|
18
|
+
|
|
19
|
+
async function packageVersion(entry: string, name: string): Promise<string> {
|
|
20
|
+
let cursor = dirname(entry);
|
|
21
|
+
for (;;) {
|
|
22
|
+
const manifest = join(cursor, 'package.json');
|
|
23
|
+
try {
|
|
24
|
+
const value = JSON.parse(await readFile(manifest, 'utf8')) as {
|
|
25
|
+
name?: string;
|
|
26
|
+
version?: string;
|
|
27
|
+
};
|
|
28
|
+
if (value.name === name && value.version) return value.version;
|
|
29
|
+
} catch {
|
|
30
|
+
// continue upwards
|
|
31
|
+
}
|
|
32
|
+
const parent = dirname(cursor);
|
|
33
|
+
if (parent === cursor) break;
|
|
34
|
+
cursor = parent;
|
|
35
|
+
}
|
|
36
|
+
return 'unknown';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Fingerprint executable ESM graph, prompts/assets, and declared package versions. */
|
|
40
|
+
export async function workflowFingerprint(
|
|
41
|
+
source: string,
|
|
42
|
+
dir: string,
|
|
43
|
+
packages: string[] = [],
|
|
44
|
+
): Promise<string> {
|
|
45
|
+
const hash = createHash('sha256').update('workflow-bundle-v2\0');
|
|
46
|
+
const entry = join(dir, 'workflow.mjs');
|
|
47
|
+
const seen = new Set<string>();
|
|
48
|
+
const importedPackages = new Set<string>();
|
|
49
|
+
|
|
50
|
+
async function addModule(path: string, knownSource?: string): Promise<void> {
|
|
51
|
+
const absolute = resolve(path);
|
|
52
|
+
if (!pathContains(dir, absolute)) {
|
|
53
|
+
throw new Error(`工作流相对模块越出工作流目录:${absolute}`);
|
|
54
|
+
}
|
|
55
|
+
if (seen.has(absolute)) return;
|
|
56
|
+
seen.add(absolute);
|
|
57
|
+
const text = knownSource ?? (await readFile(absolute, 'utf8'));
|
|
58
|
+
const name = relative(dir, absolute).split(sep).join('/');
|
|
59
|
+
hash.update(JSON.stringify(['module', name, Buffer.byteLength(text)])).update(text);
|
|
60
|
+
for (const specifier of moduleImports(text)) {
|
|
61
|
+
if (specifier.startsWith('.')) {
|
|
62
|
+
await addModule(await resolveRelativeModule(absolute, specifier));
|
|
63
|
+
} else if (specifier.startsWith('node:')) {
|
|
64
|
+
continue;
|
|
65
|
+
} else if (specifier.startsWith('/') || specifier.startsWith('file:')) {
|
|
66
|
+
throw new Error(`工作流 ESM import 不得使用绝对路径:${specifier}`);
|
|
67
|
+
} else if (packageName(specifier) === HOST_PACKAGE_NAME) {
|
|
68
|
+
// 第二道闸,对齐 scriptGuard.mjs 的同名检查:包自引用 +
|
|
69
|
+
// package.json::exports 的 "./src/*"/"./plugins/*" 通配符会让
|
|
70
|
+
// `minimal-agent/src/xxx` 解析到真实内核文件,完全绕开 wf 分组能力
|
|
71
|
+
// 对象。声明进 meta.packages 也无法绕过这条——即使调用顺序以后变了、
|
|
72
|
+
// discovery.ts 没能先跑 scriptGuard 校验,这里仍然拦得住。
|
|
73
|
+
throw new Error(
|
|
74
|
+
`工作流禁止 import 宿主引擎自身(${specifier}):一切对内核的访问必须经 wf 分组能力对象。`,
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
importedPackages.add(packageName(specifier));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await addModule(entry, source);
|
|
83
|
+
|
|
84
|
+
async function visit(relativeDir: string): Promise<void> {
|
|
85
|
+
let entries: Dirent[];
|
|
86
|
+
try {
|
|
87
|
+
if ((await lstat(join(dir, relativeDir))).isSymbolicLink())
|
|
88
|
+
throw new Error(`工作流随包资源不能是符号链接:${relativeDir}`);
|
|
89
|
+
entries = await readdir(join(dir, relativeDir), { withFileTypes: true });
|
|
90
|
+
} catch (error) {
|
|
91
|
+
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
for (const item of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
95
|
+
const name = `${relativeDir}/${item.name}`;
|
|
96
|
+
if (item.isSymbolicLink()) throw new Error(`工作流随包资源不能是符号链接:${name}`);
|
|
97
|
+
if (item.isDirectory()) await visit(name);
|
|
98
|
+
else if (item.isFile() && !seen.has(resolve(dir, name))) {
|
|
99
|
+
const bytes = await readFile(join(dir, name));
|
|
100
|
+
hash.update(JSON.stringify(['resource', name, bytes.length])).update(bytes);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
for (const folder of ['prompts', 'scripts', 'assets']) await visit(folder);
|
|
105
|
+
|
|
106
|
+
const require = createRequire(entry);
|
|
107
|
+
for (const name of importedPackages) {
|
|
108
|
+
if (!packages.includes(name)) {
|
|
109
|
+
throw new Error(`运行时包 ${name} 必须声明在 meta.packages 中。`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
for (const name of [...packages].sort()) {
|
|
113
|
+
let resolved: string;
|
|
114
|
+
try {
|
|
115
|
+
resolved = require.resolve(name);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
throw new Error(`无法解析 meta.packages 中的 ${name}:${error instanceof Error ? error.message : String(error)}`);
|
|
118
|
+
}
|
|
119
|
+
hash.update(JSON.stringify(['package', name, await packageVersion(resolved, name)]));
|
|
120
|
+
}
|
|
121
|
+
return hash.digest('hex').slice(0, 16);
|
|
122
|
+
}
|