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.
Files changed (484) hide show
  1. package/README.md +14 -12
  2. package/package.json +34 -1
  3. package/plugins/cron-runner/.claude-plugin/plugin.json +5 -0
  4. package/plugins/cron-runner/commands/cron.md +26 -0
  5. package/plugins/cron-runner/commands/crons.md +7 -0
  6. package/plugins/cron-runner/plugin.js +34 -0
  7. package/plugins/cron-runner/src/commands.js +348 -0
  8. package/plugins/cron-runner/src/cronTime.js +148 -0
  9. package/plugins/cron-runner/src/lock.js +68 -0
  10. package/plugins/cron-runner/src/runs.js +89 -0
  11. package/plugins/cron-runner/src/scheduleEngine.js +72 -0
  12. package/plugins/cron-runner/src/scheduler.js +355 -0
  13. package/plugins/cron-runner/src/schema.js +140 -0
  14. package/plugins/cron-runner/src/service.js +167 -0
  15. package/plugins/cron-runner/src/store.js +298 -0
  16. package/plugins/cron-runner/src/types.js +1 -0
  17. package/plugins/workflow-runner/commands/workflow.md +4 -4
  18. package/plugins/workflow-runner/commands/workflows.md +1 -1
  19. package/plugins/workflow-runner/plugin.js +3 -1
  20. package/plugins/workflow-runner/src/agentCommon.js +249 -51
  21. package/plugins/workflow-runner/src/dslManifest.js +72 -0
  22. package/plugins/workflow-runner/src/expressions.js +198 -15
  23. package/plugins/workflow-runner/src/index.js +40 -8
  24. package/plugins/workflow-runner/src/jsonPayload.js +1 -1
  25. package/plugins/workflow-runner/src/loader.js +286 -72
  26. package/plugins/workflow-runner/src/multimodal.js +37 -0
  27. package/plugins/workflow-runner/src/recovery.js +49 -39
  28. package/plugins/workflow-runner/src/runner.js +802 -287
  29. package/plugins/workflow-runner/src/stepExecutors/agent.js +157 -39
  30. package/plugins/workflow-runner/src/stepExecutors/assert.js +16 -3
  31. package/plugins/workflow-runner/src/stepExecutors/llm.js +60 -111
  32. package/plugins/workflow-runner/src/stepExecutors/skill.js +47 -47
  33. package/plugins/workflow-runner/src/stepExecutors/tool.js +76 -10
  34. package/plugins/workflow-runner/src/stepExecutors/verify.js +27 -10
  35. package/plugins/workflow-runner/src/taskIdentity.js +296 -0
  36. package/plugins/workflow-runner/src/types.js +19 -9
  37. package/plugins/workflow-runner/src/workflowState.js +516 -33
  38. package/skills/adversarial-review/SKILL.md +0 -1
  39. package/skills/ai-image/SKILL.md +89 -0
  40. package/skills/ai-image/scripts/generate.mjs +497 -0
  41. package/skills/ai-image/scripts/generate_from_plan.mjs +469 -0
  42. package/skills/ai-image/scripts/generate_from_plan_test.mjs +223 -0
  43. package/skills/ai-image/scripts/generate_test.mjs +74 -0
  44. package/skills/browser-automation/SKILL.md +47 -0
  45. package/skills/docx/SKILL.md +25 -3
  46. package/skills/docx/scripts/office/helpers/__pycache__/__init__.cpython-314.pyc +0 -0
  47. package/skills/docx/scripts/office/helpers/__pycache__/merge_runs.cpython-314.pyc +0 -0
  48. package/skills/docx/scripts/office/helpers/__pycache__/simplify_redlines.cpython-314.pyc +0 -0
  49. package/skills/docx/scripts/office/validators/__pycache__/__init__.cpython-314.pyc +0 -0
  50. package/skills/docx/scripts/office/validators/__pycache__/base.cpython-314.pyc +0 -0
  51. package/skills/docx/scripts/office/validators/__pycache__/docx.cpython-314.pyc +0 -0
  52. package/skills/docx/scripts/office/validators/__pycache__/pptx.cpython-314.pyc +0 -0
  53. package/skills/docx/scripts/office/validators/__pycache__/redlining.cpython-314.pyc +0 -0
  54. package/skills/docx/scripts/opc_check.py +253 -0
  55. package/skills/image-gen-openrouter/SKILL.md +10 -2
  56. package/skills/image-stats/SKILL.md +65 -0
  57. package/skills/image-stats/scripts/__pycache__/image_stats.cpython-314.pyc +0 -0
  58. package/skills/image-stats/scripts/__pycache__/image_stats_test.cpython-314.pyc +0 -0
  59. package/skills/image-stats/scripts/image_stats.py +368 -0
  60. package/skills/image-stats/scripts/image_stats_test.py +181 -0
  61. package/skills/pptx/SKILL.md +123 -95
  62. package/skills/pptx/design.md +82 -0
  63. package/skills/pptx/examples/README.md +29 -0
  64. package/skills/pptx/examples/hybrid_example.mjs +107 -0
  65. package/skills/pptx/examples/hybrid_example.pptx +0 -0
  66. package/skills/pptx/pptxgenjs.md +41 -0
  67. package/skills/pptx/scripts/deck_helpers.mjs +224 -0
  68. package/skills/pptx/scripts/layout_lint.py +293 -0
  69. package/skills/pptx/scripts/layout_lint_test.py +160 -0
  70. package/skills/pptx/scripts/opc_check.py +339 -0
  71. package/skills/pptx/scripts/svg_fallback.mjs +145 -0
  72. package/skills/pptx/svg.md +67 -0
  73. package/skills/tts-zh/SKILL.md +19 -2
  74. package/skills/ui-design/SKILL.md +158 -0
  75. package/skills/ui-design/claude_design.md +309 -0
  76. package/skills/ui-design/evals/evals.json +254 -0
  77. package/skills/ui-design/references/aesthetic-direction.md +83 -0
  78. package/skills/ui-design/references/claude-design-protocol.md +36 -0
  79. package/skills/ui-design/references/design-context.md +53 -0
  80. package/skills/ui-design/references/design-execution-playbook.md +82 -0
  81. package/skills/ui-design/references/export-pptx.md +124 -0
  82. package/skills/ui-design/references/layout-composition.md +654 -0
  83. package/skills/ui-design/references/preview-feedback.md +37 -0
  84. package/skills/ui-design/references/source-image-layout.md +189 -0
  85. package/skills/ui-design/references/starter-components.md +78 -0
  86. package/skills/ui-design/references/vi-aegis-vector.md +144 -0
  87. package/skills/ui-design/references/vi-amber-prism.md +133 -0
  88. package/skills/ui-design/references/vi-aqua-glass.md +200 -0
  89. package/skills/ui-design/references/vi-comfort-vision.md +147 -0
  90. package/skills/ui-design/references/vi-ember-prism.md +140 -0
  91. package/skills/ui-design/references/vi-nebula-console.md +151 -0
  92. package/skills/ui-design/references/vi-obsidian-optics.md +139 -0
  93. package/skills/ui-design/references/vi-obsidian-xui.md +143 -0
  94. package/skills/ui-design/references/vi-precision-horizon-dark.md +117 -0
  95. package/skills/ui-design/references/vi-precision-horizon.md +215 -0
  96. package/skills/ui-design/references/vi-solar-relay.md +130 -0
  97. package/skills/ui-design/references/vi-template-workflow.md +48 -0
  98. package/skills/ui-design/references/vi-verdant-grid.md +141 -0
  99. package/skills/ui-design/references/vi-violet-meridian.md +172 -0
  100. package/skills/ui-design/scripts/__pycache__/assemble_material.cpython-314.pyc +0 -0
  101. package/skills/ui-design/scripts/__pycache__/assemble_material_test.cpython-314.pyc +0 -0
  102. package/skills/ui-design/scripts/__pycache__/chart_sanity_check.cpython-314.pyc +0 -0
  103. package/skills/ui-design/scripts/__pycache__/check_language_policy.cpython-314.pyc +0 -0
  104. package/skills/ui-design/scripts/__pycache__/check_ui_artifact.cpython-314.pyc +0 -0
  105. package/skills/ui-design/scripts/__pycache__/check_ui_artifact_pptx_test.cpython-314.pyc +0 -0
  106. package/skills/ui-design/scripts/__pycache__/deck_pages_check.cpython-314.pyc +0 -0
  107. package/skills/ui-design/scripts/__pycache__/deck_pages_check_test.cpython-314.pyc +0 -0
  108. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check.cpython-314.pyc +0 -0
  109. package/skills/ui-design/scripts/__pycache__/deck_visual_style_check_test.cpython-314.pyc +0 -0
  110. package/skills/ui-design/scripts/__pycache__/design_budget_check.cpython-314.pyc +0 -0
  111. package/skills/ui-design/scripts/__pycache__/design_budget_check_test.cpython-314.pyc +0 -0
  112. package/skills/ui-design/scripts/__pycache__/design_repair_hints.cpython-314.pyc +0 -0
  113. package/skills/ui-design/scripts/__pycache__/design_repair_hints_test.cpython-314.pyc +0 -0
  114. package/skills/ui-design/scripts/__pycache__/design_style_check.cpython-314.pyc +0 -0
  115. package/skills/ui-design/scripts/__pycache__/design_style_check_test.cpython-314.pyc +0 -0
  116. package/skills/ui-design/scripts/__pycache__/draft_coverage_check.cpython-314.pyc +0 -0
  117. package/skills/ui-design/scripts/__pycache__/extract_source_assets.cpython-314.pyc +0 -0
  118. package/skills/ui-design/scripts/__pycache__/extract_source_assets_test.cpython-314.pyc +0 -0
  119. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect.cpython-314.pyc +0 -0
  120. package/skills/ui-design/scripts/__pycache__/generated_image_review_collect_test.cpython-314.pyc +0 -0
  121. package/skills/ui-design/scripts/__pycache__/image_plan_lint.cpython-314.pyc +0 -0
  122. package/skills/ui-design/scripts/__pycache__/image_plan_lint_test.cpython-314.pyc +0 -0
  123. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite.cpython-314.pyc +0 -0
  124. package/skills/ui-design/scripts/__pycache__/image_prompt_rewrite_test.cpython-314.pyc +0 -0
  125. package/skills/ui-design/scripts/__pycache__/layout_balance.cpython-314.pyc +0 -0
  126. package/skills/ui-design/scripts/__pycache__/layout_balance_test.cpython-314.pyc +0 -0
  127. package/skills/ui-design/scripts/__pycache__/normalize_design_json.cpython-314.pyc +0 -0
  128. package/skills/ui-design/scripts/__pycache__/normalize_design_json_test.cpython-314.pyc +0 -0
  129. package/skills/ui-design/scripts/__pycache__/plan_source_layout.cpython-314.pyc +0 -0
  130. package/skills/ui-design/scripts/__pycache__/plan_source_layout_test.cpython-314.pyc +0 -0
  131. package/skills/ui-design/scripts/__pycache__/resolve_source_hint.cpython-314.pyc +0 -0
  132. package/skills/ui-design/scripts/__pycache__/resolve_source_hint_test.cpython-314.pyc +0 -0
  133. package/skills/ui-design/scripts/__pycache__/resolve_source_input.cpython-314.pyc +0 -0
  134. package/skills/ui-design/scripts/__pycache__/resolve_source_input_test.cpython-314.pyc +0 -0
  135. package/skills/ui-design/scripts/__pycache__/scaffold_ui_artifact.cpython-314.pyc +0 -0
  136. package/skills/ui-design/scripts/__pycache__/source_usage_check.cpython-314.pyc +0 -0
  137. package/skills/ui-design/scripts/__pycache__/source_usage_check_test.cpython-314.pyc +0 -0
  138. package/skills/ui-design/scripts/__pycache__/text_readability_pixel.cpython-314.pyc +0 -0
  139. package/skills/ui-design/scripts/__pycache__/visual_quality_gate.cpython-314.pyc +0 -0
  140. package/skills/ui-design/scripts/__pycache__/visual_quality_gate_test.cpython-314.pyc +0 -0
  141. package/skills/ui-design/scripts/assemble_material.py +217 -0
  142. package/skills/ui-design/scripts/assemble_material_test.py +149 -0
  143. package/skills/ui-design/scripts/browser_check_ui_artifact.mjs +221 -0
  144. package/skills/ui-design/scripts/chart_sanity_check.py +261 -0
  145. package/skills/ui-design/scripts/chart_sanity_check_test.py +165 -0
  146. package/skills/ui-design/scripts/check_language_policy.py +351 -0
  147. package/skills/ui-design/scripts/check_ui_artifact.py +435 -0
  148. package/skills/ui-design/scripts/check_ui_artifact_pptx_test.py +251 -0
  149. package/skills/ui-design/scripts/deck_pages_check.py +158 -0
  150. package/skills/ui-design/scripts/deck_pages_check_test.py +134 -0
  151. package/skills/ui-design/scripts/deck_visual_style_check.py +767 -0
  152. package/skills/ui-design/scripts/deck_visual_style_check_test.py +713 -0
  153. package/skills/ui-design/scripts/design_budget_check.py +271 -0
  154. package/skills/ui-design/scripts/design_budget_check_test.py +183 -0
  155. package/skills/ui-design/scripts/design_repair_hints.py +162 -0
  156. package/skills/ui-design/scripts/design_repair_hints_test.py +54 -0
  157. package/skills/ui-design/scripts/design_style_check.py +397 -0
  158. package/skills/ui-design/scripts/design_style_check_test.py +233 -0
  159. package/skills/ui-design/scripts/draft_coverage_check.py +184 -0
  160. package/skills/ui-design/scripts/draft_coverage_check_test.py +131 -0
  161. package/skills/ui-design/scripts/export_pptx_from_html.mjs +2367 -0
  162. package/skills/ui-design/scripts/extract_source_assets.py +607 -0
  163. package/skills/ui-design/scripts/extract_source_assets_test.py +256 -0
  164. package/skills/ui-design/scripts/generated_image_review_collect.py +206 -0
  165. package/skills/ui-design/scripts/generated_image_review_collect_test.py +91 -0
  166. package/skills/ui-design/scripts/image_plan_lint.py +571 -0
  167. package/skills/ui-design/scripts/image_plan_lint_test.py +515 -0
  168. package/skills/ui-design/scripts/image_prompt_rewrite.py +713 -0
  169. package/skills/ui-design/scripts/image_prompt_rewrite_test.py +966 -0
  170. package/skills/ui-design/scripts/layout_balance.py +881 -0
  171. package/skills/ui-design/scripts/layout_balance_test.py +927 -0
  172. package/skills/ui-design/scripts/normalize_design_json.py +272 -0
  173. package/skills/ui-design/scripts/normalize_design_json_test.py +119 -0
  174. package/skills/ui-design/scripts/plan_source_layout.py +1450 -0
  175. package/skills/ui-design/scripts/plan_source_layout_test.py +1136 -0
  176. package/skills/ui-design/scripts/resolve_source_input.py +270 -0
  177. package/skills/ui-design/scripts/resolve_source_input_test.py +98 -0
  178. package/skills/ui-design/scripts/scaffold_ui_artifact.py +377 -0
  179. package/skills/ui-design/scripts/source_usage_check.py +581 -0
  180. package/skills/ui-design/scripts/source_usage_check_test.py +427 -0
  181. package/skills/ui-design/scripts/text_readability_pixel.py +340 -0
  182. package/skills/ui-design/scripts/text_readability_pixel_test.py +219 -0
  183. package/skills/ui-design/scripts/visual_quality_gate.py +301 -0
  184. package/skills/ui-design/scripts/visual_quality_gate_test.py +233 -0
  185. package/skills/ui-design/tests/e2e/prompts/deck.md +19 -0
  186. package/skills/ui-design/tests/e2e/prompts/webpage.md +17 -0
  187. package/skills/ui-design/tests/e2e/render_check.mjs +101 -0
  188. package/skills/ui-design/tests/e2e/rubric.json +54 -0
  189. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/browser-check.json +49 -0
  190. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/language-check.txt +12 -0
  191. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/checks/static-check.txt +15 -0
  192. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/outputs/index.html +837 -0
  193. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/prompt.md +12 -0
  194. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/review.md +21 -0
  195. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/desktop.png +0 -0
  196. package/skills/ui-design/tests/e2e/runs/aegis-vector-preview-1/screenshots/mobile.png +0 -0
  197. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/homepage.html +373 -0
  198. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/outputs/platform.html +378 -0
  199. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/prompt.md +13 -0
  200. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/review.md +26 -0
  201. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
  202. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
  203. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
  204. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
  205. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
  206. package/skills/ui-design/tests/e2e/runs/amber-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
  207. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/checks/static-check.txt +2 -0
  208. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/outputs/index.html +656 -0
  209. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/prompt.md +12 -0
  210. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-1/render_check.mjs +67 -0
  211. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/checks/static-check.txt +2 -0
  212. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/outputs/index.html +587 -0
  213. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/prompt.md +12 -0
  214. package/skills/ui-design/tests/e2e/runs/aqua-glass-iteration-2/review.md +36 -0
  215. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/browser-check.json +49 -0
  216. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/language-check.txt +8 -0
  217. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/checks/static-check.txt +16 -0
  218. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/outputs/index.html +739 -0
  219. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/prompt.md +11 -0
  220. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/review.md +22 -0
  221. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/desktop.png +0 -0
  222. package/skills/ui-design/tests/e2e/runs/aqua-glass-volcano-refresh-1/screenshots/mobile.png +0 -0
  223. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/checks/browser-check.json +52 -0
  224. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/outputs/index.html +641 -0
  225. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/desktop.png +0 -0
  226. package/skills/ui-design/tests/e2e/runs/comfort-vision-preview-1/screenshots/mobile.png +0 -0
  227. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/outputs/index.html +467 -0
  228. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/browser-check.json +49 -0
  229. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/desktop.png +0 -0
  230. package/skills/ui-design/tests/e2e/runs/ember-prism-red-preview-1/screenshots/mobile.png +0 -0
  231. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/homepage.html +373 -0
  232. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/outputs/platform.html +378 -0
  233. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/prompt.md +13 -0
  234. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/review.md +26 -0
  235. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/browser-check.json +49 -0
  236. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/desktop.png +0 -0
  237. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/homepage/mobile.png +0 -0
  238. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/browser-check.json +49 -0
  239. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/desktop.png +0 -0
  240. package/skills/ui-design/tests/e2e/runs/ember-prism-screenshot-check-1/screenshots/platform/mobile.png +0 -0
  241. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/browser-check.json +49 -0
  242. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/language-check.txt +4 -0
  243. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/checks/static-check.txt +2 -0
  244. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/execution_notes.md +10 -0
  245. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/outputs/index.html +587 -0
  246. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/prompt.md +14 -0
  247. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/review.md +13 -0
  248. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/desktop.png +0 -0
  249. package/skills/ui-design/tests/e2e/runs/empty-agent-protocol-check/screenshots/mobile.png +0 -0
  250. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/browser-check.json +24 -0
  251. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/checks/static-check.txt +2 -0
  252. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/execution_notes.md +21 -0
  253. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/outputs/deck.html +451 -0
  254. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-01.png +0 -0
  255. package/skills/ui-design/tests/e2e/runs/iteration-1/deck/screenshots/slide-02.png +0 -0
  256. package/skills/ui-design/tests/e2e/runs/iteration-1/review.md +79 -0
  257. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/browser-check.json +26 -0
  258. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/checks/static-check.txt +2 -0
  259. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/execution_notes.md +20 -0
  260. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/outputs/index.html +534 -0
  261. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/desktop.png +0 -0
  262. package/skills/ui-design/tests/e2e/runs/iteration-1/webpage/screenshots/mobile.png +0 -0
  263. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/browser-check.json +64 -0
  264. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/language-check.txt +7 -0
  265. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/quick-validate.txt +1 -0
  266. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-console.txt +2 -0
  267. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/checks/static-homepage.txt +2 -0
  268. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/console.html +600 -0
  269. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/outputs/homepage.html +556 -0
  270. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/prompt.md +29 -0
  271. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/review.md +57 -0
  272. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-desktop.png +0 -0
  273. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/console-mobile.png +0 -0
  274. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-desktop.png +0 -0
  275. package/skills/ui-design/tests/e2e/runs/nebula-console-iteration-1/screenshots/homepage-mobile.png +0 -0
  276. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/browser-check.json +33 -0
  277. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/language-check.txt +6 -0
  278. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/quick-validate.txt +1 -0
  279. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/checks/static-check.txt +2 -0
  280. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/outputs/index.html +682 -0
  281. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/prompt.md +13 -0
  282. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/review.md +59 -0
  283. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/desktop.png +0 -0
  284. package/skills/ui-design/tests/e2e/runs/obsidian-optics-iteration-1/screenshots/mobile.png +0 -0
  285. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-01.html +466 -0
  286. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/outputs/page-02.html +433 -0
  287. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/prompt.md +13 -0
  288. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/browser-check.json +49 -0
  289. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/desktop.png +0 -0
  290. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-01/mobile.png +0 -0
  291. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/browser-check.json +49 -0
  292. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/desktop.png +0 -0
  293. package/skills/ui-design/tests/e2e/runs/obsidian-xui-screenshot-check-1/screenshots/page-02/mobile.png +0 -0
  294. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/browser-check.json +49 -0
  295. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/language-check.txt +3 -0
  296. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/checks/static-check.txt +2 -0
  297. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/execution_notes.md +24 -0
  298. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/outputs/index.html +723 -0
  299. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/prompt.md +15 -0
  300. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/review.md +26 -0
  301. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/desktop.png +0 -0
  302. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-1/screenshots/mobile.png +0 -0
  303. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-dark.json +49 -0
  304. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/browser-light.json +49 -0
  305. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/language-check.txt +11 -0
  306. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-dark.txt +2 -0
  307. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/checks/static-light.txt +3 -0
  308. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/execution_notes.md +23 -0
  309. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/dark.html +392 -0
  310. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/outputs/light.html +476 -0
  311. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/prompt.md +23 -0
  312. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/review.md +41 -0
  313. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/desktop.png +0 -0
  314. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/dark/mobile.png +0 -0
  315. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/desktop.png +0 -0
  316. package/skills/ui-design/tests/e2e/runs/precision-horizon-iteration-2/screenshots/light/mobile.png +0 -0
  317. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/browser-check.json +54 -0
  318. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/language-check.txt +5 -0
  319. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/quick-validate.txt +1 -0
  320. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/checks/static-check.txt +2 -0
  321. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/outputs/index.html +765 -0
  322. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/prompt.md +15 -0
  323. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/review.md +59 -0
  324. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/desktop.png +0 -0
  325. package/skills/ui-design/tests/e2e/runs/solar-relay-iteration-1/screenshots/mobile.png +0 -0
  326. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/outputs/index.html +508 -0
  327. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/browser-check.json +49 -0
  328. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/desktop.png +0 -0
  329. package/skills/ui-design/tests/e2e/runs/verdant-grid-preview-1/screenshots/mobile.png +0 -0
  330. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/browser-check.json +54 -0
  331. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/language-check.txt +6 -0
  332. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/quick-validate.txt +1 -0
  333. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/checks/static-check.txt +2 -0
  334. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/outputs/index.html +788 -0
  335. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/prompt.md +14 -0
  336. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/review.md +60 -0
  337. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/desktop.png +0 -0
  338. package/skills/ui-design/tests/e2e/runs/violet-meridian-iteration-1/screenshots/mobile.png +0 -0
  339. package/skills/video-compose/SKILL.md +8 -1
  340. package/skills/web-crawler/SKILL.md +70 -0
  341. package/skills/web-crawler/scripts/crawl.mjs +538 -0
  342. package/skills/web-crawler/scripts/crawl.test.mjs +204 -0
  343. package/skills/xlsx/SKILL.md +12 -0
  344. package/skills/xlsx/scripts/opc_check.py +253 -0
  345. package/src/advisorState.js +22 -0
  346. package/src/askBridge.js +97 -3
  347. package/src/bootstrap/workingDir.js +12 -1
  348. package/src/cli/args.js +17 -1
  349. package/src/cli/configMenu.js +236 -0
  350. package/src/cli/configWizard.js +7 -5
  351. package/src/cli/print.js +37 -4
  352. package/src/cli/streamJson.js +77 -24
  353. package/src/cli/wizards/advisorWizard.js +147 -0
  354. package/src/cli/wizards/fieldForm.js +149 -0
  355. package/src/cli/wizards/imageWizard.js +60 -0
  356. package/src/cli/wizards/openRouterWizard.js +23 -0
  357. package/src/cli/wizards/providerPresets.js +95 -0
  358. package/src/cli/wizards/providerWizard.js +219 -0
  359. package/src/cli/wizards/searchWizard.js +23 -0
  360. package/src/cli/wizards/ttsWizard.js +34 -0
  361. package/src/config/configFile.js +441 -83
  362. package/src/config/configService.js +446 -0
  363. package/src/config.js +24 -64
  364. package/src/context/agentHome.js +9 -0
  365. package/src/context/archive.js +7 -2
  366. package/src/context/compact.js +8 -5
  367. package/src/context/contextLock.js +81 -0
  368. package/src/context/persistContext.js +30 -11
  369. package/src/context/reactiveCompact.js +4 -2
  370. package/src/context/recentDirs.js +21 -61
  371. package/src/context/sessionPath.js +97 -23
  372. package/src/context/sessionRegistry.js +303 -24
  373. package/src/context/tokenCounter.js +18 -0
  374. package/src/context/workspaceIndex.js +731 -0
  375. package/src/infra/verification.js +28 -15
  376. package/src/llm/client.js +394 -159
  377. package/src/llm/providers/anthropicFormat.js +241 -0
  378. package/src/llm/providers/openaiFormat.js +190 -0
  379. package/src/loop.js +219 -32
  380. package/src/main.js +61 -11
  381. package/src/messageQueue.js +97 -0
  382. package/src/multimodal.js +203 -0
  383. package/src/plugin-sdk.js +15 -0
  384. package/src/plugins/commandRouter.js +3 -0
  385. package/src/plugins/hookEngine.js +5 -1
  386. package/src/plugins/pluginLifecycle.js +28 -0
  387. package/src/plugins/pluginLoader.js +2 -1
  388. package/src/plugins/pluginRunner.js +49 -21
  389. package/src/plugins/transcript.js +4 -3
  390. package/src/prompts/pluginList.js +5 -5
  391. package/src/prompts/projectInstructions.js +3 -3
  392. package/src/prompts/promptAssembly.js +133 -144
  393. package/src/prompts/skillList.js +12 -22
  394. package/src/prompts/system.js +0 -1
  395. package/src/session/runAgentTurn.js +70 -0
  396. package/src/session/runTurn.js +41 -6
  397. package/src/toolGate.js +17 -0
  398. package/src/tools/advisor/advisor.js +379 -0
  399. package/src/tools/agent/agent.js +555 -0
  400. package/src/tools/agent/agentTypes.js +59 -0
  401. package/src/tools/agent/coordinator.js +93 -0
  402. package/src/tools/agent/worktree.js +270 -0
  403. package/src/tools/ask/ask.js +7 -2
  404. package/src/tools/bash/bash.js +112 -18
  405. package/src/tools/download/download.js +144 -0
  406. package/src/tools/edit/edit.js +1 -0
  407. package/src/tools/edit/multi-edit.js +1 -0
  408. package/src/tools/genimage/genimage.js +242 -0
  409. package/src/tools/genspeech/genspeech.js +67 -0
  410. package/src/tools/glob/glob.js +1 -0
  411. package/src/tools/grep/grep.js +3 -0
  412. package/src/tools/grep/rgPath.js +2 -0
  413. package/src/tools/index.js +25 -2
  414. package/src/tools/read/read.js +1 -0
  415. package/src/tools/shared/killTree.js +52 -0
  416. package/src/tools/toolProgressBridge.js +48 -0
  417. package/src/tools/webbrowser/agentBrowserPath.js +258 -0
  418. package/src/tools/webbrowser/browser.js +59 -42
  419. package/src/tools/webbrowser/browserControl.js +118 -0
  420. package/src/tools/webbrowser/browserDaemon.js +97 -0
  421. package/src/tools/webbrowser/browserService.js +27 -0
  422. package/src/tools/webbrowser/browserStream.js +119 -0
  423. package/src/tools/webbrowser/webbrowser.js +699 -130
  424. package/src/tools/webfetch/webfetch.js +1 -0
  425. package/src/tools/websearch/websearch.js +134 -51
  426. package/src/tools/write/write.js +1 -0
  427. package/src/ui/App.js +249 -22
  428. package/src/ui/AskQuestion.js +29 -10
  429. package/src/ui/InputBox.js +104 -12
  430. package/src/ui/LiveArea.js +112 -19
  431. package/src/ui/MessageList.js +100 -14
  432. package/src/ui/ModelPicker.js +56 -0
  433. package/src/ui/QueuedMessagesBanner.js +14 -0
  434. package/src/ui/Root.js +18 -10
  435. package/src/ui/SessionPicker.js +102 -0
  436. package/src/ui/StatusLine.js +13 -4
  437. package/src/ui/WorkspacePicker.js +55 -0
  438. package/src/ui/figures.js +44 -0
  439. package/src/ui/hooks/askSlot.js +82 -0
  440. package/src/ui/hooks/useChat.js +358 -64
  441. package/src/ui/hooks/usePasteHandler.js +11 -1
  442. package/src/ui/hooks/useTextBuffer.js +1 -3
  443. package/src/ui/liveViewport.js +5 -1
  444. package/src/ui/markdown.js +206 -0
  445. package/src/ui/textBuffer.js +0 -7
  446. package/src/ui/theme.js +32 -0
  447. package/src/utils/debugLog.js +0 -4
  448. package/src/utils/resourcePaths.js +2 -2
  449. package/src/utils/stripThink.js +50 -0
  450. package/src/web/browserBridge.js +447 -0
  451. package/src/web/protocol.js +19 -0
  452. package/workflows/adaptive-research.yaml +13 -5
  453. package/workflows/book-review-short.yaml +36 -10
  454. package/workflows/e2e-write-greet.yaml +6 -2
  455. package/workflows/illustrate.yaml +227 -0
  456. package/workflows/plan.yaml +460 -179
  457. package/workflows/ppt.yaml +1659 -0
  458. package/workflows/ralph-loop.yaml +199 -0
  459. package/workflows/schema.json +81 -23
  460. package/workflows/webppt.yaml +496 -0
  461. package/workflows/word.yaml +710 -0
  462. package/workflows/youtube-shorts.yaml +46 -15
  463. package/MINIMAL-TRACE.md +0 -77
  464. package/plugins/HOW-TO-WRITE-A-PLUGIN.md +0 -186
  465. package/plugins/ralph-wiggum/.claude-plugin/plugin.json +0 -9
  466. package/plugins/ralph-wiggum/README.md +0 -197
  467. package/plugins/ralph-wiggum/commands/cancel-ralph.md +0 -18
  468. package/plugins/ralph-wiggum/commands/help.md +0 -137
  469. package/plugins/ralph-wiggum/commands/ralph-loop.md +0 -85
  470. package/plugins/ralph-wiggum/hooks/hooks.json +0 -15
  471. package/plugins/ralph-wiggum/hooks/stop-hook.sh +0 -191
  472. package/plugins/ralph-wiggum/plugin.js +0 -280
  473. package/plugins/ralph-wiggum/src/goalState.js +0 -258
  474. package/plugins/ralph-wiggum/src/sentinels.js +0 -76
  475. package/plugins/ralph-wiggum/src/stopHookRunner.js +0 -104
  476. package/plugins/ralph-wiggum/src/verificationGate.js +0 -202
  477. package/plugins/workflow-runner/src/miniReAct.js +0 -223
  478. package/plugins/workflow-runner/src/voteHelpers.js +0 -110
  479. package/skills/config/SKILL.md +0 -123
  480. package/skills/frontend-design/LICENSE.txt +0 -177
  481. package/skills/frontend-design/SKILL.md +0 -42
  482. package/src/ui/ProgressPanel.js +0 -54
  483. package/src/ui/StreamingBlock.js +0 -11
  484. package/src/ui/ToolStatus.js +0 -11
@@ -13,18 +13,37 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  * 每题选项列表末尾自动追加一个「✏️ 其他(自由输入)」伪选项,命中即切到文本
14
14
  * 输入子模式,让用户填选项之外的答案(自由输入按单值处理,覆盖多选集合)。
15
15
  *
16
- * Ink 用法与风格对齐 cli/configWizard.tsx:useInput 手写键位、↑↓ 取模移动
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 = questions[questionIndex];
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 >= questions.length) {
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: "gray", children: "\uFF08\u65E0\u95EE\u9898\uFF09" }) }));
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}/${questions.length}) · ${current.header}`;
170
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "cyan", bold: true, children: progress }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: current.question }) }), textMode ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "gray", 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: "gray", children: "\u8F93\u5165\u540E Enter \u63D0\u4EA4 \u00B7 ESC \u8FD4\u56DE" })] })) : (_jsxs(Box, { flexDirection: "column", children: [options.map((opt, i) => {
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 ? 'cyan' : undefined, children: [active ? '> ' : ' ', box, opt.label] }), opt.description ? (_jsxs(Text, { color: "gray", children: [' ', clampDesc(opt.description)] })) : null] }, `${i}-${opt.label}`));
174
- }), _jsxs(Text, { color: idx === otherIndex ? 'cyan' : undefined, children: [idx === otherIndex ? '> ' : ' ', multi ? ' ' : '', "\u270F\uFE0F \u5176\u4ED6\uFF08\u81EA\u7531\u8F93\u5165\uFF09"] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: multi
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
  }
@@ -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
- function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
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 + 非 disabled)----
187
+ // ---- ✅ Ctrl+R 进入反向搜索(仅在空 buf)----
124
188
  if (key.ctrl && input === 'r') {
125
- if (!disabled && buf.state.text.length === 0) {
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: "magenta", bold: true, children: '(reverse-i-search)`' }), _jsx(Text, { color: "yellow", children: query }), _jsx(Text, { color: "magenta", bold: true, children: "': " }), _jsx(Text, { color: hitFirstLine === null ? 'gray' : 'white', children: hitDisplay })] }), _jsx(Box, { children: _jsx(Text, { color: "gray", dimColor: true, children: "Enter \u63D0\u4EA4 \u00B7 ESC \u53D6\u6D88 \u00B7 Backspace \u5220\u5B57\u7B26" }) })] }));
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 ? 'gray' : 'cyan';
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 && !disabled;
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 }) : _jsx(Text, { children: line || ' ' })] }, row));
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
  /** 光标行渲染(稳定,不会被重建) */
@@ -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 = 8;
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
- if (t.argsFriendly && t.argsFriendly.length > 0)
57
- return t.argsFriendly;
58
- const a = t.argsPreview.length > TOOL_ARGS_MAX
59
- ? `${t.argsPreview.slice(0, TOOL_ARGS_MAX - 1)}…`
60
- : t.argsPreview;
61
- return `${t.toolName}(${a})`;
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 返回 null。导出供单测断言 INV-1(每行宽)/ INV-2(行数)/ 颜色层次。
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
- status += ` · [plugin:${pluginProgress.pluginId}] ${pluginProgress.current}/${pluginProgress.max ?? '?'}${pluginProgress.message ? ` ${pluginProgress.message}` : ''}`;
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 ? `💭 ${line}` : ` ${line}`);
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
- contentLines = lastN(runningTools, maxLines).map((t) => clampWidthStart(` ${toolDesc(t)}`, maxWidth));
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' ? 'magenta' : 'cyan',
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
- if (progressStage === 'idle')
122
- return null;
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 ? 'gray' : undefined, dimColor: view.contentDim, wrap: "truncate", children: line.length > 0 ? line : ' ' }, `live-${i}`)))] }));
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
  });