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
package/src/ui/AskQuestion.js
CHANGED
|
@@ -13,18 +13,37 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
* 每题选项列表末尾自动追加一个「✏️ 其他(自由输入)」伪选项,命中即切到文本
|
|
14
14
|
* 输入子模式,让用户填选项之外的答案(自由输入按单值处理,覆盖多选集合)。
|
|
15
15
|
*
|
|
16
|
-
* Ink 用法与风格对齐 cli/
|
|
16
|
+
* Ink 用法与风格对齐 cli/wizards/providerWizard.tsx:useInput 手写键位、↑↓ 取模移动
|
|
17
17
|
* 高亮、`> ` 前缀 + cyan 高亮、gray 操作提示、文本输入用累积 draft + backspace。
|
|
18
18
|
* ============================================================
|
|
19
19
|
*/
|
|
20
|
-
import { useState } from 'react';
|
|
20
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
21
21
|
import { Box, Text, useInput } from 'ink';
|
|
22
|
+
import { theme } from './theme.js';
|
|
22
23
|
/** description 过长截断到此长度,防止 live 区被超长文本撑爆。 */
|
|
23
24
|
const DESC_MAX = 80;
|
|
25
|
+
/**
|
|
26
|
+
* 提问上限——与 system prompt 里的"最多 4 题"硬性对齐。超出会:
|
|
27
|
+
* - UI 截断到 4 题(仅前 4 题可答,后面的被静默丢弃)
|
|
28
|
+
* - stderr 注记,提示上游(callers 应在调 AskUserQuestion 工具前自检)
|
|
29
|
+
* 这是防御层——理想情况是 tool 上游 Zod 校验就拦住。
|
|
30
|
+
*/
|
|
31
|
+
const MAX_QUESTIONS = 4;
|
|
24
32
|
function clampDesc(s) {
|
|
25
33
|
return s.length > DESC_MAX ? `${s.slice(0, DESC_MAX - 1)}…` : s;
|
|
26
34
|
}
|
|
27
|
-
export function AskQuestion({ questions, onAnswer, onCancel, }) {
|
|
35
|
+
export function AskQuestion({ questions, source, queuedCount = 0, onAnswer, onCancel, }) {
|
|
36
|
+
// 硬限 4 题;超量截断。注记走 useEffect(只发一次):渲染期写 stderr 会随
|
|
37
|
+
// 每次按键重渲重复打行,且 Ink 渲染期间写 stdout/stderr 会撕裂终端画面。
|
|
38
|
+
const effectiveQuestions = useMemo(() => questions.slice(0, MAX_QUESTIONS), [questions]);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (questions.length <= MAX_QUESTIONS)
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
process.stderr.write(`[AskUserQuestion] 收到 ${questions.length} 题超过上限 ${MAX_QUESTIONS},已截断\n`);
|
|
44
|
+
}
|
|
45
|
+
catch { /* ignore */ }
|
|
46
|
+
}, [questions]);
|
|
28
47
|
// 当前进行到第几题
|
|
29
48
|
const [questionIndex, setQuestionIndex] = useState(0);
|
|
30
49
|
// 当前题高亮的选项下标(含末尾「其他」伪选项)
|
|
@@ -37,7 +56,7 @@ export function AskQuestion({ questions, onAnswer, onCancel, }) {
|
|
|
37
56
|
const [textMode, setTextMode] = useState(false);
|
|
38
57
|
// 文本子模式的累积草稿
|
|
39
58
|
const [draft, setDraft] = useState('');
|
|
40
|
-
const current =
|
|
59
|
+
const current = effectiveQuestions[questionIndex];
|
|
41
60
|
const multi = current?.multiSelect === true;
|
|
42
61
|
const options = current?.options ?? [];
|
|
43
62
|
// 末尾「其他」伪选项占据下标 options.length,故列表总长 = options.length + 1
|
|
@@ -47,7 +66,7 @@ export function AskQuestion({ questions, onAnswer, onCancel, }) {
|
|
|
47
66
|
function advance(answer) {
|
|
48
67
|
const nextAnswers = [...answers, answer];
|
|
49
68
|
const nextQ = questionIndex + 1;
|
|
50
|
-
if (nextQ >=
|
|
69
|
+
if (nextQ >= effectiveQuestions.length) {
|
|
51
70
|
onAnswer(nextAnswers);
|
|
52
71
|
return;
|
|
53
72
|
}
|
|
@@ -164,14 +183,14 @@ export function AskQuestion({ questions, onAnswer, onCancel, }) {
|
|
|
164
183
|
});
|
|
165
184
|
// 无题可问(空数组)→ 渲染占位(useInput 已处理取消,这里只防御渲染崩)
|
|
166
185
|
if (!current) {
|
|
167
|
-
return (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color:
|
|
186
|
+
return (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: theme.subtle, children: "\uFF08\u65E0\u95EE\u9898\uFF09" }) }));
|
|
168
187
|
}
|
|
169
|
-
const progress = `提问 (${questionIndex + 1}/${
|
|
170
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color:
|
|
188
|
+
const progress = `提问 (${questionIndex + 1}/${effectiveQuestions.length}) · ${current.header}`;
|
|
189
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [source?.kind === 'subagent' && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: theme.subtle, dimColor: true, children: `⚡ 子任务:${source.description ?? '执行任务'}(其他子任务继续运行中)` }) })), queuedCount > 0 && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: theme.subtle, dimColor: true, children: `另有 ${queuedCount} 个问题排队` }) })), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: theme.user, bold: true, children: progress }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: current.question }) }), textMode ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: theme.subtle, children: "\u270F\uFE0F \u81EA\u7531\u8F93\u5165\uFF1A" }), _jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: "cyan", paddingX: 1, children: _jsx(Text, { children: draft || ' ' }) }), _jsx(Text, { color: theme.subtle, children: "\u8F93\u5165\u540E Enter \u63D0\u4EA4 \u00B7 ESC \u8FD4\u56DE" })] })) : (_jsxs(Box, { flexDirection: "column", children: [options.map((opt, i) => {
|
|
171
190
|
const active = i === idx;
|
|
172
191
|
const box = multi ? (picked.has(i) ? '[x] ' : '[ ] ') : '';
|
|
173
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: active ?
|
|
174
|
-
}), _jsxs(Text, { color: idx === otherIndex ?
|
|
192
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: active ? theme.user : undefined, children: [active ? '> ' : ' ', box, opt.label] }), opt.description ? (_jsxs(Text, { color: theme.subtle, children: [' ', clampDesc(opt.description)] })) : null] }, `${i}-${opt.label}`));
|
|
193
|
+
}), _jsxs(Text, { color: idx === otherIndex ? theme.user : undefined, children: [idx === otherIndex ? '> ' : ' ', multi ? ' ' : '', "\u270F\uFE0F \u5176\u4ED6\uFF08\u81EA\u7531\u8F93\u5165\uFF09"] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.subtle, children: multi
|
|
175
194
|
? '↑↓ 移动 · 空格 多选 · Enter 确认本题 · ESC 取消'
|
|
176
195
|
: '↑↓ 选择 · Enter 确认 · ESC 取消' }) })] }))] }));
|
|
177
196
|
}
|
package/src/ui/InputBox.js
CHANGED
|
@@ -16,17 +16,45 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
16
16
|
* - 保留强制刷新但精准控制时机
|
|
17
17
|
* ============================================================
|
|
18
18
|
*/
|
|
19
|
-
import React, { useRef, useState, useCallback } from 'react';
|
|
19
|
+
import React, { useRef, useState, useCallback, useEffect } from 'react';
|
|
20
20
|
import { Box, Text, useApp, useInput } from 'ink';
|
|
21
21
|
import { useTextBuffer } from './hooks/useTextBuffer.js';
|
|
22
22
|
import { usePasteHandler } from './hooks/usePasteHandler.js';
|
|
23
23
|
import { useInputHistory } from './hooks/useInputHistory.js';
|
|
24
|
-
|
|
24
|
+
import { theme } from './theme.js';
|
|
25
|
+
// ============================================================
|
|
26
|
+
// IME 启发式(中文输入法防护)
|
|
27
|
+
// ------------------------------------------------------------
|
|
28
|
+
// Ink 5.0.1 的 useInput(基于 readline)不暴露 composition event,
|
|
29
|
+
// 无法原生支持 IME 状态机。本启发式做"最小可行"的兜底:
|
|
30
|
+
// 1. 跟踪"短时间内连续插入"——IME 拼音→候选→提交过程中会产生
|
|
31
|
+
// 一连串短间隔字符(pinyin 字母 + 单字 commit)
|
|
32
|
+
// 2. 检测到 burst 后,**短时间窗口内**把 Enter 视为"IME 确认"
|
|
33
|
+
// 而非"提交"(避免候选窗按 Enter 时把半截拼音+候选字提交)
|
|
34
|
+
// 3. 不试图拦截或过滤 IME 字符——那是终端的活,拦了反而破坏
|
|
35
|
+
//
|
|
36
|
+
// 调参依据:微软拼音/搜狗拼音的 commit 节奏典型 < 100ms/char,
|
|
37
|
+
// 而人手打英文 ≥ 200ms/char。500ms idle 视作 IME 结束。
|
|
38
|
+
//
|
|
39
|
+
// 注意:这是 best-effort,**不能 100% 解决 IME 问题**。
|
|
40
|
+
// 终态方案是换掉 Ink 底层走 use-stdin 的 raw mode。
|
|
41
|
+
// ============================================================
|
|
42
|
+
const IME_BURST_GAP_MS = 200; // 字符间隔 < 此值视作 IME 连续输入
|
|
43
|
+
const IME_BURST_MIN_COUNT = 3; // 连续 N 个字符才触发 IME 锁定
|
|
44
|
+
const IME_LOCKOUT_MS = 500; // 触发后禁 Enter 提交的窗口
|
|
45
|
+
function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact, onWorkspaces }) {
|
|
25
46
|
const buf = useTextBuffer();
|
|
26
47
|
const hist = useInputHistory();
|
|
27
48
|
const ctrlCCountRef = useRef(0);
|
|
28
49
|
const ctrlCTimerRef = useRef(null);
|
|
29
50
|
const { exit } = useApp();
|
|
51
|
+
// 卸载清理:双击退出计数窗口的定时器(组件被 AskQuestion/ConfigMenu 顶替时)
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
return () => {
|
|
54
|
+
if (ctrlCTimerRef.current)
|
|
55
|
+
clearTimeout(ctrlCTimerRef.current);
|
|
56
|
+
};
|
|
57
|
+
}, []);
|
|
30
58
|
// 刷新触发器:值本身不读,只用 setter 触发 InputBoxImpl 重渲(→ BufferView 随父重渲)。
|
|
31
59
|
const [, setRefreshCounter] = useState(0);
|
|
32
60
|
// ✅ Ctrl+R 反向搜索模式(null 表示不在搜索)
|
|
@@ -34,6 +62,30 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
34
62
|
// ✅ Delete 专用去重:只防止 Windows 双事件,不影响其他键
|
|
35
63
|
const lastDeleteTime = useRef(0);
|
|
36
64
|
const DELETE_DEBOUNCE_MS = 20; // 仅 Delete 键用极短防抖
|
|
65
|
+
// ✅ IME 启发式:跟踪字符插入节奏,检测 IME 草稿期间
|
|
66
|
+
// imeBurstRef: { lastAt: 上次插入 ms, count: 当前 burst 内插入数, lastInsertEnd: 上次 IME 锁定结束 ms }
|
|
67
|
+
const imeBurstRef = useRef({
|
|
68
|
+
lastAt: 0,
|
|
69
|
+
count: 0,
|
|
70
|
+
lockoutUntil: 0,
|
|
71
|
+
});
|
|
72
|
+
/** 把"刚插入了非空非控制字符"事件喂给 IME 检测器 */
|
|
73
|
+
const noteTextInsert = useCallback((textLen) => {
|
|
74
|
+
if (textLen <= 0)
|
|
75
|
+
return;
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
const s = imeBurstRef.current;
|
|
78
|
+
if (now - s.lastAt < IME_BURST_GAP_MS) {
|
|
79
|
+
s.count++;
|
|
80
|
+
if (s.count >= IME_BURST_MIN_COUNT) {
|
|
81
|
+
s.lockoutUntil = now + IME_LOCKOUT_MS;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
s.count = 1;
|
|
86
|
+
}
|
|
87
|
+
s.lastAt = now;
|
|
88
|
+
}, []);
|
|
37
89
|
const forceRefresh = useCallback(() => {
|
|
38
90
|
setRefreshCounter((c) => c + 1);
|
|
39
91
|
}, []);
|
|
@@ -47,6 +99,10 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
47
99
|
multiline: true,
|
|
48
100
|
});
|
|
49
101
|
useInput((input, key) => {
|
|
102
|
+
if (key.ctrl && input === 'p') {
|
|
103
|
+
onWorkspaces();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
50
106
|
// ---- ✅ 粘贴检测(必须优先处理)----
|
|
51
107
|
// 这会在粘贴期间忽略 Enter 键,防止多行内容被截断
|
|
52
108
|
const pasteResult = handlePasteInput(input, key);
|
|
@@ -116,13 +172,21 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
116
172
|
}
|
|
117
173
|
// ---- ESC ----
|
|
118
174
|
if (key.escape) {
|
|
119
|
-
if (disabled)
|
|
120
|
-
onAbort
|
|
175
|
+
if (disabled) {
|
|
176
|
+
// try/catch 防 onAbort 异常冒泡到 Ink 渲染层(abort handler 多在 useChat 里,
|
|
177
|
+
// 内部若 throw 会黑屏;吞掉仅 stderr 注记)
|
|
178
|
+
try {
|
|
179
|
+
onAbort();
|
|
180
|
+
}
|
|
181
|
+
catch (e) {
|
|
182
|
+
console.error('[InputBox] onAbort threw:', e);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
121
185
|
return;
|
|
122
186
|
}
|
|
123
|
-
// ---- ✅ Ctrl+R 进入反向搜索(仅在空 buf
|
|
187
|
+
// ---- ✅ Ctrl+R 进入反向搜索(仅在空 buf)----
|
|
124
188
|
if (key.ctrl && input === 'r') {
|
|
125
|
-
if (
|
|
189
|
+
if (buf.state.text.length === 0) {
|
|
126
190
|
setSearchMode({ query: '', hit: null });
|
|
127
191
|
}
|
|
128
192
|
return;
|
|
@@ -135,7 +199,23 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
135
199
|
return;
|
|
136
200
|
}
|
|
137
201
|
if (disabled) {
|
|
138
|
-
onAbort
|
|
202
|
+
// 同 ESC 路径,try/catch 防 onAbort 异常冒泡到 Ink 渲染层
|
|
203
|
+
try {
|
|
204
|
+
onAbort();
|
|
205
|
+
}
|
|
206
|
+
catch (e) {
|
|
207
|
+
console.error('[InputBox] onAbort threw:', e);
|
|
208
|
+
}
|
|
209
|
+
// 强制退出安全阀(2026-07-02「Ctrl+C 退不出来」事故):abort 收尾慢
|
|
210
|
+
// (长时子进程/网络挂起)时用户不能被困在程序里——1s 窗口内再按一次
|
|
211
|
+
// Ctrl+C 直接退出(复用下方双击退出的计数/窗口;工作流现场已由状态目录
|
|
212
|
+
// 持久化 halt 语义,强退不丢进度、可 resume)。ESC 保持只 abort 不退出。
|
|
213
|
+
ctrlCCountRef.current++;
|
|
214
|
+
if (ctrlCCountRef.current >= 2)
|
|
215
|
+
exit();
|
|
216
|
+
if (ctrlCTimerRef.current)
|
|
217
|
+
clearTimeout(ctrlCTimerRef.current);
|
|
218
|
+
ctrlCTimerRef.current = setTimeout(() => { ctrlCCountRef.current = 0; }, 1000);
|
|
139
219
|
return;
|
|
140
220
|
}
|
|
141
221
|
ctrlCCountRef.current++;
|
|
@@ -152,7 +232,15 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
152
232
|
// - Alt+Enter(Mac: Option+Enter):返回 'enter-newline' → 上面已处理为**插入换行**
|
|
153
233
|
// - Ctrl+Enter:返回 'continue' → 这里也执行**强制发送**
|
|
154
234
|
// - 粘贴期间 + Enter:返回 'enter-in-paste' → **忽略**(防误发)
|
|
235
|
+
// - IME 草稿期间 + Enter:视为 IME 确认而非提交(启发式,见 IME_BURST_* 常量)
|
|
155
236
|
if (key.return) {
|
|
237
|
+
const now = Date.now();
|
|
238
|
+
if (now < imeBurstRef.current.lockoutUntil) {
|
|
239
|
+
// IME 候选窗按 Enter → 走换行而非提交(pinyin 候选确认不打断草稿)
|
|
240
|
+
buf.insert('\n');
|
|
241
|
+
forceRefresh();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
156
244
|
const text = buf.state.text.trim();
|
|
157
245
|
if (text.length === 0)
|
|
158
246
|
return;
|
|
@@ -290,6 +378,7 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
|
|
|
290
378
|
// (否则 layout 永远 1 行 → ↑/↓ 失效、输入框不长高,光标只能左右)。
|
|
291
379
|
if (input && !key.meta) {
|
|
292
380
|
const normalized = input.replace(/\r\n?/g, '\n');
|
|
381
|
+
noteTextInsert(normalized.length);
|
|
293
382
|
buf.insert(normalized);
|
|
294
383
|
forceRefresh();
|
|
295
384
|
}
|
|
@@ -326,19 +415,22 @@ function ReverseSearchView({ query, hit, }) {
|
|
|
326
415
|
: hit !== null && hit.includes('\n')
|
|
327
416
|
? `${hitFirstLine} …`
|
|
328
417
|
: hitFirstLine;
|
|
329
|
-
return (_jsxs(Box, { borderStyle: "round", borderColor: "magenta", paddingX: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color:
|
|
418
|
+
return (_jsxs(Box, { borderStyle: "round", borderColor: "magenta", paddingX: 1, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: theme.plugin, bold: true, children: '(reverse-i-search)`' }), _jsx(Text, { color: theme.warning, children: query }), _jsx(Text, { color: theme.plugin, bold: true, children: "': " }), _jsx(Text, { color: hitFirstLine === null ? theme.subtle : 'white', children: hitDisplay })] }), _jsx(Box, { children: _jsx(Text, { color: theme.subtle, dimColor: true, children: "Enter \u63D0\u4EA4 \u00B7 ESC \u53D6\u6D88 \u00B7 Backspace \u5220\u5B57\u7B26" }) })] }));
|
|
330
419
|
}
|
|
331
420
|
function BufferView({ buf, disabled }) {
|
|
332
421
|
// buf.layout 由 useTextBuffer 的 useMemo([state]) 维护:父组件每次重渲传入的 buf
|
|
333
422
|
// 都已带最新 layout,这里直接读即可(BufferView 故意不 memo,随父重渲)。
|
|
334
423
|
const { lines, cursorRow, cursorCol } = buf.layout;
|
|
335
|
-
const promptColor = disabled ?
|
|
336
|
-
const prompt = disabled ? '
|
|
424
|
+
const promptColor = disabled ? theme.warning : theme.user;
|
|
425
|
+
const prompt = disabled ? '📝 ' : '> ';
|
|
426
|
+
const hasContent = lines.some(l => l.length > 0);
|
|
337
427
|
return (_jsx(Box, { borderStyle: "round", borderColor: promptColor, paddingX: 1, flexDirection: "column", children: lines.map((line, row) => {
|
|
338
428
|
const isFirst = row === 0;
|
|
339
|
-
const isCursorRow = row === cursorRow
|
|
429
|
+
const isCursorRow = row === cursorRow;
|
|
340
430
|
// key 只用 row:保持稳定,避免逐行重建(layout 变化由父级重渲带下来)
|
|
341
|
-
return (_jsxs(Box, { children: [_jsx(Text, { color: promptColor, bold: true, children: isFirst ? prompt : ' ' }), isCursorRow ? _jsx(CursorLine, { line: line, col: cursorCol }) :
|
|
431
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: promptColor, bold: true, children: isFirst ? prompt : ' ' }), isCursorRow ? (_jsx(CursorLine, { line: line, col: cursorCol })) : disabled && isFirst && !hasContent ? (
|
|
432
|
+
/* 执行中占位提示:告知可继续输入插话 */
|
|
433
|
+
_jsx(Text, { color: theme.subtle, dimColor: true, children: "AI \u5DE5\u4F5C\u4E2D\uFF0C\u53EF\u7EE7\u7EED\u8F93\u5165\u8865\u5145\u6D88\u606F\uFF08Ctrl+C \u4E2D\u65AD\uFF0C\u53CC\u51FB Ctrl+C \u5F3A\u5236\u9000\u51FA\uFF09" })) : (_jsx(Text, { children: line || ' ' }))] }, row));
|
|
342
434
|
}) }));
|
|
343
435
|
}
|
|
344
436
|
/** 光标行渲染(稳定,不会被重建) */
|
package/src/ui/LiveArea.js
CHANGED
|
@@ -11,6 +11,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
* tool_executing → runningTools 逐行人话描述(gray dim)
|
|
12
12
|
* compacting/idle→ 无内容行
|
|
13
13
|
*
|
|
14
|
+
* ★ 暂态错误行(transientError):工作流步执行中 LLM 调用失败(会被该步重试)时,
|
|
15
|
+
* 不把它当永久红字提交进 scrollback,而是作为**状态行下方的一条黄色暂态行**显示。
|
|
16
|
+
* 它随状态行每帧刷新而被覆盖(不 strand),重试成功后由 useChat 丢弃 → 自然消失。
|
|
17
|
+
* 彻底失败(步 ok:false / 顶层 halt)才由 useChat 改走永久红字(chat.error)。
|
|
18
|
+
* 这条行同样走 INV-1 宽度钳制(clampWidthStart),不破坏防刷屏不变量。
|
|
19
|
+
*
|
|
14
20
|
* ★ 为什么这样能既"多行打字机 + 流式答案"又**不刷屏**(详见 liveViewport.ts 头部):
|
|
15
21
|
* - INV-1:每行都用 wrapToDisplayLines / clampWidthStart 按 CJK/emoji=2 钳到
|
|
16
22
|
* ≤ cols - LIVE_RIGHT_MARGIN → 终端永不自动折行 → ink eraseLines 每帧精确。
|
|
@@ -26,6 +32,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
26
32
|
import React, { useEffect, useRef, useState } from 'react';
|
|
27
33
|
import { Box, Text } from 'ink';
|
|
28
34
|
import { LIVE_RIGHT_MARGIN, clampWidthStart, wrapToDisplayLines, } from './liveViewport.js';
|
|
35
|
+
import { theme } from './theme.js';
|
|
36
|
+
import { figures } from './figures.js';
|
|
29
37
|
const STAGE_LABELS = {
|
|
30
38
|
thinking: '思考中',
|
|
31
39
|
streaming: '回答中',
|
|
@@ -37,7 +45,7 @@ const SPINNER_FRAMES = ['✶', '✸', '✹', '✺', '✹', '✷'];
|
|
|
37
45
|
/** spinner 推进 + 强制 re-render 间隔(ms)。~7Hz,远低于 ink 31Hz throttle,Windows 安全。 */
|
|
38
46
|
const SPINNER_INTERVAL_MS = 150;
|
|
39
47
|
/** 内容区行数硬顶(大终端也不铺满,保持清爽)。 */
|
|
40
|
-
const CONTENT_HARD_CAP =
|
|
48
|
+
const CONTENT_HARD_CAP = 16;
|
|
41
49
|
/** 终端高度里预留给 status(1) + 输入框(3) + StatusLine(1) + error/interrupt + 安全余量。 */
|
|
42
50
|
const RESERVED_ROWS = 9;
|
|
43
51
|
/** reasoning 行 💭 前缀 / 续行缩进的预留宽度(💭=2 + 空格;上界 4 更稳)。 */
|
|
@@ -53,28 +61,108 @@ function lastN(arr, n) {
|
|
|
53
61
|
return arr.length <= n ? arr : arr.slice(arr.length - n);
|
|
54
62
|
}
|
|
55
63
|
function toolDesc(t) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
// 长时工具的步内实时进度(LoopEvent.tool_progress)追加在描述后——
|
|
65
|
+
// 比静态 args 信息量大得多(如生图 "[ai-image-plan] round 1/1 15/31 t2i → ai_p11.png")。
|
|
66
|
+
// 宽度钳制由调用方 clampWidthStart 统一负责(INV-1),这里只拼内容。
|
|
67
|
+
const base = t.argsFriendly && t.argsFriendly.length > 0
|
|
68
|
+
? t.argsFriendly
|
|
69
|
+
: `${t.toolName}(${t.argsPreview.length > TOOL_ARGS_MAX
|
|
70
|
+
? `${t.argsPreview.slice(0, TOOL_ARGS_MAX - 1)}…`
|
|
71
|
+
: t.argsPreview})`;
|
|
72
|
+
return t.progress && t.progress.length > 0 ? `${base} · ${t.progress}` : base;
|
|
73
|
+
}
|
|
74
|
+
/** 不带 progress 的静态描述(蜂群树的描述行用;进度另起 ⎿ 行)。 */
|
|
75
|
+
function toolDescStatic(t) {
|
|
76
|
+
return t.argsFriendly && t.argsFriendly.length > 0
|
|
77
|
+
? t.argsFriendly
|
|
78
|
+
: `${t.toolName}(${t.argsPreview.length > TOOL_ARGS_MAX
|
|
79
|
+
? `${t.argsPreview.slice(0, TOOL_ARGS_MAX - 1)}…`
|
|
80
|
+
: t.argsPreview})`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 蜂群树:runningTools 里有 ≥2 个并行的 Agent 子任务时,把 tool_executing
|
|
84
|
+
* 内容区渲染成树形(借鉴 Claude Code 的 AgentProgressLine 语汇):
|
|
85
|
+
*
|
|
86
|
+
* ⚡ 3 个子任务并行中(另有 1 个工具)
|
|
87
|
+
* ├─ 子任务[explore] 检索路由实现
|
|
88
|
+
* │ ⎿ 第 2 轮 · Reading src/router.ts
|
|
89
|
+
* └─ 子任务[explore] 调研配置系统
|
|
90
|
+
* ⎿ 正在撰写报告…(已输出 850 字)
|
|
91
|
+
*
|
|
92
|
+
* - <2 个 Agent → 返回 null,调用方走既有扁平路径(单 Agent 行为不变)。
|
|
93
|
+
* - 行预算:两行模式(描述行 + ⎿ 进度行)放不下 maxLines 时降级单行模式
|
|
94
|
+
* (进度拼在描述后),仍超则 lastN 截尾——INV-2 恒成立。
|
|
95
|
+
* - 每行经 clampWidthStart 钳宽(INV-1;树形字形 ├└│⎿ 已入 charWidth=2 上界)。
|
|
96
|
+
* - Agent 的 progress 行(agent.ts publish 的「label」第 N 轮 · …)剥掉与
|
|
97
|
+
* 描述行重复的「label」前缀,树里不重复念名字。
|
|
98
|
+
* 导出供单测断言(liveArea.test.ts 蜂群树 describe)。
|
|
99
|
+
*/
|
|
100
|
+
export function buildSwarmLines(runningTools, maxWidth, maxLines) {
|
|
101
|
+
const agents = runningTools.filter((t) => t.toolName === 'Agent');
|
|
102
|
+
if (agents.length < 2)
|
|
103
|
+
return null;
|
|
104
|
+
const others = runningTools.filter((t) => t.toolName !== 'Agent');
|
|
105
|
+
const queued = agents.filter((agent) => agent.progressDetail?.kind === 'subagent' && agent.progressDetail.phase === 'queued').length;
|
|
106
|
+
const activeCount = agents.length - queued;
|
|
107
|
+
const header = `${figures.swarm} ${activeCount} 运行${queued > 0 ? ` · ${queued} 排队` : ''}${others.length > 0 ? `(另有 ${others.length} 个工具)` : ''}`;
|
|
108
|
+
// 进度文案剥冗余 label 前缀(描述行已含「子任务[type] label」)
|
|
109
|
+
const stripLabel = (p) => p.replace(/^「[^」]*」\s*/, '');
|
|
110
|
+
const twoLine = 1 + agents.length * 2 + others.length <= maxLines;
|
|
111
|
+
const lines = [header];
|
|
112
|
+
agents.forEach((t, i) => {
|
|
113
|
+
const isLast = i === agents.length - 1 && others.length === 0;
|
|
114
|
+
const branch = isLast ? figures.corner : figures.branch;
|
|
115
|
+
const progress = t.progress ? stripLabel(t.progress) : '';
|
|
116
|
+
if (twoLine) {
|
|
117
|
+
lines.push(`${branch} ${toolDescStatic(t)}`);
|
|
118
|
+
lines.push(`${isLast ? ' ' : `${figures.pipe} `}${figures.elbow} ${progress || '启动中…'}`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
lines.push(`${branch} ${toolDescStatic(t)}${progress ? ` · ${progress}` : ''}`);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
for (const t of others)
|
|
125
|
+
lines.push(` ${toolDesc(t)}`);
|
|
126
|
+
return lastN(lines, maxLines).map((l) => clampWidthStart(l, maxWidth));
|
|
62
127
|
}
|
|
63
128
|
/**
|
|
64
129
|
* 纯函数:把一帧的 props(+ 动画 frame / 已耗时秒数)算成 LiveView。
|
|
65
|
-
* idle
|
|
130
|
+
* idle 且无暂态错误时返回 null(live 区隐藏);idle 但有暂态错误时仅渲染该黄色行
|
|
131
|
+
* (让"重试中/已恢复"提示在步间隙 stage 短暂回 idle 时也不闪没)。
|
|
132
|
+
* 导出供单测断言 INV-1(每行宽)/ INV-2(行数)/ 颜色层次。
|
|
66
133
|
*/
|
|
67
134
|
export function buildLiveView(props) {
|
|
68
|
-
const { progressStage, reasoningPreview, streamingText, runningTools, pluginProgress, terminalCols, terminalRows, frame, elapsedSec, } = props;
|
|
69
|
-
if (progressStage === 'idle')
|
|
70
|
-
return null;
|
|
71
|
-
const stage = progressStage;
|
|
135
|
+
const { progressStage, reasoningPreview, streamingText, runningTools, pluginProgress, transientError, terminalCols, terminalRows, frame, elapsedSec, } = props;
|
|
72
136
|
const maxWidth = Math.max(8, terminalCols - LIVE_RIGHT_MARGIN);
|
|
73
137
|
const maxLines = contentMaxLines(terminalRows);
|
|
138
|
+
// 暂态错误行:单行、钳宽(满足 INV-1)。空串视为无。
|
|
139
|
+
const transientErrorLine = transientError && transientError.length > 0
|
|
140
|
+
? clampWidthStart(transientError, maxWidth)
|
|
141
|
+
: null;
|
|
142
|
+
// idle 且无暂态错误 → 整个 live 区隐藏(保持既有行为)。
|
|
143
|
+
// idle 但有暂态错误 → 只渲染那一行黄字,无状态行 / 无 spinner(避免 idle 还转圈)。
|
|
144
|
+
if (progressStage === 'idle') {
|
|
145
|
+
if (transientErrorLine === null)
|
|
146
|
+
return null;
|
|
147
|
+
return {
|
|
148
|
+
statusLine: '',
|
|
149
|
+
statusColor: theme.user,
|
|
150
|
+
contentLines: [],
|
|
151
|
+
contentDim: true,
|
|
152
|
+
transientErrorLine,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const stage = progressStage;
|
|
74
156
|
// ---- 状态行 ----
|
|
75
157
|
let status = `${frame} ${STAGE_LABELS[stage]} (${elapsedSec}s)`;
|
|
76
158
|
if (pluginProgress) {
|
|
77
|
-
|
|
159
|
+
// current 缺省 = 纯文案进度(工作流步骤 title),不渲染数字
|
|
160
|
+
const num = pluginProgress.current !== undefined
|
|
161
|
+
? `${pluginProgress.current}/${pluginProgress.max ?? '?'}`
|
|
162
|
+
: '';
|
|
163
|
+
const msg = pluginProgress.message ?? '';
|
|
164
|
+
const body = [num, msg].filter(Boolean).join(' ');
|
|
165
|
+
status += ` · [plugin:${pluginProgress.pluginId}]${body ? ` ${body}` : ''}`;
|
|
78
166
|
}
|
|
79
167
|
status = clampWidthStart(status, maxWidth);
|
|
80
168
|
// ---- 内容区 ----
|
|
@@ -82,7 +170,7 @@ export function buildLiveView(props) {
|
|
|
82
170
|
let contentDim = true;
|
|
83
171
|
if (stage === 'thinking' && reasoningPreview.length > 0) {
|
|
84
172
|
const wrapped = wrapToDisplayLines(reasoningPreview, maxWidth - REASONING_PREFIX_RESERVE);
|
|
85
|
-
contentLines = lastN(wrapped, maxLines).map((line, i) => i === 0 ?
|
|
173
|
+
contentLines = lastN(wrapped, maxLines).map((line, i) => i === 0 ? `${figures.thought} ${line}` : ` ${line}`);
|
|
86
174
|
contentDim = true;
|
|
87
175
|
}
|
|
88
176
|
else if (stage === 'streaming' && streamingText.length > 0) {
|
|
@@ -90,14 +178,19 @@ export function buildLiveView(props) {
|
|
|
90
178
|
contentDim = false; // 答案 = 主角,默认亮色
|
|
91
179
|
}
|
|
92
180
|
else if (stage === 'tool_executing' && runningTools.length > 0) {
|
|
93
|
-
|
|
181
|
+
// ≥2 个并行 Agent 子任务 → 蜂群树;否则既有扁平路径(单工具/单 Agent 不变)
|
|
182
|
+
const swarm = buildSwarmLines(runningTools, maxWidth, maxLines);
|
|
183
|
+
contentLines =
|
|
184
|
+
swarm ??
|
|
185
|
+
lastN(runningTools, maxLines).map((t) => clampWidthStart(` ${toolDesc(t)}`, maxWidth));
|
|
94
186
|
contentDim = true;
|
|
95
187
|
}
|
|
96
188
|
return {
|
|
97
189
|
statusLine: status,
|
|
98
|
-
statusColor: stage === 'compacting' ?
|
|
190
|
+
statusColor: stage === 'compacting' ? theme.plugin : theme.user,
|
|
99
191
|
contentLines,
|
|
100
192
|
contentDim,
|
|
193
|
+
transientErrorLine,
|
|
101
194
|
};
|
|
102
195
|
}
|
|
103
196
|
export const LiveArea = React.memo(function LiveArea(props) {
|
|
@@ -118,8 +211,8 @@ export const LiveArea = React.memo(function LiveArea(props) {
|
|
|
118
211
|
const timer = setInterval(() => setTick((t) => (t + 1) % 1_000_000), SPINNER_INTERVAL_MS);
|
|
119
212
|
return () => clearInterval(timer);
|
|
120
213
|
}, [progressStage]);
|
|
121
|
-
|
|
122
|
-
|
|
214
|
+
// 不在 idle 直接 return:idle 但存在暂态错误时 buildLiveView 仍会返回一个
|
|
215
|
+
// 只含 transientErrorLine 的 view(让"已恢复/重试中"提示在步间隙也不闪没)。
|
|
123
216
|
const now = Date.now();
|
|
124
217
|
const elapsedSec = startRef.current
|
|
125
218
|
? Math.max(0, Math.floor((now - startRef.current) / 1000))
|
|
@@ -128,5 +221,5 @@ export const LiveArea = React.memo(function LiveArea(props) {
|
|
|
128
221
|
const view = buildLiveView({ ...props, frame, elapsedSec });
|
|
129
222
|
if (!view)
|
|
130
223
|
return null;
|
|
131
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: view.statusColor, bold: true, wrap: "truncate", children: view.statusLine }), view.contentLines.map((line, i) => (_jsx(Text, { color: view.contentDim ?
|
|
224
|
+
return (_jsxs(Box, { flexDirection: "column", children: [view.statusLine.length > 0 && (_jsx(Text, { color: view.statusColor, bold: true, wrap: "truncate", children: view.statusLine })), view.contentLines.map((line, i) => (_jsx(Text, { color: view.contentDim ? theme.subtle : theme.answer, dimColor: view.contentDim, wrap: "truncate", children: line.length > 0 ? line : ' ' }, `live-${i}`))), view.transientErrorLine !== null && (_jsx(Text, { color: theme.warning, wrap: "truncate", children: view.transientErrorLine }))] }));
|
|
132
225
|
});
|