minimal-agent 0.8.2 → 0.9.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 (55) hide show
  1. package/README.md +4 -5
  2. package/package.json +1 -1
  3. package/plugins/workflow-runner/plugin.js +1 -0
  4. package/plugins/workflow-runner/src/agentCommon.js +82 -47
  5. package/plugins/workflow-runner/src/expressions.js +48 -2
  6. package/plugins/workflow-runner/src/index.js +1 -0
  7. package/plugins/workflow-runner/src/jsonPayload.js +1 -1
  8. package/plugins/workflow-runner/src/loader.js +70 -8
  9. package/plugins/workflow-runner/src/recovery.js +43 -35
  10. package/plugins/workflow-runner/src/runner.js +143 -34
  11. package/plugins/workflow-runner/src/stepExecutors/agent.js +64 -35
  12. package/plugins/workflow-runner/src/stepExecutors/assert.js +14 -2
  13. package/plugins/workflow-runner/src/stepExecutors/llm.js +48 -107
  14. package/plugins/workflow-runner/src/stepExecutors/skill.js +50 -39
  15. package/plugins/workflow-runner/src/stepExecutors/tool.js +20 -7
  16. package/plugins/workflow-runner/src/stepExecutors/verify.js +11 -3
  17. package/plugins/workflow-runner/src/taskIdentity.js +141 -0
  18. package/plugins/workflow-runner/src/types.js +1 -2
  19. package/plugins/workflow-runner/src/workflowState.js +211 -28
  20. package/skills/adversarial-review/SKILL.md +0 -1
  21. package/skills/pptx/scripts/office/__pycache__/soffice.cpython-314.pyc +0 -0
  22. package/src/askBridge.js +10 -0
  23. package/src/context/archive.js +4 -0
  24. package/src/infra/verification.js +25 -13
  25. package/src/llm/client.js +160 -12
  26. package/src/loop.js +15 -12
  27. package/src/plugins/pluginLoader.js +2 -1
  28. package/src/plugins/pluginRunner.js +9 -21
  29. package/src/prompts/pluginList.js +5 -5
  30. package/src/prompts/promptAssembly.js +3 -38
  31. package/src/prompts/skillList.js +1 -1
  32. package/src/prompts/system.js +0 -1
  33. package/src/ui/AskQuestion.js +20 -3
  34. package/src/ui/InputBox.js +70 -3
  35. package/src/ui/hooks/useChat.js +13 -0
  36. package/workflows/adaptive-research.yaml +4 -3
  37. package/workflows/book-review-short.yaml +5 -3
  38. package/workflows/e2e-write-greet.yaml +3 -2
  39. package/workflows/plan.yaml +219 -168
  40. package/workflows/ralph-loop.yaml +169 -0
  41. package/workflows/youtube-shorts.yaml +8 -5
  42. package/plugins/HOW-TO-WRITE-A-PLUGIN.md +0 -186
  43. package/plugins/ralph-wiggum/.claude-plugin/plugin.json +0 -9
  44. package/plugins/ralph-wiggum/README.md +0 -197
  45. package/plugins/ralph-wiggum/commands/cancel-ralph.md +0 -18
  46. package/plugins/ralph-wiggum/commands/help.md +0 -137
  47. package/plugins/ralph-wiggum/commands/ralph-loop.md +0 -85
  48. package/plugins/ralph-wiggum/hooks/hooks.json +0 -15
  49. package/plugins/ralph-wiggum/hooks/stop-hook.sh +0 -191
  50. package/plugins/ralph-wiggum/plugin.js +0 -280
  51. package/plugins/ralph-wiggum/src/goalState.js +0 -258
  52. package/plugins/ralph-wiggum/src/sentinels.js +0 -76
  53. package/plugins/ralph-wiggum/src/stopHookRunner.js +0 -104
  54. package/plugins/ralph-wiggum/src/verificationGate.js +0 -202
  55. package/plugins/workflow-runner/src/miniReAct.js +0 -223
@@ -21,6 +21,26 @@ 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
+ // ============================================================
25
+ // IME 启发式(中文输入法防护)
26
+ // ------------------------------------------------------------
27
+ // Ink 5.0.1 的 useInput(基于 readline)不暴露 composition event,
28
+ // 无法原生支持 IME 状态机。本启发式做"最小可行"的兜底:
29
+ // 1. 跟踪"短时间内连续插入"——IME 拼音→候选→提交过程中会产生
30
+ // 一连串短间隔字符(pinyin 字母 + 单字 commit)
31
+ // 2. 检测到 burst 后,**短时间窗口内**把 Enter 视为"IME 确认"
32
+ // 而非"提交"(避免候选窗按 Enter 时把半截拼音+候选字提交)
33
+ // 3. 不试图拦截或过滤 IME 字符——那是终端的活,拦了反而破坏
34
+ //
35
+ // 调参依据:微软拼音/搜狗拼音的 commit 节奏典型 < 100ms/char,
36
+ // 而人手打英文 ≥ 200ms/char。500ms idle 视作 IME 结束。
37
+ //
38
+ // 注意:这是 best-effort,**不能 100% 解决 IME 问题**。
39
+ // 终态方案是换掉 Ink 底层走 use-stdin 的 raw mode。
40
+ // ============================================================
41
+ const IME_BURST_GAP_MS = 200; // 字符间隔 < 此值视作 IME 连续输入
42
+ const IME_BURST_MIN_COUNT = 3; // 连续 N 个字符才触发 IME 锁定
43
+ const IME_LOCKOUT_MS = 500; // 触发后禁 Enter 提交的窗口
24
44
  function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
25
45
  const buf = useTextBuffer();
26
46
  const hist = useInputHistory();
@@ -34,6 +54,30 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
34
54
  // ✅ Delete 专用去重:只防止 Windows 双事件,不影响其他键
35
55
  const lastDeleteTime = useRef(0);
36
56
  const DELETE_DEBOUNCE_MS = 20; // 仅 Delete 键用极短防抖
57
+ // ✅ IME 启发式:跟踪字符插入节奏,检测 IME 草稿期间
58
+ // imeBurstRef: { lastAt: 上次插入 ms, count: 当前 burst 内插入数, lastInsertEnd: 上次 IME 锁定结束 ms }
59
+ const imeBurstRef = useRef({
60
+ lastAt: 0,
61
+ count: 0,
62
+ lockoutUntil: 0,
63
+ });
64
+ /** 把"刚插入了非空非控制字符"事件喂给 IME 检测器 */
65
+ const noteTextInsert = useCallback((textLen) => {
66
+ if (textLen <= 0)
67
+ return;
68
+ const now = Date.now();
69
+ const s = imeBurstRef.current;
70
+ if (now - s.lastAt < IME_BURST_GAP_MS) {
71
+ s.count++;
72
+ if (s.count >= IME_BURST_MIN_COUNT) {
73
+ s.lockoutUntil = now + IME_LOCKOUT_MS;
74
+ }
75
+ }
76
+ else {
77
+ s.count = 1;
78
+ }
79
+ s.lastAt = now;
80
+ }, []);
37
81
  const forceRefresh = useCallback(() => {
38
82
  setRefreshCounter((c) => c + 1);
39
83
  }, []);
@@ -116,8 +160,16 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
116
160
  }
117
161
  // ---- ESC ----
118
162
  if (key.escape) {
119
- if (disabled)
120
- onAbort();
163
+ if (disabled) {
164
+ // try/catch 防 onAbort 异常冒泡到 Ink 渲染层(abort handler 多在 useChat 里,
165
+ // 内部若 throw 会黑屏;吞掉仅 stderr 注记)
166
+ try {
167
+ onAbort();
168
+ }
169
+ catch (e) {
170
+ console.error('[InputBox] onAbort threw:', e);
171
+ }
172
+ }
121
173
  return;
122
174
  }
123
175
  // ---- ✅ Ctrl+R 进入反向搜索(仅在空 buf + 非 disabled)----
@@ -135,7 +187,13 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
135
187
  return;
136
188
  }
137
189
  if (disabled) {
138
- onAbort();
190
+ // 同 ESC 路径,try/catch 防 onAbort 异常冒泡到 Ink 渲染层
191
+ try {
192
+ onAbort();
193
+ }
194
+ catch (e) {
195
+ console.error('[InputBox] onAbort threw:', e);
196
+ }
139
197
  return;
140
198
  }
141
199
  ctrlCCountRef.current++;
@@ -152,7 +210,15 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
152
210
  // - Alt+Enter(Mac: Option+Enter):返回 'enter-newline' → 上面已处理为**插入换行**
153
211
  // - Ctrl+Enter:返回 'continue' → 这里也执行**强制发送**
154
212
  // - 粘贴期间 + Enter:返回 'enter-in-paste' → **忽略**(防误发)
213
+ // - IME 草稿期间 + Enter:视为 IME 确认而非提交(启发式,见 IME_BURST_* 常量)
155
214
  if (key.return) {
215
+ const now = Date.now();
216
+ if (now < imeBurstRef.current.lockoutUntil) {
217
+ // IME 候选窗按 Enter → 走换行而非提交(pinyin 候选确认不打断草稿)
218
+ buf.insert('\n');
219
+ forceRefresh();
220
+ return;
221
+ }
156
222
  const text = buf.state.text.trim();
157
223
  if (text.length === 0)
158
224
  return;
@@ -290,6 +356,7 @@ function InputBoxImpl({ onSubmit, disabled, onAbort, onClear, onCompact }) {
290
356
  // (否则 layout 永远 1 行 → ↑/↓ 失效、输入框不长高,光标只能左右)。
291
357
  if (input && !key.meta) {
292
358
  const normalized = input.replace(/\r\n?/g, '\n');
359
+ noteTextInsert(normalized.length);
293
360
  buf.insert(normalized);
294
361
  forceRefresh();
295
362
  }
@@ -274,6 +274,12 @@ export function useChat(args) {
274
274
  const ac = new AbortController();
275
275
  abortRef.current = ac;
276
276
  dlog('ui', 'turn START', { input: trimmed.slice(0, 80) });
277
+ // 长时间运行时(如工作流 agent 步骤)的定时 token 刷新:
278
+ // runQuery 的 text/reasoning 事件不触发 bump,导致 StatusLine token 数
279
+ // 可能冻结数十秒。此定时器每 10s 强制刷新一次,确保用户看到上下文增长。
280
+ const tokenRefreshTimer = setInterval(() => {
281
+ bump();
282
+ }, 10_000);
277
283
  try {
278
284
  for await (const ev of runWithPlugins(trimmed, {
279
285
  provider: args.provider,
@@ -311,6 +317,7 @@ export function useChat(args) {
311
317
  }
312
318
  finally {
313
319
  dlog('ui', 'turn END (finally)');
320
+ clearInterval(tokenRefreshTimer);
314
321
  setIsLoading(false);
315
322
  cancelAllThrottles();
316
323
  resetTurnState();
@@ -532,18 +539,24 @@ export function handleEvent(ev, setters) {
532
539
  switch (wf.type) {
533
540
  case 'workflow_start':
534
541
  setters.emitProgressLine?.(`▶ 工作流 ${wf.name} 开始(共 ${wf.totalSteps} 步)`);
542
+ // 工作流开始:立即刷新 token(可能已积累大量前置对话上下文)
543
+ setters.bump();
535
544
  return;
536
545
  case 'workflow_step_start':
537
546
  setters.emitProgressLine?.(` ▶ ${(wf.index ?? 0) + 1}/${wf.total ?? '?'} ${wf.id} (${wf.kind})`);
538
547
  return;
539
548
  case 'workflow_step_end':
540
549
  setters.emitProgressLine?.(` ${wf.ok ? '✓' : '✗'} ${wf.id}${wf.error ? `:${wf.error}` : ''}`);
550
+ // 步骤完成:强制刷新 token(agent/llm 步骤可能写入大量上下文)
551
+ setters.bump();
541
552
  return;
542
553
  case 'workflow_step_skipped':
543
554
  setters.emitProgressLine?.(` ⊘ ${wf.id}:${wf.reason ?? ''}`);
544
555
  return;
545
556
  case 'workflow_done':
546
557
  setters.emitProgressLine?.(`✓ 工作流 ${wf.name} 完成`);
558
+ // 工作流结束:最终刷新(反映完整执行后的上下文量)
559
+ setters.bump();
547
560
  return;
548
561
  }
549
562
  // 收口到 LoopEvent:未识别的 PluginEvent type 走 default no-op
@@ -35,8 +35,9 @@ steps:
35
35
  capture:
36
36
  content: line_report
37
37
 
38
- # 3. 守门 assert
38
+ # 3. 守门 verify(升级自 assert,享受 verify 的 file_exists 检查器)
39
39
  - id: verify
40
- type: assert
41
- condition: 'fileExists("./out/notes.md")'
40
+ type: verify
41
+ checks:
42
+ - 'file_exists:./out/notes.md'
42
43
  onFail: "调研笔记 ./out/notes.md 未生成,检查 research 步"
@@ -92,8 +92,10 @@ steps:
92
92
  "thumbnail_prompt": "${thumb_prompt}"
93
93
  }
94
94
 
95
- # 7. 守门 assert
95
+ # 7. 守门 verify(升级自 assert;多条 file_exists 拆成 checks 数组)
96
96
  - id: verify
97
- type: assert
98
- condition: 'fileExists("videos/${inputs.book}/script.txt") && fileExists("videos/${inputs.book}/meta.json")'
97
+ type: verify
98
+ checks:
99
+ - 'file_exists:videos/${inputs.book}/script.txt'
100
+ - 'file_exists:videos/${inputs.book}/meta.json'
99
101
  onFail: "脚本或 meta 未写盘,请检查 Write 工具"
@@ -17,8 +17,9 @@ steps:
17
17
  args.content: note_body
18
18
 
19
19
  - id: verify_file
20
- type: assert
21
- condition: 'fileExists("out/${inputs.topic}/note.txt")'
20
+ type: verify
21
+ checks:
22
+ - 'file_exists:out/${inputs.topic}/note.txt'
22
23
  onFail: "note.txt 未落盘"
23
24
 
24
25
  - id: verify_capture
@@ -1,189 +1,240 @@
1
- # ============================================================
2
- # workflows/plan.yaml —— 零交互计划流程(Analyze→Verify→Synthesize→Critic→Gate→Execute→Summary)
3
- # ------------------------------------------------------------
4
- # 设计目标:① 跨模型稳(弱模型也能跑完);② 零用户交互——全程自主;
5
- # ③ 计划详细程度从 goal 自动推断,不提问。
6
- # 全用现有 StepKind(不改引擎):
7
- # Analyze : analyze(agent 只读探索) → extract_findings(llm+schema 固化成可验证 claims)
8
- # Verify : verify_findings(type:vote 红队对每条 finding 反向提问证伪,存活的才进下游)
9
- # Synthesize: draft_plan(llm 纯文本出计划正文) → read_existing_plan + write_plan(tool 确定性落盘)
10
- # Critic : critic_plan(skill:adversarial-review 反向提问审稿,追加进 PLAN.md)
11
- # Gate : verify(assert 守门确认 PLAN.md 生成)
12
- # Execute : execute_plan(agent 按计划执行,产出最终交付物)
13
- # Summary : exit_summary(llm 退出摘要)
14
- # ------------------------------------------------------------
15
- # 提问策略:本工作流**零交互**。计划深度从用户 goal 自动推断:
16
- # - 目标含"概览/快速/简单/简短" → 快速概览
17
- # - 目标含"详细/完整/分步/彻底/带风险" → 带风险回滚评估
18
- # - 其他 → 详细分步(默认推荐)
19
- # 不询问用户选择深度——自行判断。
20
- # ------------------------------------------------------------
21
- # 注:critic 用 skill: 节点 dogfood 仓库自带的 adversarial-review skill。
22
- # skill 双源查找(cwd 优先、packageRoot fallback);异地 cwd 缺该 skill 时
23
- # critic 的 onError:continue 兜底——审稿出岔不应推翻已写好的计划。
24
- # ============================================================
1
+ # workflows/plan.yaml —— Plan 模式工作流
2
+ #
3
+ # 架构参考: Claude Code Plan Mode (commands/plan/plan.tsx)
4
+ # 适配差异:
5
+ # - Claude Code 用多 sub-agent(Explore/Plan/Verification) 并行
6
+ # - 我们用单 TAOR 引擎 + 不同 prompt 角色扮演(共享 history 更自然)
7
+ # - Claude Code 有权限系统只读约束(EnterPlanMode/ExitPlanMode)
8
+ # - 我们通过 agent prompt 约束 + artifacts 声明达到类似效果
9
+ #
10
+ # 断点续执行: 由 runner 层自动处理(taskIdentity + checkpoint + capture 回放)
11
+ # 自愈: 由 runner 的 self_heal.backoff + 内部 retry 循环控制
12
+
25
13
  name: plan
26
- description: |
27
- 零交互计划流程(跨模型稳、全程自主、自动推断深度)。
28
- Analyze(探索+固化) → Verify(vote 红队证伪) → Synthesize(出正文+落盘)
29
- → Critic(反向提问审稿追加) → Gate(assert 守门) → Execute(按计划执行) → Summary(退出摘要)。
30
- version: "0.4"
14
+ description: >
15
+ Plan 模式:探索→设计→审查→写计划→等审批→执行。
16
+ 5 阶段流水线,参考 Claude Code plan mode 的 Phase 1-5。
31
17
 
32
18
  inputs:
33
19
  - name: goal
34
20
  type: string
35
21
  required: true
36
- description: "要做的事 / 目标"
22
+ description: 用户想要实现的目标
23
+
24
+ self_heal:
25
+ backoff: 1 # step N 失败 → 回退 N 步重跑(覆盖可能有问题的产出)
26
+ max_retries: 2 # 每个步骤内部 retry 上限
27
+
28
+ artifacts:
29
+ - PLAN.md # 核心产出:实现计划文档
37
30
 
38
31
  steps:
39
- # ===================== Analyze =====================
40
- # [Analyze-1] 只读探索:agent 自主用 Read/Grep/Glob 摸清现状(不写盘、不副作用)
41
- - id: analyze
32
+ # ================================================================
33
+ # Phase 1: Initial Understanding —— 理解需求
34
+ # ================================================================
35
+ - id: gathering
42
36
  agent: |
43
- 只读调研目标「${inputs.goal}」相关的代码 / 资料:用 Read、Grep、Glob 工具
44
- (不要写文件、不要执行副作用命令)摸清现状,整理出 3-6 条候选关键事实
45
- 以及 1-3 个仍未决 / 需用户拍板的点,用简洁中文 markdown 列点返回。
46
- allowed_tools: [Read, Grep, Glob]
47
- capture:
48
- content: analysis
49
-
50
- # [Analyze-2] 固化成可验证 claims:llm 单轮 + output_schema(provider 不支持时由 client.ts 自动退化)
51
- - id: extract_findings
52
- llm: |
53
- 从下面的调研笔记中抽取「候选关键事实」与「未决问题」,原样保留信息、不要新增臆测。
54
- 调研笔记:
55
- ${analysis}
56
- output_schema:
57
- type: object
58
- additionalProperties: false
59
- required: [findings, open_questions]
60
- properties:
61
- findings:
62
- type: array
63
- items: { type: string }
64
- description: "每条独立成句的候选关键事实(便于逐条对抗验证)"
65
- open_questions:
66
- type: array
67
- items: { type: string }
68
- description: "仍需进一步验证 / 用户拍板的点"
69
- capture:
70
- findings: findings
71
- open_questions: open_questions
72
-
73
- # ===================== Verify =====================
74
- # [Verify] 红队对抗:vote 对每条 finding 反向提问证伪(voter 默认倾向 refuted=true);
75
- # 存活集可能偏少甚至为空,draft 对此 graceful degrade(见其提示)。
76
- - id: verify_findings
77
- type: vote
78
- input: "findings"
79
- voters_count: 3
80
- threshold: 2
81
- rules: |
82
- 判断这条「调研结论」是否站得住脚。不要问"它对不对",要问"它哪里是错的":
83
- 是否证据不足、把假设当事实、想当然、会被反例或现有代码/资料推翻。
84
- 只有当你找不到任何合理反驳、且它确有依据时,才认定成立(refuted=false)。
85
- capture:
86
- survived: verified_findings
87
- kept: kept_count
88
- total: total_count
89
-
90
- # ===================== Synthesize =====================
91
- # [Synthesize-1] 生成计划正文:llm 纯文本(不开工具、不提问)——确定性、跨模型稳,
92
- # 彻底避开"agent 反复调 Write"的弱模型死循环。
93
- - id: draft_plan
94
- llm: |
95
- 综合下列输入,为目标「${inputs.goal}」写一份**中文实现计划的完整 markdown 正文**
96
- (直接输出正文本身:不要寒暄、不要复述要求、不要用代码围栏包裹整篇)。
37
+ 你是一名资深的需求分析师。用户的目标是:「${inputs.goal}」
97
38
 
98
- —— 通过红队对抗验证的结论(${kept_count}/${total_count} 条存活)——
99
- ${verified_findings}
39
+ 请收集实现这个目标所需的关键信息:
40
+ 1. 目标的具体范围和边界条件
41
+ 2. 技术约束(语言、框架、兼容性要求)
42
+ 3. 质量要求(性能、安全、可维护性)
43
+ 4. 优先级排序(如果涉及多个子目标)
100
44
 
101
- —— 仍未决的问题 ——
102
- ${open_questions}
103
-
104
- ## 计划详细程度(自动推断,不询问用户)
105
- 根据用户目标「${inputs.goal}」中的关键词自动判断:
106
- - 如果目标包含"概览"、"快速"、"简单"、"简短"、"简要"、"大致"等词 → 输出快速概览(高层方向与关键决策,不展开到每一步)
107
- - 如果目标包含"详细"、"完整"、"分步"、"彻底"、"风险"、"回滚"、"全面"等词 → 输出带风险/回滚评估的详细计划
108
- - 其他情况 → 默认输出**详细分步**计划(可执行的有序步骤,每步说清动作、涉及文件与验收点)
45
+ 如果信息不足,使用 AskUserQuestion 工具向用户提问。
46
+ 如果已有足够信息(从上下文或目标描述中能推断),直接输出分析结果。
109
47
 
110
48
  要求:
111
- - 按上述推断的详细程度输出;
112
- - "存活结论"为空时不要硬编:按目标常识给出合理的计划骨架;
113
- - 凡需按需求拍板、但本工作流未询问的点(如受众/时长/范围),**自行做合理默认假设并继续**,
114
- 在正文开头用「## 假设(如需调整请告知)」一节列出假设,**绝不中断提问**。
115
- capture:
116
- text: plan_text
117
-
118
- # [Synthesize-2] 满足 Write 的"覆盖前须先 Read"守卫:PLAN.md 已存在则先 Read;
119
- # 首跑文件不存在 → Read 报错 → onError:continue 略过(不影响后续 Write 新建)。
120
- - id: read_existing_plan
121
- tool: Read
122
- args:
123
- file_path: ./PLAN.md
124
- onError: continue
125
-
126
- # [Synthesis-3] 落盘:tool:Write 确定性写入(不经 agent 循环,弱模型也稳)
127
- - id: write_plan
128
- tool: Write
129
- args:
130
- file_path: ./PLAN.md
131
- content: "${plan_text}"
132
-
133
- # ===================== Critic =====================
134
- # [Critic] 反向提问审稿:dogfood 仓库自带 adversarial-review skill;onError:continue 兜底
135
- - id: critic_plan
49
+ - 不要过度提问,对不确定的点做合理默认假设并继续
50
+ - 在正文开头用「## 假设」一节列出假设
51
+ - 最终输出结构化的需求分析(3-8 条要点)
52
+ capture: requirements
53
+ max_retries: 1
54
+
55
+ # ================================================================
56
+ # Phase 2: Research —— 探索代码库
57
+ # ================================================================
58
+ - id: research
59
+ agent: |
60
+ 你是一名资深工程师,负责研究现有代码库以支撑「${inputs.goal}」的实现。
61
+
62
+ 已知需求分析:
63
+ ${requirements}
64
+
65
+ 请执行以下探索(并行使用 Read/Grep/Glob/RunCommand):
66
+ 1. 定位所有相关的源代码文件(列出路径和关键行号)
67
+ 2. 理解现有架构和数据流(文字描述)
68
+ 3. 找到可复用的模式和函数(格式:函数名 @ file:line — 用途)
69
+ 4. 识别潜在的技术风险和外部依赖
70
+
71
+ 输出格式:
72
+ ## 代码探索报告
73
+ ### 相关文件
74
+ ### 现有架构概要
75
+ ### 可复用资源
76
+ ### 风险与依赖
77
+ capture: research_report
78
+ max_retries: 1
79
+
80
+ # ================================================================
81
+ # Phase 3: Design —— 设计方案
82
+ # ================================================================
83
+ - id: design
84
+ agent: |
85
+ 你是一名软件架构师。基于以下输入设计实现方案:
86
+
87
+ ## 用户目标
88
+ ${inputs.goal}
89
+
90
+ ## 需求分析
91
+ ${requirements}
92
+
93
+ ## 代码探索报告
94
+ ${research_report}
95
+
96
+ 请输出完整设计方案:
97
+
98
+ ### 1. 整体架构
99
+ (文字描述 + 关键决策及理由)
100
+
101
+ ### 2. 文件变更清单
102
+ 每个要修改/新建的文件一行:
103
+ - `path/to/file.ts` — 操作类型(new/edit/delete) — 具体改什么
104
+
105
+ ### 3. 详细变更
106
+ 对每个文件的变更给出具体内容概要(函数签名、数据结构、逻辑流)
107
+
108
+ ### 4. 数据流和接口
109
+ (模块间调用关系、新增/变更的接口)
110
+
111
+ ### 5. 验证方式
112
+ 编译命令 + 测试命令 + 手动检查项
113
+ capture: design_doc
114
+ max_retries: 1
115
+
116
+ # ================================================================
117
+ # Phase 4: Review —— 对抗性审查
118
+ # ================================================================
119
+ - id: review
136
120
  skill: adversarial-review
137
- maxTurns: 25
138
121
  input: |
139
- 对当前目录下的 ./PLAN.md 做一次对抗审查(先用 Read 读它)。审完用 Edit / Write 在文件
140
- 末尾追加一节 "## 审稿意见(反向提问对抗审查)",按 skill 的输出格式分
141
- 「🔴 真问题 / ⚪ 误报 / 🟡 待澄清」三类列出并附结论(真问题为 0 条也如实写)。
142
- 只新增这一节,不要重写或删改计划正文。
143
- onError: continue
144
-
145
- # ===================== Gate =====================
146
- # [Gate] 守门:确认计划文件确实生成
147
- - id: verify
148
- type: assert
149
- condition: 'fileExists("./PLAN.md")'
150
- onFail: "计划文件 ./PLAN.md 未生成,检查 draft_plan/write_plan 步是否成功"
151
-
152
- # ===================== Execute(按计划执行)=====================
153
- # [Execute] 读取已落盘的 PLAN.md,agent 自主按计划步骤逐一执行,
154
- # 直到完成所有任务并产出最终交付物。
155
- # onError: recover —— 执行中撞上预料之外的错误就就地降级为 agent 自适应恢复。
122
+ 待审查的设计方案:
123
+ ${design_doc}
124
+ 用户原始目标:${inputs.goal}
125
+ capture: review_notes
126
+ max_retries: 1
127
+
128
+ # ================================================================
129
+ # Phase 4.5: Revise —— 根据审查修订
130
+ # ================================================================
131
+ - id: revise
132
+ agent: |
133
+ 你是一名资深工程师。设计方案刚经过对抗性审查,审稿意见如下:
134
+
135
+ ${review_notes}
136
+
137
+ 原始设计方案:
138
+ ${design_doc}
139
+
140
+ 请根据审稿意见修订方案:
141
+ - 对每个真实问题给出具体修复方案
142
+ - 对误报(审稿意见不合理的地方)说明为什么不改
143
+ - 输出最终版设计方案(完整文档,不是 patch)
144
+ - 保持与原设计方案相同的结构
145
+ capture: revised_design
146
+ max_retries: 1
147
+
148
+ # ================================================================
149
+ # Phase 5: Draft Plan —— 生成计划文档(核心产出)
150
+ # ================================================================
151
+ - id: draft_plan
152
+ agent: |
153
+ 你是一名资深工程师,负责把最终设计方案写成可执行的实现计划。
154
+
155
+ ## 用户目标
156
+ ${inputs.goal}
157
+
158
+ ## 最终设计方案
159
+ ${revised_design}
160
+
161
+ 请将计划写入 ./PLAN.md,内容必须包含:
162
+
163
+ # 实现计划:{goal 的简短摘要}
164
+
165
+ ## 假设(如需调整请告知)
166
+ (列出所有默认假设,每条一行)
167
+
168
+ ## 实现步骤
169
+ ### Step 1: {标题}
170
+ - **文件**: path/to/file.ts
171
+ - **操作**: 具体改什么(精确到函数/行级别)
172
+ - **理由**: 为什么这么改
173
+
174
+ (每个要修改的文件一个 Step,按依赖顺序排列)
175
+
176
+ ## 验证命令
177
+ \`\`\`bash
178
+ # 编译检查命令
179
+ # 测试运行命令
180
+ \`\`\`
181
+
182
+ ## 产出物清单
183
+ - [ ] 文件 A
184
+ - [ ] 文件 B
185
+
186
+ ---
187
+ **硬约束**:
188
+ ① 绝对不要输出思考过程标签
189
+ ② 绝对不要输出 JSON tool_call 原文
190
+ ③ 必须是可直接执行的实现计划(不是审查意见、不是问题列表)
191
+ ④ "存活结论"为空时按常识给出合理的计划骨架
192
+ ⑤ 凡需拍板但未询问的点自行假设并继续,不中断
193
+ artifacts:
194
+ - PLAN.md
195
+ max_retries: 1
196
+
197
+ # ================================================================
198
+ # Phase 5.5: User Review —— 用户审批(交互模式)/ 自动通过(非交互)
199
+ # ================================================================
200
+ - id: user_review
201
+ type: pause
202
+ pause:
203
+ message: |
204
+ 📋 计划已生成:./PLAN.md
205
+ 请review后回复"继续"开始执行,或提出修改意见。
206
+ (非交互模式将自动跳过此步骤)
207
+ max_retries: 1
208
+
209
+ # ================================================================
210
+ # Phase 6: Execute Plan —— 执行实现
211
+ # ================================================================
156
212
  - id: execute_plan
157
213
  agent: |
158
- 下面是一份已经过完整工作流验证的实现计划(./PLAN.md)。
214
+ 你是一名资深工程师,负责执行一份已经过工作流验证的实现计划。
159
215
  请先 Read ./PLAN.md 了解完整计划内容和步骤。
160
- 然后严格按照计划的步骤逐一执行,直到完成所有任务并产出最终交付物。
161
- 执行过程中:
162
- 1. 如果计划中提到使用某个 skill(如 pptx/pdf/docx),先用 Read 读取对应 skills/ 目录下的 SKILL.md 了解用法
216
+
217
+ 重要说明:
218
+ - PLAN.md 可能包含审稿意见章节(以"## 审稿意见"或"## 对抗审查结果"开头),
219
+ 那是反向提问审查的输出,不是计划本身。请聚焦于计划正文部分提取实际任务步骤。
220
+ - 如果计划正文质量不佳或格式异常,请根据目标「${inputs.goal}」
221
+ 自行推断合理的执行方案并继续推进。
222
+
223
+ 执行要求:
224
+ 1. 如果计划中提到使用某个 skill(如 pptx/pdf/docx),先用 Read 读取对应 SKILL.md 了解用法
163
225
  2. 每完成一个主要步骤后简要汇报进度
164
226
  3. 如果遇到计划中未预见的情况,自行判断合理方案并继续(不要中断等待)
165
227
  4. 全部完成后用一两句话总结产出物位置和内容
166
- allowed_tools: [Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch]
167
- maxTurns: 40
168
- onError: recover
169
- capture:
170
- content: execution_result
171
-
172
- # ===================== Exit Summary(退出摘要)=====================
173
- # [Exit Summary] 用 llm 产出一句话摘要,让用户知道"做了什么、产物在哪、如何继续"。
174
- # plan 工作流到此彻底结束,之后回到正常 TUI 对话模式。
175
- - id: exit_summary
176
- llm: |
177
- 用户的目标是「${inputs.goal}」。
178
- 计划已制定(PLAN.md)并执行完毕。
179
- 执行结果:${execution_result}
180
-
181
- 请用简洁中文写一段最终摘要(3-5句话),包含:
182
- 1. 完成了什么
183
- 2. 最终产物路径(文件名和目录)
184
- 3. 如有后续建议也简短提及
185
-
186
- 直接输出摘要正文,不要寒暄。
187
- ${execution_result ? `执行结果:${execution_result}` : '(执行步骤未产出详细结果)'}
188
- capture:
189
- text: summary_text
228
+ 5. 绝不要输出 __AGENT_GIVEUP__ —— 即使计划不完美也要尽力达成目标
229
+ max_retries: 2
230
+
231
+ # ================================================================
232
+ # Phase 7: Summary —— 总结
233
+ # ================================================================
234
+ - id: summary
235
+ agent: |
236
+ 工作流已全部完成。请简要总结:
237
+ 1. 产出物位置和内容(文件路径 + 一句话描述)
238
+ 2. 是否有遗留问题需要用户关注
239
+ 3. 验证结果(测试是否通过、编译是否成功)
240
+ max_retries: 1