minimal-agent 0.8.2 → 0.10.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 +14 -12
- package/package.json +34 -1
- package/plugins/cron-runner/.claude-plugin/plugin.json +5 -0
- package/plugins/cron-runner/commands/cron.md +26 -0
- package/plugins/cron-runner/commands/crons.md +7 -0
- package/plugins/cron-runner/plugin.js +34 -0
- package/plugins/cron-runner/src/commands.js +348 -0
- package/plugins/cron-runner/src/cronTime.js +148 -0
- package/plugins/cron-runner/src/lock.js +68 -0
- package/plugins/cron-runner/src/runs.js +89 -0
- package/plugins/cron-runner/src/scheduleEngine.js +72 -0
- package/plugins/cron-runner/src/scheduler.js +355 -0
- package/plugins/cron-runner/src/schema.js +140 -0
- package/plugins/cron-runner/src/service.js +167 -0
- package/plugins/cron-runner/src/store.js +298 -0
- package/plugins/cron-runner/src/types.js +1 -0
- package/plugins/workflow-runner/commands/workflow.md +4 -4
- package/plugins/workflow-runner/commands/workflows.md +1 -1
- package/plugins/workflow-runner/plugin.js +3 -1
- package/plugins/workflow-runner/src/agentCommon.js +249 -51
- package/plugins/workflow-runner/src/dslManifest.js +72 -0
- package/plugins/workflow-runner/src/expressions.js +198 -15
- package/plugins/workflow-runner/src/index.js +40 -8
- package/plugins/workflow-runner/src/jsonPayload.js +1 -1
- package/plugins/workflow-runner/src/loader.js +286 -72
- package/plugins/workflow-runner/src/multimodal.js +37 -0
- package/plugins/workflow-runner/src/recovery.js +49 -39
- package/plugins/workflow-runner/src/runner.js +802 -287
- package/plugins/workflow-runner/src/stepExecutors/agent.js +157 -39
- package/plugins/workflow-runner/src/stepExecutors/assert.js +16 -3
- package/plugins/workflow-runner/src/stepExecutors/llm.js +60 -111
- package/plugins/workflow-runner/src/stepExecutors/skill.js +47 -47
- package/plugins/workflow-runner/src/stepExecutors/tool.js +76 -10
- package/plugins/workflow-runner/src/stepExecutors/verify.js +27 -10
- package/plugins/workflow-runner/src/taskIdentity.js +296 -0
- package/plugins/workflow-runner/src/types.js +19 -9
- package/plugins/workflow-runner/src/workflowState.js +516 -33
- package/skills/adversarial-review/SKILL.md +0 -1
- package/skills/ai-image/SKILL.md +89 -0
- package/skills/ai-image/scripts/generate.mjs +497 -0
- package/skills/ai-image/scripts/generate_from_plan.mjs +469 -0
- package/skills/ai-image/scripts/generate_from_plan_test.mjs +223 -0
- package/skills/ai-image/scripts/generate_test.mjs +74 -0
- package/skills/browser-automation/SKILL.md +47 -0
- package/skills/docx/SKILL.md +25 -3
- 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/docx/scripts/opc_check.py +253 -0
- package/skills/image-gen-openrouter/SKILL.md +10 -2
- package/skills/image-stats/SKILL.md +65 -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/image-stats/scripts/image_stats.py +368 -0
- package/skills/image-stats/scripts/image_stats_test.py +181 -0
- package/skills/pptx/SKILL.md +123 -95
- package/skills/pptx/design.md +82 -0
- package/skills/pptx/examples/README.md +29 -0
- package/skills/pptx/examples/hybrid_example.mjs +107 -0
- package/skills/pptx/examples/hybrid_example.pptx +0 -0
- package/skills/pptx/pptxgenjs.md +41 -0
- package/skills/pptx/scripts/deck_helpers.mjs +224 -0
- package/skills/pptx/scripts/layout_lint.py +293 -0
- package/skills/pptx/scripts/layout_lint_test.py +160 -0
- package/skills/pptx/scripts/opc_check.py +339 -0
- package/skills/pptx/scripts/svg_fallback.mjs +145 -0
- package/skills/pptx/svg.md +67 -0
- package/skills/tts-zh/SKILL.md +19 -2
- package/skills/ui-design/SKILL.md +158 -0
- package/skills/ui-design/claude_design.md +309 -0
- package/skills/ui-design/evals/evals.json +254 -0
- package/skills/ui-design/references/aesthetic-direction.md +83 -0
- package/skills/ui-design/references/claude-design-protocol.md +36 -0
- package/skills/ui-design/references/design-context.md +53 -0
- package/skills/ui-design/references/design-execution-playbook.md +82 -0
- package/skills/ui-design/references/export-pptx.md +124 -0
- package/skills/ui-design/references/layout-composition.md +654 -0
- package/skills/ui-design/references/preview-feedback.md +37 -0
- package/skills/ui-design/references/source-image-layout.md +189 -0
- package/skills/ui-design/references/starter-components.md +78 -0
- package/skills/ui-design/references/vi-aegis-vector.md +144 -0
- package/skills/ui-design/references/vi-amber-prism.md +133 -0
- package/skills/ui-design/references/vi-aqua-glass.md +200 -0
- package/skills/ui-design/references/vi-comfort-vision.md +147 -0
- package/skills/ui-design/references/vi-ember-prism.md +140 -0
- package/skills/ui-design/references/vi-nebula-console.md +151 -0
- package/skills/ui-design/references/vi-obsidian-optics.md +139 -0
- package/skills/ui-design/references/vi-obsidian-xui.md +143 -0
- package/skills/ui-design/references/vi-precision-horizon-dark.md +117 -0
- package/skills/ui-design/references/vi-precision-horizon.md +215 -0
- package/skills/ui-design/references/vi-solar-relay.md +130 -0
- package/skills/ui-design/references/vi-template-workflow.md +48 -0
- package/skills/ui-design/references/vi-verdant-grid.md +141 -0
- package/skills/ui-design/references/vi-violet-meridian.md +172 -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/ui-design/scripts/assemble_material.py +217 -0
- package/skills/ui-design/scripts/assemble_material_test.py +149 -0
- package/skills/ui-design/scripts/browser_check_ui_artifact.mjs +221 -0
- package/skills/ui-design/scripts/chart_sanity_check.py +261 -0
- package/skills/ui-design/scripts/chart_sanity_check_test.py +165 -0
- package/skills/ui-design/scripts/check_language_policy.py +351 -0
- package/skills/ui-design/scripts/check_ui_artifact.py +435 -0
- package/skills/ui-design/scripts/check_ui_artifact_pptx_test.py +251 -0
- package/skills/ui-design/scripts/deck_pages_check.py +158 -0
- package/skills/ui-design/scripts/deck_pages_check_test.py +134 -0
- package/skills/ui-design/scripts/deck_visual_style_check.py +767 -0
- package/skills/ui-design/scripts/deck_visual_style_check_test.py +713 -0
- package/skills/ui-design/scripts/design_budget_check.py +271 -0
- package/skills/ui-design/scripts/design_budget_check_test.py +183 -0
- package/skills/ui-design/scripts/design_repair_hints.py +162 -0
- package/skills/ui-design/scripts/design_repair_hints_test.py +54 -0
- package/skills/ui-design/scripts/design_style_check.py +397 -0
- package/skills/ui-design/scripts/design_style_check_test.py +233 -0
- package/skills/ui-design/scripts/draft_coverage_check.py +184 -0
- package/skills/ui-design/scripts/draft_coverage_check_test.py +131 -0
- package/skills/ui-design/scripts/export_pptx_from_html.mjs +2367 -0
- package/skills/ui-design/scripts/extract_source_assets.py +607 -0
- package/skills/ui-design/scripts/extract_source_assets_test.py +256 -0
- package/skills/ui-design/scripts/generated_image_review_collect.py +206 -0
- package/skills/ui-design/scripts/generated_image_review_collect_test.py +91 -0
- package/skills/ui-design/scripts/image_plan_lint.py +571 -0
- package/skills/ui-design/scripts/image_plan_lint_test.py +515 -0
- package/skills/ui-design/scripts/image_prompt_rewrite.py +713 -0
- package/skills/ui-design/scripts/image_prompt_rewrite_test.py +966 -0
- package/skills/ui-design/scripts/layout_balance.py +881 -0
- package/skills/ui-design/scripts/layout_balance_test.py +927 -0
- package/skills/ui-design/scripts/normalize_design_json.py +272 -0
- package/skills/ui-design/scripts/normalize_design_json_test.py +119 -0
- package/skills/ui-design/scripts/plan_source_layout.py +1450 -0
- package/skills/ui-design/scripts/plan_source_layout_test.py +1136 -0
- package/skills/ui-design/scripts/resolve_source_input.py +270 -0
- package/skills/ui-design/scripts/resolve_source_input_test.py +98 -0
- package/skills/ui-design/scripts/scaffold_ui_artifact.py +377 -0
- package/skills/ui-design/scripts/source_usage_check.py +581 -0
- package/skills/ui-design/scripts/source_usage_check_test.py +427 -0
- package/skills/ui-design/scripts/text_readability_pixel.py +340 -0
- package/skills/ui-design/scripts/text_readability_pixel_test.py +219 -0
- package/skills/ui-design/scripts/visual_quality_gate.py +301 -0
- package/skills/ui-design/scripts/visual_quality_gate_test.py +233 -0
- package/skills/ui-design/tests/e2e/prompts/deck.md +19 -0
- package/skills/ui-design/tests/e2e/prompts/webpage.md +17 -0
- package/skills/ui-design/tests/e2e/render_check.mjs +101 -0
- package/skills/ui-design/tests/e2e/rubric.json +54 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/language-check.txt +12 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/static-check.txt +15 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/outputs/index.html +837 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/review.md +21 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/homepage.html +373 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/platform.html +378 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/outputs/index.html +656 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/render_check.mjs +67 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/outputs/index.html +587 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/prompt.md +12 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/review.md +36 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/language-check.txt +8 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/static-check.txt +16 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/outputs/index.html +739 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/prompt.md +11 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/review.md +22 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/checks/browser-check.json +52 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/outputs/index.html +641 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/outputs/index.html +467 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/homepage.html +373 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/platform.html +378 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/language-check.txt +4 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/execution_notes.md +10 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/outputs/index.html +587 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/prompt.md +14 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/review.md +13 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/browser-check.json +24 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/execution_notes.md +21 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/outputs/deck.html +451 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-01.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-02.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/review.md +79 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/browser-check.json +26 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/execution_notes.md +20 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/outputs/index.html +534 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/browser-check.json +64 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/language-check.txt +7 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-console.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-homepage.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/console.html +600 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/homepage.html +556 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/prompt.md +29 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/review.md +57 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/browser-check.json +33 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/language-check.txt +6 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/outputs/index.html +682 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/review.md +59 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-01.html +466 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-02.html +433 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/prompt.md +13 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/language-check.txt +3 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/execution_notes.md +24 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/outputs/index.html +723 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/prompt.md +15 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/review.md +26 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-dark.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-light.json +49 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/language-check.txt +11 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-dark.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-light.txt +3 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/execution_notes.md +23 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/dark.html +392 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/light.html +476 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/prompt.md +23 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/review.md +41 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/browser-check.json +54 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/language-check.txt +5 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/outputs/index.html +765 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/prompt.md +15 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/review.md +59 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/outputs/index.html +508 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/browser-check.json +49 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/mobile.png +0 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/browser-check.json +54 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/language-check.txt +6 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/quick-validate.txt +1 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/static-check.txt +2 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/outputs/index.html +788 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/prompt.md +14 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/review.md +60 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/desktop.png +0 -0
- package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/mobile.png +0 -0
- package/skills/video-compose/SKILL.md +8 -1
- package/skills/web-crawler/SKILL.md +70 -0
- package/skills/web-crawler/scripts/crawl.mjs +538 -0
- package/skills/web-crawler/scripts/crawl.test.mjs +204 -0
- package/skills/xlsx/SKILL.md +12 -0
- package/skills/xlsx/scripts/opc_check.py +253 -0
- package/src/advisorState.js +22 -0
- package/src/askBridge.js +97 -3
- package/src/bootstrap/workingDir.js +12 -1
- package/src/cli/args.js +17 -1
- package/src/cli/configMenu.js +236 -0
- package/src/cli/configWizard.js +7 -5
- package/src/cli/print.js +37 -4
- package/src/cli/streamJson.js +77 -24
- package/src/cli/wizards/advisorWizard.js +147 -0
- package/src/cli/wizards/fieldForm.js +149 -0
- package/src/cli/wizards/imageWizard.js +60 -0
- package/src/cli/wizards/openRouterWizard.js +23 -0
- package/src/cli/wizards/providerPresets.js +95 -0
- package/src/cli/wizards/providerWizard.js +219 -0
- package/src/cli/wizards/searchWizard.js +23 -0
- package/src/cli/wizards/ttsWizard.js +34 -0
- package/src/config/configFile.js +441 -83
- package/src/config/configService.js +446 -0
- package/src/config.js +24 -64
- package/src/context/agentHome.js +9 -0
- package/src/context/archive.js +7 -2
- package/src/context/compact.js +8 -5
- package/src/context/contextLock.js +81 -0
- package/src/context/persistContext.js +30 -11
- package/src/context/reactiveCompact.js +4 -2
- package/src/context/recentDirs.js +21 -61
- package/src/context/sessionPath.js +97 -23
- package/src/context/sessionRegistry.js +303 -24
- package/src/context/tokenCounter.js +18 -0
- package/src/context/workspaceIndex.js +731 -0
- package/src/infra/verification.js +28 -15
- package/src/llm/client.js +394 -159
- package/src/llm/providers/anthropicFormat.js +241 -0
- package/src/llm/providers/openaiFormat.js +190 -0
- package/src/loop.js +219 -32
- package/src/main.js +61 -11
- package/src/messageQueue.js +97 -0
- package/src/multimodal.js +203 -0
- package/src/plugin-sdk.js +15 -0
- package/src/plugins/commandRouter.js +3 -0
- package/src/plugins/hookEngine.js +5 -1
- package/src/plugins/pluginLifecycle.js +28 -0
- package/src/plugins/pluginLoader.js +2 -1
- package/src/plugins/pluginRunner.js +49 -21
- package/src/plugins/transcript.js +4 -3
- package/src/prompts/pluginList.js +5 -5
- package/src/prompts/projectInstructions.js +3 -3
- package/src/prompts/promptAssembly.js +133 -144
- package/src/prompts/skillList.js +12 -22
- package/src/prompts/system.js +0 -1
- package/src/session/runAgentTurn.js +70 -0
- package/src/session/runTurn.js +41 -6
- package/src/toolGate.js +17 -0
- package/src/tools/advisor/advisor.js +379 -0
- package/src/tools/agent/agent.js +555 -0
- package/src/tools/agent/agentTypes.js +59 -0
- package/src/tools/agent/coordinator.js +93 -0
- package/src/tools/agent/worktree.js +270 -0
- package/src/tools/ask/ask.js +7 -2
- package/src/tools/bash/bash.js +112 -18
- package/src/tools/download/download.js +144 -0
- package/src/tools/edit/edit.js +1 -0
- package/src/tools/edit/multi-edit.js +1 -0
- package/src/tools/genimage/genimage.js +242 -0
- package/src/tools/genspeech/genspeech.js +67 -0
- package/src/tools/glob/glob.js +1 -0
- package/src/tools/grep/grep.js +3 -0
- package/src/tools/grep/rgPath.js +2 -0
- package/src/tools/index.js +25 -2
- package/src/tools/read/read.js +1 -0
- package/src/tools/shared/killTree.js +52 -0
- package/src/tools/toolProgressBridge.js +48 -0
- package/src/tools/webbrowser/agentBrowserPath.js +258 -0
- package/src/tools/webbrowser/browser.js +59 -42
- package/src/tools/webbrowser/browserControl.js +118 -0
- package/src/tools/webbrowser/browserDaemon.js +97 -0
- package/src/tools/webbrowser/browserService.js +27 -0
- package/src/tools/webbrowser/browserStream.js +119 -0
- package/src/tools/webbrowser/webbrowser.js +699 -130
- package/src/tools/webfetch/webfetch.js +1 -0
- package/src/tools/websearch/websearch.js +134 -51
- package/src/tools/write/write.js +1 -0
- package/src/ui/App.js +249 -22
- package/src/ui/AskQuestion.js +29 -10
- package/src/ui/InputBox.js +104 -12
- package/src/ui/LiveArea.js +112 -19
- package/src/ui/MessageList.js +100 -14
- package/src/ui/ModelPicker.js +56 -0
- package/src/ui/QueuedMessagesBanner.js +14 -0
- package/src/ui/Root.js +18 -10
- package/src/ui/SessionPicker.js +102 -0
- package/src/ui/StatusLine.js +13 -4
- package/src/ui/WorkspacePicker.js +55 -0
- package/src/ui/figures.js +44 -0
- package/src/ui/hooks/askSlot.js +82 -0
- package/src/ui/hooks/useChat.js +358 -64
- package/src/ui/hooks/usePasteHandler.js +11 -1
- package/src/ui/hooks/useTextBuffer.js +1 -3
- package/src/ui/liveViewport.js +5 -1
- package/src/ui/markdown.js +206 -0
- package/src/ui/textBuffer.js +0 -7
- package/src/ui/theme.js +32 -0
- package/src/utils/debugLog.js +0 -4
- package/src/utils/resourcePaths.js +2 -2
- package/src/utils/stripThink.js +50 -0
- package/src/web/browserBridge.js +447 -0
- package/src/web/protocol.js +19 -0
- package/workflows/adaptive-research.yaml +13 -5
- package/workflows/book-review-short.yaml +36 -10
- package/workflows/e2e-write-greet.yaml +6 -2
- package/workflows/illustrate.yaml +227 -0
- package/workflows/plan.yaml +460 -179
- package/workflows/ppt.yaml +1659 -0
- package/workflows/ralph-loop.yaml +199 -0
- package/workflows/schema.json +81 -23
- package/workflows/webppt.yaml +496 -0
- package/workflows/word.yaml +710 -0
- package/workflows/youtube-shorts.yaml +46 -15
- package/MINIMAL-TRACE.md +0 -77
- package/plugins/HOW-TO-WRITE-A-PLUGIN.md +0 -186
- package/plugins/ralph-wiggum/.claude-plugin/plugin.json +0 -9
- package/plugins/ralph-wiggum/README.md +0 -197
- package/plugins/ralph-wiggum/commands/cancel-ralph.md +0 -18
- package/plugins/ralph-wiggum/commands/help.md +0 -137
- package/plugins/ralph-wiggum/commands/ralph-loop.md +0 -85
- package/plugins/ralph-wiggum/hooks/hooks.json +0 -15
- package/plugins/ralph-wiggum/hooks/stop-hook.sh +0 -191
- package/plugins/ralph-wiggum/plugin.js +0 -280
- package/plugins/ralph-wiggum/src/goalState.js +0 -258
- package/plugins/ralph-wiggum/src/sentinels.js +0 -76
- package/plugins/ralph-wiggum/src/stopHookRunner.js +0 -104
- package/plugins/ralph-wiggum/src/verificationGate.js +0 -202
- package/plugins/workflow-runner/src/miniReAct.js +0 -223
- package/plugins/workflow-runner/src/voteHelpers.js +0 -110
- package/skills/config/SKILL.md +0 -123
- package/skills/frontend-design/LICENSE.txt +0 -177
- package/skills/frontend-design/SKILL.md +0 -42
- package/src/ui/ProgressPanel.js +0 -54
- package/src/ui/StreamingBlock.js +0 -11
- package/src/ui/ToolStatus.js +0 -11
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================
|
|
3
|
-
* src/
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/tool.ts —— tool step 执行
|
|
4
4
|
* ------------------------------------------------------------
|
|
5
5
|
* 把 step.args 递归 ${var} 插值后 JSON.stringify,转发到 executeTool。
|
|
6
6
|
* 失败(ok=false)抛 Error,让 runner 走 onError 处理。
|
|
7
7
|
*
|
|
8
8
|
* v2(P1 TUI 可见):本执行器改为 AsyncGenerator,在调 executeTool 前后
|
|
9
9
|
* yield 通用 tool_start / tool_end LoopEvent —— 这样 workflow 的 tool 步骤
|
|
10
|
-
* 在 TUI 里像普通 ReAct 工具调用一样显示(runningTools spinner +
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
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 中留痕。
|
|
14
16
|
*
|
|
15
17
|
* capture 字段(支持点路径):
|
|
16
18
|
* - `{ content: var_name }` 绑 ToolResult.content(工具回执文本)
|
|
@@ -19,15 +21,27 @@
|
|
|
19
21
|
* - `{ args.<任意字段>: var_name }` 绑入参的具名字段
|
|
20
22
|
* ============================================================
|
|
21
23
|
*/
|
|
22
|
-
import {
|
|
24
|
+
import { existsSync } from 'node:fs';
|
|
25
|
+
import { resolve } from 'node:path';
|
|
26
|
+
import { executeTool, getToolByName, recordRead, } from '../../../../src/plugin-sdk.js';
|
|
23
27
|
import { interpolateDeep } from '../expressions.js';
|
|
24
28
|
export async function* execToolStep(step, vars, ctx) {
|
|
25
29
|
if (!step.tool)
|
|
26
30
|
throw new Error(`step ${step.id}: 缺少 tool 字段`);
|
|
27
31
|
const tool = getToolByName(step.tool);
|
|
28
32
|
if (!tool)
|
|
29
|
-
throw new Error(`step ${step.id}:
|
|
30
|
-
|
|
33
|
+
throw new Error(`step ${step.id}: 未知工具 "${step.tool}"`);
|
|
34
|
+
// 未定义变量插值可见化(args 里静默空串会让工具拿到空路径/空内容)
|
|
35
|
+
const missing = [];
|
|
36
|
+
const args = interpolateDeep(step.args ?? {}, vars, {
|
|
37
|
+
onMissing: (e) => missing.push(e),
|
|
38
|
+
});
|
|
39
|
+
if (missing.length > 0) {
|
|
40
|
+
yield {
|
|
41
|
+
type: 'warning',
|
|
42
|
+
message: `step "${step.id}": 模板变量未定义,已按空串插值:${[...new Set(missing)].map((m) => `\${${m}}`).join('、')}(裸名请用 inputs.<name> 或先 capture/set)`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
31
45
|
const argsJson = JSON.stringify(args);
|
|
32
46
|
const toolCallId = `wf_${step.id}`;
|
|
33
47
|
const argsPreview = argsJson.length > 80 ? `${argsJson.slice(0, 80)}…` : argsJson;
|
|
@@ -38,6 +52,14 @@ export async function* execToolStep(step, vars, ctx) {
|
|
|
38
52
|
argsPreview,
|
|
39
53
|
argsFriendly: friendlyToolDesc(tool.name, args),
|
|
40
54
|
};
|
|
55
|
+
// ════ 声明产物覆盖判定(解 Write/Edit 的 pre-read 守卫) ════
|
|
56
|
+
// 内核写类工具有「文件已存在必须先 Read」守卫(fileState 进程级 Map,
|
|
57
|
+
// 跨进程 / resume / 残留旧产物时必空)。确定性 tool 步的 args 是 yaml 作者
|
|
58
|
+
// 写死的,模型没有机会先 Read —— 目标文件若是工作流**声明的产物**
|
|
59
|
+
// (def 级 + step 级 artifacts:,= 工作流自己拥有、本就要覆盖的文件),
|
|
60
|
+
// 这里自动 pre-Read 一次解除守卫(管线动作,不 yield 事件、结果丢弃)。
|
|
61
|
+
// 非声明产物的盲写保护原样生效;pre-Read 失败也不拦,让写工具自己报错。
|
|
62
|
+
await preReadDeclaredArtifact(tool, args, step, ctx);
|
|
41
63
|
const result = await executeTool(tool.name, argsJson, ctx.signal);
|
|
42
64
|
yield {
|
|
43
65
|
type: 'tool_end',
|
|
@@ -50,15 +72,59 @@ export async function* execToolStep(step, vars, ctx) {
|
|
|
50
72
|
throw new Error(result.error);
|
|
51
73
|
}
|
|
52
74
|
const content = result.content;
|
|
75
|
+
// ════ v0.9.3:上下文统一 —— 把工具调用写入共享 history ════
|
|
76
|
+
// 后续 agent/llm/skill 步骤走 runQuery() 时,LLM 能在上下文中看到
|
|
77
|
+
// 这步做了什么(与正常 TAOR 循环中 tool_call → tool_result 的记录方式一致)。
|
|
78
|
+
// 只记录精简摘要(不把完整工具回执塞入 history,避免 token 浪费)。
|
|
79
|
+
const summary = content.length > 500
|
|
80
|
+
? `${content.slice(0, 500)}…(已截断,共 ${content.length} 字符)`
|
|
81
|
+
: content;
|
|
82
|
+
ctx.history.push({
|
|
83
|
+
role: 'assistant',
|
|
84
|
+
content: `[workflow:${step.id}] ✅ ${tool.name} 执行完成:${summary}`,
|
|
85
|
+
timestamp: Date.now(),
|
|
86
|
+
id: crypto.randomUUID(),
|
|
87
|
+
});
|
|
53
88
|
return {
|
|
54
89
|
raw: { content, result: content, args },
|
|
55
90
|
preview: content.length > 200 ? `${content.slice(0, 200)}...` : content,
|
|
56
91
|
};
|
|
57
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* 写类 tool 步的目标文件若命中声明产物且已存在 → pre-Read 解除内核守卫。
|
|
95
|
+
*
|
|
96
|
+
* 路径归一化:artifacts 声明相对 cwd;args.file_path 可能是 ./相对 或 绝对,
|
|
97
|
+
* 双方都 resolve(cwd, …) 后比较(win32 文件系统大小写不敏感 → lowercase 比较;
|
|
98
|
+
* 其余平台保持大小写敏感,避免 Plan.md / plan.md 误判同文件)。
|
|
99
|
+
*/
|
|
100
|
+
async function preReadDeclaredArtifact(tool, args, step, ctx) {
|
|
101
|
+
if (tool.isReadOnly !== false)
|
|
102
|
+
return; // 只对写类工具生效
|
|
103
|
+
if (typeof args.file_path !== 'string')
|
|
104
|
+
return;
|
|
105
|
+
const norm = (p) => {
|
|
106
|
+
const abs = resolve(ctx.cwd, p);
|
|
107
|
+
return process.platform === 'win32' ? abs.toLowerCase() : abs;
|
|
108
|
+
};
|
|
109
|
+
const target = norm(args.file_path);
|
|
110
|
+
const declared = [...(ctx.declaredArtifacts ?? []), ...(step.artifacts ?? [])];
|
|
111
|
+
if (!declared.some((a) => norm(a) === target))
|
|
112
|
+
return;
|
|
113
|
+
const abs = resolve(ctx.cwd, args.file_path);
|
|
114
|
+
if (!existsSync(abs))
|
|
115
|
+
return; // 新建文件不需要解守卫
|
|
116
|
+
// 直接登记一次「完整已读」状态解除内核 pre-read 守卫——不真正 Read 内容:
|
|
117
|
+
// 1. 声明产物本就要被本步整体覆盖,旧内容无需进上下文/烧 token;
|
|
118
|
+
// 2. 真 Read 大文件会触发字符上限截断(read.ts → recordRead({truncated:true})),
|
|
119
|
+
// 反而踩中 Write 的「截断禁写」硬守卫(write.ts: existsSync && wasTruncated → 拒绝),
|
|
120
|
+
// 正是本步要解除的同一道墙——曾导致 plan.yaml 回写变长的 PLAN.md 时 halt
|
|
121
|
+
// (首轮新建 PLAN.md 不存在直接放行,审批反馈后回写已存在的大 PLAN.md 被挡死)。
|
|
122
|
+
// 两道守卫(never-read + truncated)必须一并解除,声明产物的整体覆盖才算真正授权。
|
|
123
|
+
// recordRead 内部自带 statSync 失败兜底(返回 1、不抛),无需再包 try/catch。
|
|
124
|
+
recordRead(abs, { truncated: false });
|
|
125
|
+
}
|
|
58
126
|
/**
|
|
59
127
|
* 给 tool_start 生成人话描述(LiveArea spinner 行用)。
|
|
60
|
-
* 取常见入参键(file_path/command/query/...)拼成 "Write greetings/a/hello.txt"
|
|
61
|
-
* 这样的短句;都没命中就回退到工具名本身。
|
|
62
128
|
*/
|
|
63
129
|
function friendlyToolDesc(toolName, args) {
|
|
64
130
|
const key = ['file_path', 'command', 'query', 'pattern', 'path', 'url'].find((k) => typeof args[k] === 'string');
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================
|
|
3
|
-
* stepExecutors/verify.ts —— verify step 执行
|
|
3
|
+
* plugins/workflow-runner/src/stepExecutors/verify.ts —— verify step 执行
|
|
4
4
|
* ------------------------------------------------------------
|
|
5
|
-
*
|
|
5
|
+
* 复用内核共享验证基础设施(经 plugin-sdk 门面取 runVerification/parseCheckString),
|
|
6
6
|
* 支持 shell / file_exists / file_contains / test_count 四种检查。
|
|
7
7
|
*
|
|
8
8
|
* 与 assert 的区别:
|
|
@@ -10,19 +10,36 @@
|
|
|
10
10
|
* - verify: 完整检查器(重量,支持命令执行/正则匹配/测试计数)
|
|
11
11
|
* ============================================================
|
|
12
12
|
*/
|
|
13
|
-
import { parseCheckString, runVerification } from '../../../../src/
|
|
13
|
+
import { parseCheckString, runVerification } from '../../../../src/plugin-sdk.js';
|
|
14
14
|
import { interpolate } from '../expressions.js';
|
|
15
15
|
export async function execVerifyStep(step, vars) {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// 兼容两种格式:YAML 数组 或逗号分隔字符串。
|
|
17
|
+
// 关键:【先插值再按逗号分割】。checks 可能是 "${verify_checks}" 这类模板,插值后才
|
|
18
|
+
// 展开成逗号分隔的多项(如 "shell:bun test,file_exists:x")。若先分割再插值,整段模板
|
|
19
|
+
// 会被当成一项,解析时 value 混入逗号、多项检查失效(ralph-loop 的 run_verify 即如此)。
|
|
20
|
+
let rawChecks;
|
|
21
|
+
if (Array.isArray(step.checks) && step.checks.length > 0) {
|
|
22
|
+
rawChecks = step.checks
|
|
23
|
+
.flatMap((s) => interpolate(s, vars).split(','))
|
|
24
|
+
.map((s) => s.trim())
|
|
25
|
+
.filter(Boolean);
|
|
18
26
|
}
|
|
19
|
-
|
|
27
|
+
else if (typeof step.checks === 'string' && step.checks.trim() !== '') {
|
|
28
|
+
rawChecks = interpolate(step.checks, vars)
|
|
29
|
+
.split(',')
|
|
30
|
+
.map((s) => s.trim())
|
|
31
|
+
.filter(Boolean);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
throw new Error(`step ${step.id}: verify 缺少 checks(需要数组或逗号分隔字符串)`);
|
|
35
|
+
}
|
|
36
|
+
// 解析每条已插值的 check 字符串(插值后若整体为空——如 ${verify_checks} 取到空串——
|
|
37
|
+
// 则 checks 为空,runVerification 视为"无检查项"通过;ralph-loop 另有 when 守卫不会走到这)
|
|
20
38
|
const checks = [];
|
|
21
|
-
for (const raw of
|
|
22
|
-
const
|
|
23
|
-
const check = parseCheckString(interpolated);
|
|
39
|
+
for (const raw of rawChecks) {
|
|
40
|
+
const check = parseCheckString(raw);
|
|
24
41
|
if (!check) {
|
|
25
|
-
throw new Error(`step ${step.id}: 无法解析 check "${
|
|
42
|
+
throw new Error(`step ${step.id}: 无法解析 check "${raw}",格式应为 "type:value"`);
|
|
26
43
|
}
|
|
27
44
|
checks.push(check);
|
|
28
45
|
}
|
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { chat as sdkChat, executeTool as sdkExecuteTool, } from '../../../src/plugin-sdk.js';
|
|
5
|
+
import { truncate } from './agentCommon.js';
|
|
6
|
+
import { extractJsonPayload } from './jsonPayload.js';
|
|
7
|
+
// ============================================================
|
|
8
|
+
// 工作流状态目录布局(E6 修复:按 workflow 名隔离)
|
|
9
|
+
// ------------------------------------------------------------
|
|
10
|
+
// <cwd>/.minimal-agent-workflow/<name>/ ← 每个工作流独立状态
|
|
11
|
+
// <cwd>/.minimal-agent-workflow/<name>.done/ ← 成功归档
|
|
12
|
+
// 曾经一个 cwd 单例目录:A(如 /plan)未完成时跑不同名工作流 B,
|
|
13
|
+
// init 的 new-task 路径会清掉 A 的声明产物 + 整个状态目录,A 永久失去
|
|
14
|
+
// resume 能力——与「不同任务中间文件互不干扰」需求直接冲突。
|
|
15
|
+
// 按名隔离后跨工作流互不可见,互踩从结构上消失。
|
|
16
|
+
// /new 的前缀清理(.minimal-agent*)作用于父目录,行为不变。
|
|
17
|
+
// ============================================================
|
|
18
|
+
/** 工作流状态目录的父目录名(/new 按 .minimal-agent 前缀整体清理)。 */
|
|
19
|
+
export const WF_STATE_PARENT = '.minimal-agent-workflow';
|
|
20
|
+
/** 把 workflow 名清洗成安全的目录名(保留字母数字._-,其余替换为 -)。 */
|
|
21
|
+
export function sanitizeWorkflowDirName(name) {
|
|
22
|
+
return name.replace(/[^\w.-]/g, '-');
|
|
23
|
+
}
|
|
24
|
+
/** 某 workflow 的状态目录绝对路径。workflowState / taskIdentity 共用唯一权威实现。 */
|
|
25
|
+
export function workflowStateDir(workingDir, workflowName) {
|
|
26
|
+
return join(workingDir, WF_STATE_PARENT, sanitizeWorkflowDirName(workflowName));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 计算任务身份 hash。
|
|
30
|
+
*
|
|
31
|
+
* 策略(内容 hash 是【唯一权威信号】):
|
|
32
|
+
* - 对「workflow 名 + 归一化 goal」做 SHA256 → 取前 16 位 = taskId。
|
|
33
|
+
* - 同 hash → 同一任务(无论隔了多久);hash 不同 → 不同任务。
|
|
34
|
+
* - recency(上次 startedAt 的时间窗口)【不】参与身份判定:30 分钟内换一个
|
|
35
|
+
* 完全不同的 goal 重跑同名 workflow,必须判「全新任务」清理重开,而不是
|
|
36
|
+
* 错误地 resume 旧任务把旧变量混进新目标(需求 3.2「不相关新任务自动清理重开」)。
|
|
37
|
+
* 旧版「时间窗口覆盖 hash 差异」是 bug,已移除。
|
|
38
|
+
*
|
|
39
|
+
* 归一化规则:
|
|
40
|
+
* - 转小写
|
|
41
|
+
* - 去除所有标点符号(保留中文、英文、数字、空格)
|
|
42
|
+
* - 去除多余空格(连续空格→单空格,首尾 trim)
|
|
43
|
+
* - 截断到 200 字符(防止超长输入导致不必要的差异)
|
|
44
|
+
*/
|
|
45
|
+
export function computeTaskId(workflowName, inputs, workingDir) {
|
|
46
|
+
// 1. 提取 goal 文本(与 buildGoalAnchor 同策略)
|
|
47
|
+
const rawGoal = extractGoal(inputs);
|
|
48
|
+
// 2. 归一化 goal
|
|
49
|
+
const normalizedGoal = normalizeGoal(rawGoal);
|
|
50
|
+
// 3. 计算 contentHash = SHA256(`${workflowName}::${normalizedGoal}`)[:16]
|
|
51
|
+
const contentHash = createHash('sha256')
|
|
52
|
+
.update(`${workflowName}::${normalizedGoal}`)
|
|
53
|
+
.digest('hex')
|
|
54
|
+
.slice(0, 16);
|
|
55
|
+
// 4. 如果没有提供 workingDir,只返回 hash,不做比较
|
|
56
|
+
if (!workingDir) {
|
|
57
|
+
return {
|
|
58
|
+
hash: contentHash,
|
|
59
|
+
isSameTask: false,
|
|
60
|
+
reason: 'no_previous',
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// 5. 尝试读取旧状态文件(按 workflow 名隔离的状态目录)
|
|
64
|
+
const stateFilePath = join(workflowStateDir(workingDir, workflowName), 'current.json');
|
|
65
|
+
if (!existsSync(stateFilePath)) {
|
|
66
|
+
return {
|
|
67
|
+
hash: contentHash,
|
|
68
|
+
isSameTask: false,
|
|
69
|
+
reason: 'no_previous',
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const stateContent = readFileSync(stateFilePath, 'utf-8');
|
|
74
|
+
const prevState = JSON.parse(stateContent);
|
|
75
|
+
// a. 不同 workflow 名 → 不同任务
|
|
76
|
+
if (prevState.name && prevState.name !== workflowName) {
|
|
77
|
+
return {
|
|
78
|
+
hash: contentHash,
|
|
79
|
+
isSameTask: false,
|
|
80
|
+
reason: 'different_workflow',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
// b. 内容 hash 一致 → 同一任务(唯一权威信号,与时间无关)
|
|
84
|
+
if (prevState.taskId === contentHash) {
|
|
85
|
+
return {
|
|
86
|
+
hash: contentHash,
|
|
87
|
+
isSameTask: true,
|
|
88
|
+
reason: 'hash_match',
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// c. hash 不一致 → 不同任务(goal 变了)。recency 不覆盖此判定(见函数头注)。
|
|
92
|
+
return {
|
|
93
|
+
hash: contentHash,
|
|
94
|
+
isSameTask: false,
|
|
95
|
+
reason: 'hash_diff',
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// 解析失败时返回默认结果
|
|
100
|
+
return {
|
|
101
|
+
hash: contentHash,
|
|
102
|
+
isSameTask: false,
|
|
103
|
+
reason: 'no_previous',
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 从 inputs 中提取 goal 文本
|
|
109
|
+
*
|
|
110
|
+
* 策略:
|
|
111
|
+
* - 优先 inputs.goal
|
|
112
|
+
* - 其次第一个 length > 2 的 string 值
|
|
113
|
+
* - 最后 JSON.stringify 整个 inputs
|
|
114
|
+
*/
|
|
115
|
+
export function extractGoal(inputs) {
|
|
116
|
+
// 优先级1:直接使用 inputs.goal
|
|
117
|
+
if (typeof inputs.goal === 'string') {
|
|
118
|
+
return inputs.goal;
|
|
119
|
+
}
|
|
120
|
+
// 优先级2:查找第一个长度 > 2 的字符串值
|
|
121
|
+
for (const value of Object.values(inputs)) {
|
|
122
|
+
if (typeof value === 'string' && value.length > 2) {
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// 优先级3:JSON 序列化整个 inputs
|
|
127
|
+
return JSON.stringify(inputs);
|
|
128
|
+
}
|
|
129
|
+
/** 延续短语白名单(归一化后精确匹配;短输入再放宽到前缀匹配)。 */
|
|
130
|
+
const CONTINUATION_PHRASES = new Set([
|
|
131
|
+
'继续',
|
|
132
|
+
'继续吧',
|
|
133
|
+
'继续执行',
|
|
134
|
+
'继续任务',
|
|
135
|
+
'继续上次',
|
|
136
|
+
'继续刚才',
|
|
137
|
+
'接着',
|
|
138
|
+
'接着做',
|
|
139
|
+
'接着干',
|
|
140
|
+
'接着来',
|
|
141
|
+
'做完它',
|
|
142
|
+
'接着执行',
|
|
143
|
+
'continue',
|
|
144
|
+
'resume',
|
|
145
|
+
'go on',
|
|
146
|
+
'keep going',
|
|
147
|
+
'carry on',
|
|
148
|
+
]);
|
|
149
|
+
/** 新输入是否是「延续上次任务」的指令(仲裁快路径,不花 LLM)。 */
|
|
150
|
+
export function isContinuationPhrase(rawGoal) {
|
|
151
|
+
const norm = normalizeGoal(rawGoal);
|
|
152
|
+
if (!norm)
|
|
153
|
+
return false;
|
|
154
|
+
if (CONTINUATION_PHRASES.has(norm))
|
|
155
|
+
return true;
|
|
156
|
+
// 短输入且以延续词开头(如「继续干活」「continue please」)也算
|
|
157
|
+
if (norm.length <= 12 &&
|
|
158
|
+
(norm.startsWith('继续') ||
|
|
159
|
+
norm.startsWith('接着') ||
|
|
160
|
+
norm.startsWith('continue') ||
|
|
161
|
+
norm.startsWith('resume'))) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 构建复合仲裁器(短语快路径 → LLM 单轮仲裁 → AskUserQuestion → 兜底 new)。
|
|
168
|
+
* runner 在 state.init 前构建并传入;任何一级抛错都降级到下一级,绝不让仲裁本身 halt 工作流。
|
|
169
|
+
*/
|
|
170
|
+
export function buildTaskArbitrator(deps) {
|
|
171
|
+
const note = (m) => {
|
|
172
|
+
deps.notes?.push(m);
|
|
173
|
+
};
|
|
174
|
+
return async (actx) => {
|
|
175
|
+
// a. 延续短语快路径
|
|
176
|
+
if (isContinuationPhrase(actx.newGoal)) {
|
|
177
|
+
note(`任务仲裁:新输入「${truncate(actx.newGoal, 40)}」命中延续短语 → 继续旧任务(目标:${truncate(actx.prevGoal, 60)})`);
|
|
178
|
+
return 'resume';
|
|
179
|
+
}
|
|
180
|
+
// b. LLM 单轮仲裁
|
|
181
|
+
try {
|
|
182
|
+
const verdict = await llmArbitrate(deps, actx);
|
|
183
|
+
if (verdict !== 'unsure') {
|
|
184
|
+
note(`任务仲裁:LLM 判定新输入${verdict === 'resume' ? '是旧任务的延续 → 续跑' : '是全新任务 → 清理旧产物重开'}`);
|
|
185
|
+
return verdict;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// LLM 不可用 → 降级到提问
|
|
190
|
+
}
|
|
191
|
+
// c. AskUserQuestion(TUI 弹界面;非交互宿主 askBridge 自动选推荐项=全新开始)
|
|
192
|
+
try {
|
|
193
|
+
const verdict = await askUserArbitrate(deps, actx);
|
|
194
|
+
note(`任务仲裁:经用户确认 → ${verdict === 'resume' ? '继续旧任务' : '全新开始'}`);
|
|
195
|
+
return verdict;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// 提问被取消/不可用 → 兜底
|
|
199
|
+
}
|
|
200
|
+
// d. 兜底 = 旧红线行为(hash 不等 → new-task),最小惊讶
|
|
201
|
+
note('任务仲裁:无法判定(LLM 与提问均不可用)→ 按全新任务处理');
|
|
202
|
+
return 'new';
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** LLM 单轮仲裁:旧 goal + 新输入 + 进度摘要 → {verdict, reason}。解析失败按 unsure。 */
|
|
206
|
+
async function llmArbitrate(deps, actx) {
|
|
207
|
+
const chatFn = deps.chat ?? sdkChat;
|
|
208
|
+
const progress = `${actx.completedStepIds.length}/${actx.totalSteps}`;
|
|
209
|
+
const prompt = [
|
|
210
|
+
`你是工作流引擎的任务身份仲裁器。同名工作流「${actx.workflowName}」存在一个未完成的旧任务,`,
|
|
211
|
+
`用户刚发起了一次新调用,新输入的文本与旧任务目标不同。请判断新输入是「旧任务的延续指令」还是「全新任务」。`,
|
|
212
|
+
'',
|
|
213
|
+
`旧任务目标:${truncate(actx.prevGoal, 300)}`,
|
|
214
|
+
`旧任务进度:已完成 ${progress} 步${actx.completedStepIds.length ? `(${actx.completedStepIds.join(', ')})` : ''}`,
|
|
215
|
+
actx.artifacts.length ? `旧任务产物:${actx.artifacts.join(', ')}` : '',
|
|
216
|
+
`新输入:${truncate(actx.newGoal, 300)}`,
|
|
217
|
+
'',
|
|
218
|
+
'判断标准:新输入若是「继续 / 接着做 / 把它做完 / 对旧任务的补充修改意见」类延续语义 → resume;',
|
|
219
|
+
'若是与旧目标无关的新需求 → new;真不确定 → unsure。',
|
|
220
|
+
'只输出一行 JSON(不要 markdown 代码块、不要解释):{"verdict":"resume"|"new"|"unsure","reason":"一句话"}',
|
|
221
|
+
]
|
|
222
|
+
.filter((l) => l !== '')
|
|
223
|
+
.join('\n');
|
|
224
|
+
let text = '';
|
|
225
|
+
for await (const ev of chatFn({
|
|
226
|
+
provider: deps.provider,
|
|
227
|
+
messages: [
|
|
228
|
+
{ role: 'user', content: prompt, timestamp: Date.now(), id: crypto.randomUUID() },
|
|
229
|
+
],
|
|
230
|
+
tools: [],
|
|
231
|
+
signal: deps.signal,
|
|
232
|
+
})) {
|
|
233
|
+
if (ev.type === 'text_delta')
|
|
234
|
+
text += ev.delta;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const parsed = JSON.parse(extractJsonPayload(text.trim()));
|
|
238
|
+
if (parsed.verdict === 'resume' || parsed.verdict === 'new') {
|
|
239
|
+
return parsed.verdict;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
// 解析失败按 unsure
|
|
244
|
+
}
|
|
245
|
+
return 'unsure';
|
|
246
|
+
}
|
|
247
|
+
/** 经 AskUserQuestion 问用户(推荐项=全新开始,与兜底语义一致;非交互自动按推荐项)。 */
|
|
248
|
+
async function askUserArbitrate(deps, actx) {
|
|
249
|
+
const exec = deps.executeTool ?? sdkExecuteTool;
|
|
250
|
+
const progress = `${actx.completedStepIds.length}/${actx.totalSteps}`;
|
|
251
|
+
const args = {
|
|
252
|
+
questions: [
|
|
253
|
+
{
|
|
254
|
+
question: `检测到工作流「${actx.workflowName}」有一个未完成的任务(目标:${truncate(actx.prevGoal, 80)},` +
|
|
255
|
+
`进度 ${progress} 步)。本次输入「${truncate(actx.newGoal, 80)}」是要继续该任务,还是开始全新任务?`,
|
|
256
|
+
header: '任务仲裁',
|
|
257
|
+
options: [
|
|
258
|
+
{
|
|
259
|
+
label: '全新开始 (推荐)',
|
|
260
|
+
description: '清理旧任务的中间产物,按本次输入重新规划执行',
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
label: '继续上次任务',
|
|
264
|
+
description: '从断点续跑旧任务,本次输入作为补充指令',
|
|
265
|
+
},
|
|
266
|
+
],
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
};
|
|
270
|
+
const r = await exec('AskUserQuestion', JSON.stringify(args), deps.signal);
|
|
271
|
+
if (!r.ok)
|
|
272
|
+
throw new Error(r.error);
|
|
273
|
+
return r.content.includes('继续上次任务') ? 'resume' : 'new';
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* 归一化 goal 字符串
|
|
277
|
+
*
|
|
278
|
+
* 规则:
|
|
279
|
+
* - toLowerCase()
|
|
280
|
+
* - 去除所有标点符号(保留中文、英文、数字、空格)
|
|
281
|
+
* - 去除多余空格(连续空格→单空格)
|
|
282
|
+
* - 首尾 trim
|
|
283
|
+
* - 截断到 200 字符
|
|
284
|
+
*/
|
|
285
|
+
function normalizeGoal(raw) {
|
|
286
|
+
return (raw
|
|
287
|
+
.toLowerCase()
|
|
288
|
+
// 保留中文、英文、数字、空格,去除其他字符(标点等)
|
|
289
|
+
.replace(/[^\p{L}\p{N}\s]/gu, '')
|
|
290
|
+
// 连续空格替换为单空格
|
|
291
|
+
.replace(/\s+/g, ' ')
|
|
292
|
+
// 首尾去空格
|
|
293
|
+
.trim()
|
|
294
|
+
// 截断到 200 字符
|
|
295
|
+
.slice(0, 200));
|
|
296
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ============================================================
|
|
3
|
-
* src/
|
|
3
|
+
* plugins/workflow-runner/src/types.ts —— workflow runner 核心类型
|
|
4
4
|
* ------------------------------------------------------------
|
|
5
|
-
*
|
|
6
|
-
* 驱动执行,LLM 只在 llm: / skill: 节点出场。本文件定义 YAML 解析
|
|
5
|
+
* 外层确定性 step 列表驱动执行,LLM 只在 llm: / skill: / agent: 节点出场。
|
|
7
6
|
* 后的内存形态(WorkflowDef / StepDef),以及运行时上下文(VarStack /
|
|
8
7
|
* RunContext)和 UI 事件(WorkflowEvent)。
|
|
9
8
|
*
|
|
@@ -52,14 +51,25 @@ export class VarStack {
|
|
|
52
51
|
if (this.frames.length > 1)
|
|
53
52
|
this.frames.pop();
|
|
54
53
|
}
|
|
55
|
-
/** ADR-05: parallel 用——给子 fork 一份深拷贝栈;子 fork 的 set/push/pop 不污染父栈。 */
|
|
56
|
-
fork() {
|
|
57
|
-
const child = new VarStack();
|
|
58
|
-
child.frames = this.frames.map((f) => ({ ...f }));
|
|
59
|
-
return child;
|
|
60
|
-
}
|
|
61
54
|
/** 合并所有帧为一个普通对象(外层覆盖内层),用于 vars 持久化与事件 */
|
|
62
55
|
snapshot() {
|
|
63
56
|
return Object.assign({}, ...this.frames);
|
|
64
57
|
}
|
|
65
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* 把 yaml 的 capture 归一化成 { resultField: varName } map。支持两种写法
|
|
61
|
+
* (通用 DSL,根治「裸字符串 capture 被 Object.entries/values 迭代成单字符」的静默 footgun):
|
|
62
|
+
* - map 形式: capture: { text: foo, args.content: bar }
|
|
63
|
+
* - 简写字符串: capture: foo ≡ capture: { result: foo }
|
|
64
|
+
* 绑 StepResult.raw.result —— llm/agent=文本、tool=回执,各 executor 都提供 result 别名。
|
|
65
|
+
*
|
|
66
|
+
* 放在 types.ts(零依赖)供 runner.ts(bindCapture)与 agentCommon.ts(describeCaptureContract)
|
|
67
|
+
* 共用,避免 runner↔agentCommon 循环引用。
|
|
68
|
+
*/
|
|
69
|
+
export function normalizeCapture(cap) {
|
|
70
|
+
if (cap == null)
|
|
71
|
+
return {};
|
|
72
|
+
if (typeof cap === 'string')
|
|
73
|
+
return { result: cap };
|
|
74
|
+
return cap;
|
|
75
|
+
}
|