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
package/src/cli/args.js CHANGED
@@ -31,6 +31,17 @@ export function extractFlagValue(args, names) {
31
31
  }
32
32
  return undefined;
33
33
  }
34
+ /** 提取可重复带值标志,例如 `--image a.png --image b.png`。 */
35
+ export function extractFlagValues(args, names) {
36
+ const values = [];
37
+ for (let i = 0; i < args.length; i++) {
38
+ if (names.includes(args[i]) && args[i + 1] !== undefined) {
39
+ values.push(args[i + 1]);
40
+ i++;
41
+ }
42
+ }
43
+ return values;
44
+ }
34
45
  /**
35
46
  * CLI 布尔标志(出现即生效、不带值)。集中定义一份,供 print.ts 的 extractPromptArgs
36
47
  * 共用 —— 避免 flag 列表在多处各维护一份、新增 flag 时漏改导致「flag 值被当 prompt 污染」。
@@ -44,9 +55,9 @@ export const BOOLEAN_FLAGS = new Set([
44
55
  '--help',
45
56
  '-V',
46
57
  '--version',
47
- // stream-json 控制位(webchat broker / 网关用);出现即生效、不带值。
48
58
  '--clear',
49
59
  '--compact',
60
+ '--workspace-doctor',
50
61
  ]);
51
62
  /**
52
63
  * CLI 带值标志(标志本身 + 紧跟的下一个元素都不是位置参数)。
@@ -55,6 +66,11 @@ export const BOOLEAN_FLAGS = new Set([
55
66
  export const VALUE_FLAGS = new Set([
56
67
  '-d',
57
68
  '--cwd',
69
+ '-s',
70
+ '--session',
58
71
  '--output-format',
59
72
  '--max-turns',
73
+ '--image',
74
+ '--image-detail',
75
+ '--image-max-long-side-pixel',
60
76
  ]);
@@ -0,0 +1,236 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * ============================================================
4
+ * src/cli/configMenu.tsx —— 配置主菜单(菜单 + 分段向导 的入口)
5
+ * ------------------------------------------------------------
6
+ * 取代旧版一条线走到底的 configWizard.tsx。展示 6 个配置分区 + "完成
7
+ * 退出",每项状态从 ConfigService 实时读取;选中一项进入对应子向导,
8
+ * 子向导做完(成功或 ESC 取消)都回到本菜单。
9
+ *
10
+ * 两种模式:
11
+ * - mode="first-run":Root.tsx 在没有 provider 时渲染。基座模型未
12
+ * 配置时"完成退出"会被拦下(应用没有 provider 跑不起来);ESC/
13
+ * Ctrl+C 在菜单层直接退出整个进程——已完成的子项各自都是即时
14
+ * savePatch 落盘的,不会因为中途退出而丢失(相对旧版"一条线走到
15
+ * 底、中途退出等于全部作废"是个改进)。
16
+ * - mode="reconfigure":App.tsx 的 /config 命令挂载。随时可"完成
17
+ * 退出"关闭覆盖层回到聊天;ESC/Ctrl+C 在菜单层等价于"完成退出"。
18
+ *
19
+ * 模型管理:支持添加多个模型、编辑已有模型、设置基座模型(通过向导完成);
20
+ * 运行时切换基座模型使用 /model 命令、切换顾问模型使用 /advisor select,
21
+ * 无需重启会话即可生效。顾问/搜索/生图/语音/OpenRouter 改动下一次工具
22
+ * 调用即可读到新值(ConfigService.advisor()/tool() 每次都 fresh reload,
23
+ * 不缓存)。
24
+ * ============================================================
25
+ */
26
+ import { useCallback, useEffect, useState } from 'react';
27
+ import { Box, Text, useApp, useInput } from 'ink';
28
+ import { configService } from '../config/configService.js';
29
+ import { AdvisorWizard } from './wizards/advisorWizard.js';
30
+ import { ImageWizard } from './wizards/imageWizard.js';
31
+ import { OpenRouterWizard } from './wizards/openRouterWizard.js';
32
+ import { ProviderWizard } from './wizards/providerWizard.js';
33
+ import { SearchWizard } from './wizards/searchWizard.js';
34
+ import { TtsWizard } from './wizards/ttsWizard.js';
35
+ const ITEMS = [
36
+ {
37
+ screen: 'provider',
38
+ label: '添加/编辑模型',
39
+ status: (s) => {
40
+ const count = s.models.length;
41
+ const enabled = s.models.filter((m) => m.enabled && m.apiKey).length;
42
+ if (count === 0)
43
+ return '尚未添加模型';
44
+ return `共 ${count} 个模型(${enabled} 个可用)· 基座:${s.provider ? `${s.provider.name}/${s.provider.model}` : '未设置'}`;
45
+ },
46
+ },
47
+ {
48
+ screen: 'search',
49
+ label: '配置搜索引擎',
50
+ status: (s) => (s.webSearch ? '已配置' : '未配置'),
51
+ },
52
+ {
53
+ screen: 'image',
54
+ label: '配置生图模型',
55
+ status: (s) => s.imageGeneration ? `已配置 ${s.imageGeneration.provider}/${s.imageGeneration.model}` : '未配置',
56
+ },
57
+ {
58
+ screen: 'advisor',
59
+ label: '配置顾问模型',
60
+ status: (s) => s.advisor
61
+ ? `已配置 ${s.advisor.provider.name}/${s.advisor.provider.model}(${s.advisor.enabled ? '已启用' : '已关闭'})`
62
+ : '未配置',
63
+ },
64
+ {
65
+ screen: 'tts',
66
+ label: '配置语音合成',
67
+ status: (s) => (s.textToSpeech ? '已配置' : '未配置'),
68
+ },
69
+ {
70
+ screen: 'openrouter',
71
+ label: '配置 OpenRouter',
72
+ status: (s) => (s.openRouter ? '已配置' : '未配置'),
73
+ },
74
+ ];
75
+ export function ConfigMenu({ mode, onDone }) {
76
+ const { exit } = useApp();
77
+ const [screen, setScreen] = useState('menu');
78
+ const [snapshot, setSnapshot] = useState(null);
79
+ const [menuIndex, setMenuIndex] = useState(0);
80
+ const [blockedMsg, setBlockedMsg] = useState(null);
81
+ const [editingModelId, setEditingModelId] = useState(null);
82
+ const [modelListIndex, setModelListIndex] = useState(0);
83
+ const refresh = useCallback(async () => {
84
+ const [provider, advisor, webSearch, imageGeneration, textToSpeech, openRouter, config, models] = await Promise.all([
85
+ configService.provider(),
86
+ configService.advisor(),
87
+ configService.tool('webSearch'),
88
+ configService.tool('imageGeneration'),
89
+ configService.tool('textToSpeech'),
90
+ configService.tool('openRouter'),
91
+ configService.getSnapshot(),
92
+ configService.models(),
93
+ ]);
94
+ setSnapshot({ provider, baseModelId: config.config?.baseModelId ?? null, advisor, models, webSearch, imageGeneration, textToSpeech, openRouter });
95
+ }, []);
96
+ useEffect(() => {
97
+ void refresh();
98
+ }, [refresh]);
99
+ const backToMenu = useCallback(() => {
100
+ setScreen('menu');
101
+ setEditingModelId(null);
102
+ void refresh();
103
+ }, [refresh]);
104
+ const backToModelList = useCallback(() => {
105
+ setScreen('provider-list');
106
+ setEditingModelId(null);
107
+ void refresh();
108
+ }, [refresh]);
109
+ useInput((input, key) => {
110
+ if (screen === 'provider-list' && snapshot) {
111
+ const models = snapshot.models;
112
+ const listLen = models.length + 1; // +1 for "添加新模型"
113
+ if (key.escape || (key.ctrl && input === 'c')) {
114
+ setScreen('menu');
115
+ return;
116
+ }
117
+ if (key.upArrow) {
118
+ setModelListIndex((i) => (i - 1 + listLen) % listLen);
119
+ return;
120
+ }
121
+ if (key.downArrow) {
122
+ setModelListIndex((i) => (i + 1) % listLen);
123
+ return;
124
+ }
125
+ if (key.return) {
126
+ if (modelListIndex === models.length) {
127
+ // 添加新模型
128
+ setEditingModelId(null);
129
+ setScreen('provider');
130
+ }
131
+ else {
132
+ const selected = models[modelListIndex];
133
+ if (selected) {
134
+ setEditingModelId(selected.id);
135
+ setScreen('provider');
136
+ }
137
+ }
138
+ return;
139
+ }
140
+ return;
141
+ }
142
+ if (screen !== 'menu')
143
+ return;
144
+ if (key.escape || (key.ctrl && input === 'c')) {
145
+ if (mode === 'first-run')
146
+ exit();
147
+ else
148
+ onDone();
149
+ return;
150
+ }
151
+ if (key.upArrow) {
152
+ setMenuIndex((i) => (i - 1 + ITEMS.length + 1) % (ITEMS.length + 1));
153
+ setBlockedMsg(null);
154
+ return;
155
+ }
156
+ if (key.downArrow) {
157
+ setMenuIndex((i) => (i + 1) % (ITEMS.length + 1));
158
+ setBlockedMsg(null);
159
+ return;
160
+ }
161
+ if (key.return) {
162
+ if (menuIndex === ITEMS.length) {
163
+ // "完成退出"
164
+ if (mode === 'first-run' && !snapshot?.provider) {
165
+ setBlockedMsg('请先添加模型并设置基座模型再退出——应用没有基座模型无法运行。');
166
+ return;
167
+ }
168
+ if (mode === 'first-run') {
169
+ void configService.provider().then((p) => onDone(p ?? undefined));
170
+ }
171
+ else {
172
+ onDone();
173
+ }
174
+ return;
175
+ }
176
+ setBlockedMsg(null);
177
+ const targetScreen = ITEMS[menuIndex].screen;
178
+ if (targetScreen === 'provider') {
179
+ // 模型管理:有模型则显示列表供选择编辑,无模型直接进添加向导
180
+ if (snapshot && snapshot.models.length > 0) {
181
+ setModelListIndex(0);
182
+ setScreen('provider-list');
183
+ }
184
+ else {
185
+ setEditingModelId(null);
186
+ setScreen('provider');
187
+ }
188
+ }
189
+ else {
190
+ setScreen(targetScreen);
191
+ }
192
+ }
193
+ });
194
+ if (!snapshot) {
195
+ return (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "gray", children: "\u6B63\u5728\u8BFB\u53D6\u914D\u7F6E..." }) }));
196
+ }
197
+ if (screen === 'provider-list' && snapshot) {
198
+ const models = snapshot.models;
199
+ const formatLabel = (f) => f === 'anthropic' ? 'Anthropic' : f === 'openai' ? 'OpenAI兼容' : f;
200
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "cyan", bold: true, children: "\u6A21\u578B\u7BA1\u7406" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "gray", children: "\u2191\u2193 \u9009\u62E9 \u00B7 Enter \u7F16\u8F91/\u6DFB\u52A0 \u00B7 ESC \u8FD4\u56DE\u83DC\u5355" }) }), _jsxs(Box, { flexDirection: "column", children: [models.map((m, i) => (_jsxs(Text, { color: i === modelListIndex ? 'cyan' : undefined, children: [i === modelListIndex ? '> ' : ' ', m.id === snapshot.baseModelId ? '★ ' : ' ', m.displayName || m.model, " ", _jsxs(Text, { color: "gray", children: ["(", formatLabel(m.apiFormat), "/", m.model, !m.enabled ? ' · 已禁用' : !m.apiKey ? ' · 未配置密钥' : '', ")"] })] }, m.id))), _jsxs(Text, { color: modelListIndex === models.length ? 'cyan' : undefined, children: [modelListIndex === models.length ? '> ' : ' ', "\uFF0B \u6DFB\u52A0\u65B0\u6A21\u578B"] })] }), snapshot.baseModelId && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "\u2605 = \u5F53\u524D\u57FA\u5EA7\u6A21\u578B\uFF08\u804A\u5929\u4E2D\u53EF\u7528 /model \u5B9E\u65F6\u5207\u6362\uFF09" }) }))] }));
201
+ }
202
+ if (screen === 'provider') {
203
+ // 根据 editingModelId 决定编辑哪个模型;null = 添加新模型
204
+ const editingModel = editingModelId
205
+ ? snapshot?.models.find((m) => m.id === editingModelId)
206
+ : undefined;
207
+ // 首次配置模式(无基座)时添加新模型自动设为基座;
208
+ // 从模型列表添加额外模型时不自动替换基座(用户可用 /model 切换)
209
+ const shouldSetAsBase = mode === 'first-run' || !snapshot?.baseModelId;
210
+ return (_jsx(ProviderWizard, { existing: editingModel
211
+ ? {
212
+ id: editingModel.id,
213
+ name: editingModel.displayName ?? editingModel.model,
214
+ baseURL: editingModel.baseURL,
215
+ apiKey: editingModel.apiKey,
216
+ model: editingModel.model,
217
+ }
218
+ : null, setAsBase: shouldSetAsBase, onDone: snapshot && snapshot.models.length > 0 ? backToModelList : backToMenu, onCancel: snapshot && snapshot.models.length > 0 ? backToModelList : backToMenu }));
219
+ }
220
+ if (screen === 'search') {
221
+ return _jsx(SearchWizard, { existing: snapshot.webSearch ?? null, onDone: backToMenu, onCancel: backToMenu });
222
+ }
223
+ if (screen === 'image') {
224
+ return _jsx(ImageWizard, { existing: snapshot.imageGeneration ?? null, onDone: backToMenu, onCancel: backToMenu });
225
+ }
226
+ if (screen === 'advisor') {
227
+ return _jsx(AdvisorWizard, { existing: snapshot.advisor ?? null, models: snapshot.models, onDone: backToMenu, onCancel: backToMenu });
228
+ }
229
+ if (screen === 'tts') {
230
+ return _jsx(TtsWizard, { existing: snapshot.textToSpeech ?? null, onDone: backToMenu, onCancel: backToMenu });
231
+ }
232
+ if (screen === 'openrouter') {
233
+ return _jsx(OpenRouterWizard, { existing: snapshot.openRouter ?? null, onDone: backToMenu, onCancel: backToMenu });
234
+ }
235
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "cyan", bold: true, children: ["minimal-agent \u00B7 ", mode === 'first-run' ? '首次配置菜单' : '配置菜单'] }) }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "gray", children: ["\u2191\u2193 \u9009\u62E9 \u00B7 Enter \u8FDB\u5165/\u786E\u8BA4 \u00B7 ESC ", mode === 'first-run' ? '退出程序' : '关闭菜单'] }) }), _jsxs(Box, { flexDirection: "column", children: [ITEMS.map((item, i) => (_jsxs(Text, { color: i === menuIndex ? 'cyan' : undefined, children: [i === menuIndex ? '> ' : ' ', i + 1, ". ", item.label, " ", _jsxs(Text, { color: "gray", children: ["[", item.status(snapshot), "]"] })] }, item.screen))), _jsxs(Text, { color: menuIndex === ITEMS.length ? 'cyan' : undefined, children: [menuIndex === ITEMS.length ? '> ' : ' ', ITEMS.length + 1, ". \u5B8C\u6210\u9000\u51FA"] })] }), blockedMsg && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "red", children: ["\u2717 ", blockedMsg] }) }))] }));
236
+ }
@@ -26,6 +26,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
26
26
  import { useCallback, useMemo, useState } from 'react';
27
27
  import { Box, Text, useApp, useInput } from 'ink';
28
28
  import { saveConfig } from '../config/configFile.js';
29
+ import { configService } from '../config/configService.js';
29
30
  // 兜底值:custom 或表外 model 都退到这里。
30
31
  // 与 src/config.ts 的同名常量含义对齐("既没 env、saved 也没填 contextWindow" 的最终兜底)。
31
32
  const FALLBACK_CONTEXT_WINDOW = 128_000;
@@ -34,7 +35,7 @@ const PRESETS = [
34
35
  name: 'minimax',
35
36
  label: 'MiniMax (海螺)',
36
37
  baseURL: 'https://api.minimax.chat/v1',
37
- models: ['MiniMax-M2.7', 'MiniMax-M1', 'abab6.5s-chat'],
38
+ models: ['MiniMax-M3', 'MiniMax-M2.7', 'MiniMax-M1', 'abab6.5s-chat'],
38
39
  contextWindow: 204_800,
39
40
  },
40
41
  {
@@ -52,9 +53,13 @@ const PRESETS = [
52
53
  'glm-5.1',
53
54
  'minimax-latest',
54
55
  'deepseek-v3.2',
56
+ 'kimi-k2.7-code',
55
57
  'kimi-k2.6',
56
58
  ],
57
59
  contextWindow: 204_800,
60
+ modelContextWindows: {
61
+ 'kimi-k2.7-code': 512_000,
62
+ },
58
63
  },
59
64
  {
60
65
  name: 'deepseek',
@@ -175,10 +180,7 @@ export function ConfigWizard({ onSuccess }) {
175
180
  contextWindow,
176
181
  tavilyApiKey,
177
182
  });
178
- // 立刻注入当前进程 env,让本会话内的 WebSearch 不必重启就能用
179
- if (tavilyApiKey) {
180
- process.env.TAVILY_API_KEY = tavilyApiKey;
181
- }
183
+ await configService.reload();
182
184
  onSuccess({
183
185
  name: preset.name,
184
186
  baseURL,
package/src/cli/print.js CHANGED
@@ -23,8 +23,10 @@
23
23
  * ============================================================
24
24
  */
25
25
  import { getContextPath, saveContext } from '../context/persistContext.js';
26
+ import { updateSessionMetadata } from '../context/sessionRegistry.js';
27
+ import { normalizeImageDetail } from '../multimodal.js';
26
28
  import { runWithPlugins } from '../plugins/pluginRunner.js';
27
- import { BOOLEAN_FLAGS, VALUE_FLAGS } from './args.js';
29
+ import { BOOLEAN_FLAGS, VALUE_FLAGS, extractFlagValue, extractFlagValues, } from './args.js';
28
30
  /** stderr 显示工具结果时的截断阈值;超过即末尾加 "..." */
29
31
  const TOOL_OUTPUT_PREVIEW_MAX = 200;
30
32
  /** stdin 读取超时(ms),防止非 TTY + 无管道时永久挂起 */
@@ -64,6 +66,21 @@ export function extractPromptArgs(args) {
64
66
  }
65
67
  return result;
66
68
  }
69
+ export function extractImageOptions(args) {
70
+ const imageDetail = normalizeImageDetail(extractFlagValue(args, ['--image-detail']));
71
+ const rawMaxLongSide = extractFlagValue(args, [
72
+ '--image-max-long-side-pixel',
73
+ ]);
74
+ const imageMaxLongSidePixel = rawMaxLongSide !== undefined && Number.isFinite(Number(rawMaxLongSide))
75
+ ? Math.floor(Number(rawMaxLongSide))
76
+ : undefined;
77
+ const imageInputs = extractFlagValues(args, ['--image']).map((source) => ({
78
+ source,
79
+ detail: imageDetail,
80
+ maxLongSidePixel: imageMaxLongSidePixel,
81
+ }));
82
+ return { imageInputs, imageDetail, imageMaxLongSidePixel };
83
+ }
67
84
  /**
68
85
  * 输出 `-p --output-format json` 的结局契约(**一行** JSON 到 stdout)。
69
86
  *
@@ -100,8 +117,13 @@ export function emitJsonResult(result, sessionFile) {
100
117
  /**
101
118
  * 尝试拿当前会话落盘路径(给 json 契约的 session_file 字段)。
102
119
  * 取不到(异常等)返回 undefined,emitJsonResult 据此省略该键(契约允许)。
120
+ *
121
+ * override 有值时直接用它(`--session` 解析出的路径)——不重新调用无参的
122
+ * getContextPath(),否则会跟真正读写的文件不一致。
103
123
  */
104
- function trySessionFile() {
124
+ function trySessionFile(override) {
125
+ if (override)
126
+ return override;
105
127
  try {
106
128
  return getContextPath();
107
129
  }
@@ -121,6 +143,7 @@ export async function runPrintMode(provider, args, initialHistory, options) {
121
143
  process.stderr.on('error', handleEPIPE(process.stderr));
122
144
  const outputFormat = options.outputFormat ?? 'text';
123
145
  const isJson = outputFormat === 'json';
146
+ const imageOptions = extractImageOptions(args);
124
147
  const promptArgs = extractPromptArgs(args);
125
148
  let prompt;
126
149
  if (promptArgs.length > 0) {
@@ -137,6 +160,11 @@ export async function runPrintMode(provider, args, initialHistory, options) {
137
160
  console.error('错误: 提示不能为空');
138
161
  process.exit(1);
139
162
  }
163
+ if (options.workspace) {
164
+ await updateSessionMetadata(options.workspace.cwd, options.workspace.sessionId, {
165
+ lastMessagePreview: prompt.trim(),
166
+ }).catch(() => { });
167
+ }
140
168
  const abortController = new AbortController();
141
169
  let interrupted = false;
142
170
  const history = initialHistory;
@@ -158,9 +186,9 @@ export async function runPrintMode(provider, args, initialHistory, options) {
158
186
  function finalizeOnce() {
159
187
  if (!finalizePromise) {
160
188
  finalizePromise = (async () => {
161
- await saveContext(history);
189
+ await saveContext(history, options.sessionFile);
162
190
  if (isJson)
163
- emitJsonResult(result, trySessionFile());
191
+ emitJsonResult(result, trySessionFile(options.sessionFile));
164
192
  })();
165
193
  }
166
194
  return finalizePromise;
@@ -182,6 +210,10 @@ export async function runPrintMode(provider, args, initialHistory, options) {
182
210
  history,
183
211
  signal: abortController.signal,
184
212
  maxTurns: options.maxTurns,
213
+ imageInputs: imageOptions.imageInputs,
214
+ parseInlineImages: true,
215
+ imageDetail: imageOptions.imageDetail,
216
+ imageMaxLongSidePixel: imageOptions.imageMaxLongSidePixel,
185
217
  })) {
186
218
  // event 是 LoopEvent | PluginEvent;handleEvent 只认 LoopEvent,未识别的插件私有事件走 default 静默忽略
187
219
  const handled = handleEvent(event, result, options.verbose, outputFormat);
@@ -295,6 +327,7 @@ export function handleEvent(event, result, verbose, outputFormat = 'text') {
295
327
  case 'plugin_progress':
296
328
  case 'reasoning':
297
329
  case 'stage_change':
330
+ case 'context_usage':
298
331
  return {};
299
332
  default:
300
333
  // 落到这里 = 插件私有事件(PluginEvent,type 任意字符串)。正常静默忽略;
@@ -22,10 +22,12 @@ import crypto from 'node:crypto';
22
22
  import { getWorkingDir } from '../bootstrap/workingDir.js';
23
23
  import { forceCompact } from '../context/compact.js';
24
24
  import { recordRecentDir } from '../context/recentDirs.js';
25
+ import { updateSessionMetadata } from '../context/sessionRegistry.js';
25
26
  import { saveContext } from '../context/persistContext.js';
26
27
  import { setAskHandler } from '../askBridge.js';
28
+ import { normalizeImageDetail } from '../multimodal.js';
27
29
  import { runWithPlugins } from '../plugins/pluginRunner.js';
28
- import { extractPromptArgs } from './print.js';
30
+ import { extractImageOptions, extractPromptArgs } from './print.js';
29
31
  /** 一行一个 JSON 事件写 stdout。EPIPE 时静默。 */
30
32
  function emitLine(ev) {
31
33
  try {
@@ -37,7 +39,40 @@ function emitLine(ev) {
37
39
  }
38
40
  function firstUserTitle(history) {
39
41
  const u = history.find((m) => m.role === 'user');
40
- return u && typeof u.content === 'string' ? u.content : undefined;
42
+ if (!u)
43
+ return undefined;
44
+ if (typeof u.content === 'string')
45
+ return u.content;
46
+ return u.content.find((p) => p.type === 'text')?.text;
47
+ }
48
+ function parseWireImages(raw) {
49
+ if (!Array.isArray(raw))
50
+ return [];
51
+ const out = [];
52
+ for (const item of raw) {
53
+ if (typeof item === 'string') {
54
+ out.push({ source: item });
55
+ continue;
56
+ }
57
+ if (!item || typeof item !== 'object')
58
+ continue;
59
+ const source = typeof item.source === 'string'
60
+ ? item.source
61
+ : typeof item.url === 'string'
62
+ ? item.url
63
+ : undefined;
64
+ if (!source)
65
+ continue;
66
+ const detail = typeof item.detail === 'string'
67
+ ? normalizeImageDetail(item.detail)
68
+ : undefined;
69
+ const rawMax = item.maxLongSidePixel ?? item.max_long_side_pixel;
70
+ const maxLongSidePixel = typeof rawMax === 'number' && Number.isFinite(rawMax)
71
+ ? Math.floor(rawMax)
72
+ : undefined;
73
+ out.push({ source, detail, maxLongSidePixel });
74
+ }
75
+ return out;
41
76
  }
42
77
  /**
43
78
  * stdin 控制通道:把 stdin 从「一次性裸 prompt」升级为**逐行 JSON 控制通道**,
@@ -59,11 +94,13 @@ export function attachStdinChannel(opts) {
59
94
  const input = opts.input ?? process.stdin;
60
95
  return new Promise((resolvePrompt) => {
61
96
  let promptResolved = false;
62
- const resolveOnce = (text, control) => {
97
+ const resolveOnce = (text, control, imageInputs) => {
63
98
  if (promptResolved)
64
99
  return;
65
100
  promptResolved = true;
66
- resolvePrompt({ prompt: text, control });
101
+ resolvePrompt(imageInputs && imageInputs.length > 0
102
+ ? { prompt: text, control, imageInputs }
103
+ : { prompt: text, control });
67
104
  };
68
105
  // argv 给的 prompt:直连 CLI、无控制通道(broker 走 stdin 的 {type:'prompt'},不用 argv)。
69
106
  if (opts.argvPrompt !== undefined)
@@ -95,7 +132,7 @@ export function attachStdinChannel(opts) {
95
132
  }
96
133
  if (!promptResolved) {
97
134
  if (msg && msg.type === 'prompt' && typeof msg.text === 'string') {
98
- resolveOnce(msg.text, true); // 控制行 → 存在控制通道(broker 会回灌 ask_answer)
135
+ resolveOnce(msg.text, true, parseWireImages(msg.images)); // 控制行 → 存在控制通道
99
136
  }
100
137
  else {
101
138
  // 首行不是 prompt 控制消息 → legacy:把它放回去,整段当裸 prompt 读到 EOF
@@ -122,23 +159,27 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
122
159
  process.stdout.destroy();
123
160
  });
124
161
  const history = initialHistory;
125
- let finalized = false;
126
- const finalize = async () => {
127
- if (finalized)
128
- return;
129
- finalized = true;
130
- // 释放 stdin:attachStdinChannel 的 'data' 监听会让进程在本轮结束后**仍存活**
131
- // (等下一行输入)→ broker 永远收不到子进程 close、web 端 conn.running 卡死。
132
- // turn 已结束(无挂起提问),unref 让 stdout 排空后进程自然退出;中途挂起期间
133
- // 不会走到这里,故等答案时进程仍被 stdin 监听保活。
134
- try {
135
- process.stdin.unref();
136
- }
137
- catch {
138
- /* 某些 stdin 类型无 unref,忽略 */
139
- }
140
- setAskHandler(null); // 注销 handler,避免全局污染(测试复用 / 同进程多次调用)
141
- await saveContext(history);
162
+ // 收尾守卫用「缓存 promise」而非「布尔 once」(与 print.ts finalizeOnce 同构):
163
+ // SIGINT handler 与 for-await 的 AbortError catch 是两条并发退出路径,布尔 once
164
+ // 会让后到的路径立即返回、抢在 saveContext 落盘完成前 process.exit → 会话丢失。
165
+ // 缓存 promise 让所有路径 await 同一次真实收尾。
166
+ let finalizePromise = null;
167
+ const finalize = () => {
168
+ finalizePromise ??= (async () => {
169
+ // 释放 stdin:attachStdinChannel 的 'data' 监听会让进程在本轮结束后**仍存活**
170
+ // (等下一行输入)→ broker 永远收不到子进程 close、web 端 conn.running 卡死。
171
+ // turn 已结束(无挂起提问),unref 让 stdout 排空后进程自然退出;中途挂起期间
172
+ // 不会走到这里,故等答案时进程仍被 stdin 监听保活。
173
+ try {
174
+ process.stdin.unref();
175
+ }
176
+ catch {
177
+ /* 某些 stdin 类型无 unref,忽略 */
178
+ }
179
+ setAskHandler(null); // 注销 handler,避免全局污染(测试复用 / 同进程多次调用)
180
+ await saveContext(history, options.sessionFile);
181
+ })();
182
+ return finalizePromise;
142
183
  };
143
184
  // --- 压缩动作(/compact):不需要 prompt ---
144
185
  if (options.compact) {
@@ -165,7 +206,8 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
165
206
  pendingAsks.clear();
166
207
  };
167
208
  const promptArgs = extractPromptArgs(args);
168
- const { prompt, control } = await attachStdinChannel({
209
+ const cliImageOptions = extractImageOptions(args);
210
+ const { prompt, control, imageInputs: stdinImageInputs } = await attachStdinChannel({
169
211
  argvPrompt: promptArgs.length > 0 ? promptArgs.join(' ') : undefined,
170
212
  onAskAnswer: (requestId, answers) => {
171
213
  const p = pendingAsks.get(requestId);
@@ -192,6 +234,11 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
192
234
  }
193
235
  // 记录最近目录(侧栏用);title 优先用历史里第一条用户消息(稳定),否则用当前 prompt
194
236
  await recordRecentDir(getWorkingDir(), firstUserTitle(history) ?? prompt);
237
+ if (options.workspace) {
238
+ await updateSessionMetadata(options.workspace.cwd, options.workspace.sessionId, {
239
+ lastMessagePreview: prompt,
240
+ }).catch(() => { });
241
+ }
195
242
  const abortController = new AbortController();
196
243
  let interrupted = false;
197
244
  process.on('SIGINT', () => {
@@ -209,6 +256,10 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
209
256
  history,
210
257
  signal: abortController.signal,
211
258
  maxTurns: options.maxTurns,
259
+ imageInputs: [...cliImageOptions.imageInputs, ...(stdinImageInputs ?? [])],
260
+ parseInlineImages: true,
261
+ imageDetail: cliImageOptions.imageDetail,
262
+ imageMaxLongSidePixel: cliImageOptions.imageMaxLongSidePixel,
212
263
  })) {
213
264
  // event 是 LoopEvent | PluginEvent,原样逐行 emit;前端不识别的插件私有事件会静默忽略
214
265
  emitLine(event);
@@ -216,7 +267,9 @@ export async function runStreamJsonMode(provider, args, initialHistory, options)
216
267
  }
217
268
  catch (e) {
218
269
  if (e.name === 'AbortError') {
219
- emitLine({ type: 'interrupted' });
270
+ // SIGINT 路径已 emit 过 interrupted → 不重发(stdout jsonl 语义:一次中断一行)
271
+ if (!interrupted)
272
+ emitLine({ type: 'interrupted' });
220
273
  await finalize();
221
274
  process.exit(130);
222
275
  }