edit プロパティによるファイル編集制御、ステップ完了時のレポートログ出力、resolveContentPath 追加
- edit: true/false をワークフローステップに追加し、エージェントへの編集許可/禁止プロンプトを自動注入 - ステップ完了時に step:report イベントを発火し、レポート内容をコンソール出力 - resolveContentPath() で format/instruction_template の .md ファイル参照に対応 - writeStepReport() を削除し、レポート出力はエージェント責務に統一 - 全8ワークフローYAMLに edit フィールドを付与 resolves #6, resolves #21, resolves #22
This commit is contained in:
parent
6fe6491948
commit
706a59d3b6
@ -28,6 +28,7 @@ initial_step: plan
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -91,6 +92,7 @@ steps:
|
||||
3. Decide implementation approach
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -149,6 +151,7 @@ steps:
|
||||
```
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -202,6 +205,7 @@ steps:
|
||||
- Scope creep detection
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -231,6 +235,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
@ -285,6 +290,7 @@ steps:
|
||||
Review the changes and provide feedback.
|
||||
|
||||
- name: improve
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -316,6 +322,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -342,6 +349,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/security-reviewer.md
|
||||
report:
|
||||
name: 05-security-review.md
|
||||
@ -398,6 +406,7 @@ steps:
|
||||
- Cryptographic weaknesses
|
||||
|
||||
- name: security_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -423,6 +432,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 06-supervisor-validation.md
|
||||
|
||||
@ -31,6 +31,7 @@ steps:
|
||||
# Phase 0: Planning
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -91,6 +92,7 @@ steps:
|
||||
# Phase 1: Implementation
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -151,6 +153,7 @@ steps:
|
||||
# Phase 2: AI Review
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -204,6 +207,7 @@ steps:
|
||||
next: ai_fix
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -235,6 +239,7 @@ steps:
|
||||
# Phase 3: CQRS+ES Review
|
||||
# ===========================================
|
||||
- name: cqrs_es_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert-cqrs/cqrs-es-reviewer.md
|
||||
report:
|
||||
name: 04-cqrs-es-review.md
|
||||
@ -292,6 +297,7 @@ steps:
|
||||
next: fix_cqrs_es
|
||||
|
||||
- name: fix_cqrs_es
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -325,6 +331,7 @@ steps:
|
||||
# Phase 4: Frontend Review
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
@ -382,6 +389,7 @@ steps:
|
||||
next: fix_frontend
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -415,6 +423,7 @@ steps:
|
||||
# Phase 5: Security Review
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
@ -469,6 +478,7 @@ steps:
|
||||
next: fix_security
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -512,6 +522,7 @@ steps:
|
||||
# Phase 6: QA Review
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
@ -566,6 +577,7 @@ steps:
|
||||
next: fix_qa
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -613,6 +625,7 @@ steps:
|
||||
# Phase 7: Supervision
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
@ -709,6 +722,7 @@ steps:
|
||||
next: fix_supervisor
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
|
||||
@ -43,6 +43,7 @@ steps:
|
||||
# Phase 0: Planning
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -103,6 +104,7 @@ steps:
|
||||
# Phase 1: Implementation
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -163,6 +165,7 @@ steps:
|
||||
# Phase 2: AI Review
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -216,6 +219,7 @@ steps:
|
||||
next: ai_fix
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -247,6 +251,7 @@ steps:
|
||||
# Phase 3: Architecture Review
|
||||
# ===========================================
|
||||
- name: architect_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
@ -310,6 +315,7 @@ steps:
|
||||
next: fix_architect
|
||||
|
||||
- name: fix_architect
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -339,6 +345,7 @@ steps:
|
||||
# Phase 4: Frontend Review
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
@ -396,6 +403,7 @@ steps:
|
||||
next: fix_frontend
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -429,6 +437,7 @@ steps:
|
||||
# Phase 5: Security Review
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
@ -483,6 +492,7 @@ steps:
|
||||
next: fix_security
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -526,6 +536,7 @@ steps:
|
||||
# Phase 6: QA Review
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
@ -580,6 +591,7 @@ steps:
|
||||
next: fix_qa
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -627,6 +639,7 @@ steps:
|
||||
# Phase 7: Supervision
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
@ -723,6 +736,7 @@ steps:
|
||||
next: fix_supervisor
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
|
||||
@ -25,6 +25,7 @@ initial_step: plan
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -84,6 +85,7 @@ steps:
|
||||
3. Decide implementation approach
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -142,6 +144,7 @@ steps:
|
||||
```
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -195,6 +198,7 @@ steps:
|
||||
- Scope creep detection
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
@ -250,6 +254,7 @@ steps:
|
||||
If there are minor suggestions, use APPROVE + comments.
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 05-supervisor-validation.md
|
||||
|
||||
@ -19,6 +19,7 @@ initial_step: plan
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -82,6 +83,7 @@ steps:
|
||||
3. 実装アプローチを決める
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -145,6 +147,7 @@ steps:
|
||||
```
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -198,6 +201,7 @@ steps:
|
||||
- スコープクリープの検出
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -227,6 +231,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
@ -292,6 +297,7 @@ steps:
|
||||
- 呼び出しチェーン検証
|
||||
|
||||
- name: improve
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -323,6 +329,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -348,6 +355,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/security-reviewer.md
|
||||
report:
|
||||
name: 05-security-review.md
|
||||
@ -404,6 +412,7 @@ steps:
|
||||
- 暗号化の弱点
|
||||
|
||||
- name: security_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -429,6 +438,7 @@ steps:
|
||||
pass_previous_response: true
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 06-supervisor-validation.md
|
||||
|
||||
@ -40,6 +40,7 @@ steps:
|
||||
# Phase 0: Planning
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -100,6 +101,7 @@ steps:
|
||||
# Phase 1: Implementation
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -117,7 +119,7 @@ steps:
|
||||
planステップで立てた計画に従って実装してください。
|
||||
計画レポート(00-plan.md)を参照し、実装を進めてください。
|
||||
|
||||
**レポート出力:** 上記の `Report Files` に出力してください。
|
||||
**レポート出力:** Report Files に出力してください。
|
||||
- ファイルが存在しない場合: 新規作成
|
||||
- ファイルが存在する場合: `## Iteration {step_iteration}` セクションを追記
|
||||
|
||||
@ -160,6 +162,7 @@ steps:
|
||||
# Phase 2: AI Review
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -213,6 +216,7 @@ steps:
|
||||
next: ai_fix
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -244,6 +248,7 @@ steps:
|
||||
# Phase 3: CQRS+ES Review
|
||||
# ===========================================
|
||||
- name: cqrs_es_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert-cqrs/cqrs-es-reviewer.md
|
||||
report:
|
||||
name: 04-cqrs-es-review.md
|
||||
@ -301,6 +306,7 @@ steps:
|
||||
next: fix_cqrs_es
|
||||
|
||||
- name: fix_cqrs_es
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -334,6 +340,7 @@ steps:
|
||||
# Phase 4: Frontend Review
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
@ -391,6 +398,7 @@ steps:
|
||||
next: fix_frontend
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -424,6 +432,7 @@ steps:
|
||||
# Phase 5: Security Review
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
@ -478,6 +487,7 @@ steps:
|
||||
next: fix_security
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -521,6 +531,7 @@ steps:
|
||||
# Phase 6: QA Review
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
@ -575,6 +586,7 @@ steps:
|
||||
next: fix_qa
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -622,6 +634,7 @@ steps:
|
||||
# Phase 7: Supervision
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
@ -652,7 +665,7 @@ steps:
|
||||
**レポートの確認:** Report Directory内の全レポートを読み、
|
||||
未対応の改善提案がないか確認してください。
|
||||
|
||||
**レポート出力:** 上記の `Report Files` に出力してください。
|
||||
**レポート出力:** Report Files に出力してください。
|
||||
- ファイルが存在しない場合: 新規作成
|
||||
- ファイルが存在する場合: `## Iteration {step_iteration}` セクションを追記
|
||||
|
||||
@ -718,6 +731,7 @@ steps:
|
||||
next: fix_supervisor
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
|
||||
@ -31,6 +31,7 @@ steps:
|
||||
# Phase 0: Planning
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -91,6 +92,7 @@ steps:
|
||||
# Phase 1: Implementation
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -108,7 +110,7 @@ steps:
|
||||
planステップで立てた計画に従って実装してください。
|
||||
計画レポート(00-plan.md)を参照し、実装を進めてください。
|
||||
|
||||
**レポート出力:** 上記の `Report Files` に出力してください。
|
||||
**レポート出力:** Report Files に出力してください。
|
||||
- ファイルが存在しない場合: 新規作成
|
||||
- ファイルが存在する場合: `## Iteration {step_iteration}` セクションを追記
|
||||
|
||||
@ -151,6 +153,7 @@ steps:
|
||||
# Phase 2: AI Review
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -204,6 +207,7 @@ steps:
|
||||
next: ai_fix
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -235,6 +239,7 @@ steps:
|
||||
# Phase 3: Architecture Review
|
||||
# ===========================================
|
||||
- name: architect_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
@ -298,6 +303,7 @@ steps:
|
||||
next: fix_architect
|
||||
|
||||
- name: fix_architect
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -327,6 +333,7 @@ steps:
|
||||
# Phase 4: Frontend Review
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
@ -384,6 +391,7 @@ steps:
|
||||
next: fix_frontend
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -417,6 +425,7 @@ steps:
|
||||
# Phase 5: Security Review
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
@ -471,6 +480,7 @@ steps:
|
||||
next: fix_security
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -514,6 +524,7 @@ steps:
|
||||
# Phase 6: QA Review
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
@ -568,6 +579,7 @@ steps:
|
||||
next: fix_qa
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
@ -615,6 +627,7 @@ steps:
|
||||
# Phase 7: Supervision
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
@ -645,7 +658,7 @@ steps:
|
||||
**レポートの確認:** Report Directory内の全レポートを読み、
|
||||
未対応の改善提案がないか確認してください。
|
||||
|
||||
**レポート出力:** 上記の `Report Files` に出力してください。
|
||||
**レポート出力:** Report Files に出力してください。
|
||||
- ファイルが存在しない場合: 新規作成
|
||||
- ファイルが存在する場合: `## Iteration {step_iteration}` セクションを追記
|
||||
|
||||
@ -711,6 +724,7 @@ steps:
|
||||
next: fix_supervisor
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
|
||||
@ -20,6 +20,7 @@ initial_step: plan
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
@ -83,6 +84,7 @@ steps:
|
||||
- {質問2}
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
@ -101,6 +103,10 @@ steps:
|
||||
planステップで立てた計画に従って実装してください。
|
||||
計画レポート(00-plan.md)を参照し、実装を進めてください。
|
||||
|
||||
**レポート出力:** Report Files に出力してください。
|
||||
- ファイルが存在しない場合: 新規作成
|
||||
- ファイルが存在する場合: `## Iteration {step_iteration}` セクションを追記
|
||||
|
||||
**Scopeレポートフォーマット(実装開始時に作成):**
|
||||
```markdown
|
||||
# 変更スコープ宣言
|
||||
@ -137,6 +143,7 @@ steps:
|
||||
next: plan
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
@ -190,6 +197,7 @@ steps:
|
||||
next: plan
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
@ -245,6 +253,7 @@ steps:
|
||||
next: plan
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 05-supervisor-validation.md
|
||||
@ -268,6 +277,10 @@ steps:
|
||||
**レポートの確認:** Report Directory内の全レポートを読み、
|
||||
未対応の改善提案がないか確認してください。
|
||||
|
||||
**レポート出力:** Report Files に出力してください。
|
||||
- ファイルが存在しない場合: 新規作成
|
||||
- ファイルが存在する場合: `## Iteration {step_iteration}` セクションを追記
|
||||
|
||||
**Validationレポートフォーマット:**
|
||||
```markdown
|
||||
# 最終検証結果
|
||||
|
||||
175
src/__tests__/engine-report.test.ts
Normal file
175
src/__tests__/engine-report.test.ts
Normal file
@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Tests for engine report event emission (step:report)
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
||||
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { isReportObjectConfig } from '../workflow/instruction-builder.js';
|
||||
import type { WorkflowStep, ReportObjectConfig, ReportConfig } from '../models/types.js';
|
||||
|
||||
/**
|
||||
* Extracted emitStepReports logic for unit testing.
|
||||
* Mirrors engine.ts emitStepReports + emitIfReportExists.
|
||||
*/
|
||||
function emitStepReports(
|
||||
emitter: EventEmitter,
|
||||
step: WorkflowStep,
|
||||
reportDir: string,
|
||||
projectCwd: string,
|
||||
): void {
|
||||
if (!step.report || !reportDir) return;
|
||||
const baseDir = join(projectCwd, '.takt', 'reports', reportDir);
|
||||
|
||||
if (typeof step.report === 'string') {
|
||||
emitIfReportExists(emitter, step, baseDir, step.report);
|
||||
} else if (isReportObjectConfig(step.report)) {
|
||||
emitIfReportExists(emitter, step, baseDir, step.report.name);
|
||||
} else {
|
||||
for (const rc of step.report) {
|
||||
emitIfReportExists(emitter, step, baseDir, rc.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function emitIfReportExists(
|
||||
emitter: EventEmitter,
|
||||
step: WorkflowStep,
|
||||
baseDir: string,
|
||||
fileName: string,
|
||||
): void {
|
||||
const filePath = join(baseDir, fileName);
|
||||
if (existsSync(filePath)) {
|
||||
emitter.emit('step:report', step, filePath, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a minimal WorkflowStep for testing */
|
||||
function createStep(overrides: Partial<WorkflowStep> = {}): WorkflowStep {
|
||||
return {
|
||||
name: 'test-step',
|
||||
agent: 'coder',
|
||||
agentDisplayName: 'Coder',
|
||||
instructionTemplate: '',
|
||||
passPreviousResponse: false,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe('emitStepReports', () => {
|
||||
let tmpDir: string;
|
||||
let reportBaseDir: string;
|
||||
const reportDirName = 'test-report-dir';
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = join(tmpdir(), `takt-report-test-${Date.now()}`);
|
||||
reportBaseDir = join(tmpDir, '.takt', 'reports', reportDirName);
|
||||
mkdirSync(reportBaseDir, { recursive: true });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('should emit step:report when string report file exists', () => {
|
||||
// Given: a step with string report and the file exists
|
||||
const step = createStep({ report: 'plan.md' });
|
||||
writeFileSync(join(reportBaseDir, 'plan.md'), '# Plan', 'utf-8');
|
||||
const emitter = new EventEmitter();
|
||||
const handler = vi.fn();
|
||||
emitter.on('step:report', handler);
|
||||
|
||||
// When
|
||||
emitStepReports(emitter, step, reportDirName, tmpDir);
|
||||
|
||||
// Then
|
||||
expect(handler).toHaveBeenCalledOnce();
|
||||
expect(handler).toHaveBeenCalledWith(step, join(reportBaseDir, 'plan.md'), 'plan.md');
|
||||
});
|
||||
|
||||
it('should not emit when string report file does not exist', () => {
|
||||
// Given: a step with string report but file doesn't exist
|
||||
const step = createStep({ report: 'missing.md' });
|
||||
const emitter = new EventEmitter();
|
||||
const handler = vi.fn();
|
||||
emitter.on('step:report', handler);
|
||||
|
||||
// When
|
||||
emitStepReports(emitter, step, reportDirName, tmpDir);
|
||||
|
||||
// Then
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit step:report when ReportObjectConfig report file exists', () => {
|
||||
// Given: a step with ReportObjectConfig and the file exists
|
||||
const report: ReportObjectConfig = { name: '03-review.md', format: '# Review' };
|
||||
const step = createStep({ report });
|
||||
writeFileSync(join(reportBaseDir, '03-review.md'), '# Review\nOK', 'utf-8');
|
||||
const emitter = new EventEmitter();
|
||||
const handler = vi.fn();
|
||||
emitter.on('step:report', handler);
|
||||
|
||||
// When
|
||||
emitStepReports(emitter, step, reportDirName, tmpDir);
|
||||
|
||||
// Then
|
||||
expect(handler).toHaveBeenCalledOnce();
|
||||
expect(handler).toHaveBeenCalledWith(step, join(reportBaseDir, '03-review.md'), '03-review.md');
|
||||
});
|
||||
|
||||
it('should emit for each existing file in ReportConfig[] array', () => {
|
||||
// Given: a step with array report, two files exist, one missing
|
||||
const report: ReportConfig[] = [
|
||||
{ label: 'Scope', path: '01-scope.md' },
|
||||
{ label: 'Decisions', path: '02-decisions.md' },
|
||||
{ label: 'Missing', path: '03-missing.md' },
|
||||
];
|
||||
const step = createStep({ report });
|
||||
writeFileSync(join(reportBaseDir, '01-scope.md'), '# Scope', 'utf-8');
|
||||
writeFileSync(join(reportBaseDir, '02-decisions.md'), '# Decisions', 'utf-8');
|
||||
const emitter = new EventEmitter();
|
||||
const handler = vi.fn();
|
||||
emitter.on('step:report', handler);
|
||||
|
||||
// When
|
||||
emitStepReports(emitter, step, reportDirName, tmpDir);
|
||||
|
||||
// Then: emitted for scope and decisions, not for missing
|
||||
expect(handler).toHaveBeenCalledTimes(2);
|
||||
expect(handler).toHaveBeenCalledWith(step, join(reportBaseDir, '01-scope.md'), '01-scope.md');
|
||||
expect(handler).toHaveBeenCalledWith(step, join(reportBaseDir, '02-decisions.md'), '02-decisions.md');
|
||||
});
|
||||
|
||||
it('should not emit when step has no report', () => {
|
||||
// Given: a step without report
|
||||
const step = createStep({ report: undefined });
|
||||
const emitter = new EventEmitter();
|
||||
const handler = vi.fn();
|
||||
emitter.on('step:report', handler);
|
||||
|
||||
// When
|
||||
emitStepReports(emitter, step, reportDirName, tmpDir);
|
||||
|
||||
// Then
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not emit when reportDir is empty', () => {
|
||||
// Given: a step with report but empty reportDir
|
||||
const step = createStep({ report: 'plan.md' });
|
||||
writeFileSync(join(reportBaseDir, 'plan.md'), '# Plan', 'utf-8');
|
||||
const emitter = new EventEmitter();
|
||||
const handler = vi.fn();
|
||||
emitter.on('step:report', handler);
|
||||
|
||||
// When: empty reportDir
|
||||
emitStepReports(emitter, step, '', tmpDir);
|
||||
|
||||
// Then
|
||||
expect(handler).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@ -9,6 +9,7 @@ import {
|
||||
renderExecutionMetadata,
|
||||
renderStatusRulesHeader,
|
||||
generateStatusRulesFromRules,
|
||||
isReportObjectConfig,
|
||||
type InstructionContext,
|
||||
} from '../workflow/instruction-builder.js';
|
||||
import type { WorkflowStep, WorkflowRule } from '../models/types.js';
|
||||
@ -75,6 +76,34 @@ describe('instruction-builder', () => {
|
||||
|
||||
expect(metadataIndex).toBeLessThan(bodyIndex);
|
||||
});
|
||||
|
||||
it('should include edit enabled prompt when step.edit is true', () => {
|
||||
const step = { ...createMinimalStep('Implement feature'), edit: true as const };
|
||||
const context = createMinimalContext({ cwd: '/project' });
|
||||
|
||||
const result = buildInstruction(step, context);
|
||||
|
||||
expect(result).toContain('Editing is ENABLED');
|
||||
});
|
||||
|
||||
it('should include edit disabled prompt when step.edit is false', () => {
|
||||
const step = { ...createMinimalStep('Review code'), edit: false as const };
|
||||
const context = createMinimalContext({ cwd: '/project' });
|
||||
|
||||
const result = buildInstruction(step, context);
|
||||
|
||||
expect(result).toContain('Editing is DISABLED');
|
||||
});
|
||||
|
||||
it('should not include edit prompt when step.edit is undefined', () => {
|
||||
const step = createMinimalStep('Do some work');
|
||||
const context = createMinimalContext({ cwd: '/project' });
|
||||
|
||||
const result = buildInstruction(step, context);
|
||||
|
||||
expect(result).not.toContain('Editing is ENABLED');
|
||||
expect(result).not.toContain('Editing is DISABLED');
|
||||
});
|
||||
});
|
||||
|
||||
describe('report_dir replacement', () => {
|
||||
@ -176,6 +205,20 @@ describe('instruction-builder', () => {
|
||||
|
||||
expect(metadata.language).toBe('ja');
|
||||
});
|
||||
|
||||
it('should propagate edit field when provided', () => {
|
||||
const context = createMinimalContext({ cwd: '/project' });
|
||||
|
||||
expect(buildExecutionMetadata(context, true).edit).toBe(true);
|
||||
expect(buildExecutionMetadata(context, false).edit).toBe(false);
|
||||
});
|
||||
|
||||
it('should leave edit undefined when not provided', () => {
|
||||
const context = createMinimalContext({ cwd: '/project' });
|
||||
const metadata = buildExecutionMetadata(context);
|
||||
|
||||
expect(metadata.edit).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderExecutionMetadata', () => {
|
||||
@ -212,6 +255,43 @@ describe('instruction-builder', () => {
|
||||
expect(enRendered).toContain('Note:');
|
||||
expect(jaRendered).not.toContain('Note:');
|
||||
});
|
||||
|
||||
it('should include edit enabled prompt when edit is true (en)', () => {
|
||||
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en', edit: true });
|
||||
|
||||
expect(rendered).toContain('Editing is ENABLED');
|
||||
expect(rendered).not.toContain('Editing is DISABLED');
|
||||
});
|
||||
|
||||
it('should include edit disabled prompt when edit is false (en)', () => {
|
||||
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en', edit: false });
|
||||
|
||||
expect(rendered).toContain('Editing is DISABLED');
|
||||
expect(rendered).not.toContain('Editing is ENABLED');
|
||||
});
|
||||
|
||||
it('should not include edit prompt when edit is undefined', () => {
|
||||
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'en' });
|
||||
|
||||
expect(rendered).not.toContain('Editing is ENABLED');
|
||||
expect(rendered).not.toContain('Editing is DISABLED');
|
||||
expect(rendered).not.toContain('編集が許可');
|
||||
expect(rendered).not.toContain('編集が禁止');
|
||||
});
|
||||
|
||||
it('should render edit enabled prompt in Japanese when language is ja', () => {
|
||||
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'ja', edit: true });
|
||||
|
||||
expect(rendered).toContain('編集が許可されています');
|
||||
expect(rendered).not.toContain('編集が禁止');
|
||||
});
|
||||
|
||||
it('should render edit disabled prompt in Japanese when language is ja', () => {
|
||||
const rendered = renderExecutionMetadata({ workingDirectory: '/project', language: 'ja', edit: false });
|
||||
|
||||
expect(rendered).toContain('編集が禁止されています');
|
||||
expect(rendered).not.toContain('編集が許可');
|
||||
});
|
||||
});
|
||||
|
||||
describe('renderStatusRulesHeader', () => {
|
||||
@ -746,4 +826,22 @@ describe('instruction-builder', () => {
|
||||
expect(result).toContain('Run #2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isReportObjectConfig', () => {
|
||||
it('should return true for ReportObjectConfig', () => {
|
||||
expect(isReportObjectConfig({ name: '00-plan.md' })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for ReportObjectConfig with order/format', () => {
|
||||
expect(isReportObjectConfig({ name: '00-plan.md', order: 'output to...', format: '# Plan' })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for string', () => {
|
||||
expect(isReportObjectConfig('00-plan.md')).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for ReportConfig[] (array)', () => {
|
||||
expect(isReportObjectConfig([{ label: 'Scope', path: '01-scope.md' }])).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
* Workflow execution logic
|
||||
*/
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { WorkflowEngine } from '../workflow/engine.js';
|
||||
import type { WorkflowConfig, Language } from '../models/types.js';
|
||||
import type { IterationLimitRequest } from '../workflow/types.js';
|
||||
@ -223,6 +224,12 @@ export async function executeWorkflow(
|
||||
updateLatestPointer(sessionLog, workflowSessionId, projectCwd);
|
||||
});
|
||||
|
||||
engine.on('step:report', (_step, filePath, fileName) => {
|
||||
const content = readFileSync(filePath, 'utf-8');
|
||||
console.log(`\n📄 Report: ${fileName}\n`);
|
||||
console.log(content);
|
||||
});
|
||||
|
||||
engine.on('workflow:complete', (state) => {
|
||||
log.info('Workflow completed successfully', { iterations: state.iteration });
|
||||
finalizeSessionLog(sessionLog, 'completed');
|
||||
|
||||
@ -54,6 +54,31 @@ function extractAgentDisplayName(agentPath: string): string {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a string value that may be a file path.
|
||||
* If the value ends with .md and the file exists (resolved relative to workflowDir),
|
||||
* read and return the file contents. Otherwise return the value as-is.
|
||||
*/
|
||||
function resolveContentPath(value: string | undefined, workflowDir: string): string | undefined {
|
||||
if (value == null) return undefined;
|
||||
if (value.endsWith('.md')) {
|
||||
// Resolve path relative to workflow directory
|
||||
let resolvedPath = value;
|
||||
if (value.startsWith('./')) {
|
||||
resolvedPath = join(workflowDir, value.slice(2));
|
||||
} else if (value.startsWith('~')) {
|
||||
const homedir = process.env.HOME || process.env.USERPROFILE || '';
|
||||
resolvedPath = join(homedir, value.slice(1));
|
||||
} else if (!value.startsWith('/')) {
|
||||
resolvedPath = join(workflowDir, value);
|
||||
}
|
||||
if (existsSync(resolvedPath)) {
|
||||
return readFileSync(resolvedPath, 'utf-8');
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a raw report value is the object form (has 'name' property).
|
||||
*/
|
||||
@ -78,11 +103,16 @@ function isReportObject(raw: unknown): raw is { name: string; order?: string; fo
|
||||
*/
|
||||
function normalizeReport(
|
||||
raw: string | Record<string, string>[] | { name: string; order?: string; format?: string } | undefined,
|
||||
workflowDir: string,
|
||||
): string | ReportConfig[] | ReportObjectConfig | undefined {
|
||||
if (raw == null) return undefined;
|
||||
if (typeof raw === 'string') return raw;
|
||||
if (isReportObject(raw)) {
|
||||
return { name: raw.name, order: raw.order, format: raw.format };
|
||||
return {
|
||||
name: raw.name,
|
||||
order: resolveContentPath(raw.order, workflowDir),
|
||||
format: resolveContentPath(raw.format, workflowDir),
|
||||
};
|
||||
}
|
||||
// Convert [{Scope: "01-scope.md"}, ...] to [{label: "Scope", path: "01-scope.md"}, ...]
|
||||
return (raw as Record<string, string>[]).flatMap((entry) =>
|
||||
@ -113,9 +143,10 @@ function normalizeWorkflowConfig(raw: unknown, workflowDir: string): WorkflowCon
|
||||
provider: step.provider,
|
||||
model: step.model,
|
||||
permissionMode: step.permission_mode,
|
||||
instructionTemplate: step.instruction_template || step.instruction || '{task}',
|
||||
edit: step.edit,
|
||||
instructionTemplate: resolveContentPath(step.instruction_template, workflowDir) || step.instruction || '{task}',
|
||||
rules,
|
||||
report: normalizeReport(step.report),
|
||||
report: normalizeReport(step.report, workflowDir),
|
||||
passPreviousResponse: step.pass_previous_response,
|
||||
};
|
||||
});
|
||||
|
||||
@ -92,6 +92,8 @@ export const WorkflowStepRawSchema = z.object({
|
||||
model: z.string().optional(),
|
||||
/** Permission mode for tool execution in this step */
|
||||
permission_mode: PermissionModeSchema.optional(),
|
||||
/** Whether this step is allowed to edit project files */
|
||||
edit: z.boolean().optional(),
|
||||
instruction: z.string().optional(),
|
||||
instruction_template: z.string().optional(),
|
||||
/** Rules for step routing */
|
||||
|
||||
@ -88,6 +88,8 @@ export interface WorkflowStep {
|
||||
model?: string;
|
||||
/** Permission mode for tool execution in this step */
|
||||
permissionMode?: PermissionMode;
|
||||
/** Whether this step is allowed to edit project files (true=allowed, false=prohibited, undefined=no prompt) */
|
||||
edit?: boolean;
|
||||
instructionTemplate: string;
|
||||
/** Rules for step routing */
|
||||
rules?: WorkflowRule[];
|
||||
|
||||
@ -16,7 +16,7 @@ import { COMPLETE_STEP, ABORT_STEP, ERROR_MESSAGES } from './constants.js';
|
||||
import type { WorkflowEngineOptions } from './types.js';
|
||||
import { determineNextStepByRules } from './transitions.js';
|
||||
import { detectRuleIndex } from '../claude/client.js';
|
||||
import { buildInstruction as buildInstructionFromTemplate } from './instruction-builder.js';
|
||||
import { buildInstruction as buildInstructionFromTemplate, isReportObjectConfig } from './instruction-builder.js';
|
||||
import { LoopDetector } from './loop-detector.js';
|
||||
import { handleBlocked } from './blocked-handler.js';
|
||||
import {
|
||||
@ -168,6 +168,34 @@ export class WorkflowEngine extends EventEmitter {
|
||||
return step;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit step:report events for each report file that exists after step completion.
|
||||
* The UI layer (workflowExecution.ts) listens and displays the content.
|
||||
*/
|
||||
private emitStepReports(step: WorkflowStep): void {
|
||||
if (!step.report || !this.reportDir) return;
|
||||
const baseDir = join(this.projectCwd, '.takt', 'reports', this.reportDir);
|
||||
|
||||
if (typeof step.report === 'string') {
|
||||
this.emitIfReportExists(step, baseDir, step.report);
|
||||
} else if (isReportObjectConfig(step.report)) {
|
||||
this.emitIfReportExists(step, baseDir, step.report.name);
|
||||
} else {
|
||||
// ReportConfig[] (array)
|
||||
for (const rc of step.report) {
|
||||
this.emitIfReportExists(step, baseDir, rc.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Emit step:report if the report file exists */
|
||||
private emitIfReportExists(step: WorkflowStep, baseDir: string, fileName: string): void {
|
||||
const filePath = join(baseDir, fileName);
|
||||
if (existsSync(filePath)) {
|
||||
this.emit('step:report', step, filePath, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/** Run a single step */
|
||||
private async runStep(step: WorkflowStep): Promise<{ response: AgentResponse; instruction: string }> {
|
||||
const stepIteration = incrementStepIteration(this.state, step.name);
|
||||
@ -214,6 +242,7 @@ export class WorkflowEngine extends EventEmitter {
|
||||
}
|
||||
|
||||
this.state.stepOutputs.set(step.name, response);
|
||||
this.emitStepReports(step);
|
||||
return { response, instruction };
|
||||
}
|
||||
|
||||
|
||||
@ -43,17 +43,20 @@ export interface ExecutionMetadata {
|
||||
readonly workingDirectory: string;
|
||||
/** Language for metadata rendering */
|
||||
readonly language: Language;
|
||||
/** Whether file editing is allowed for this step (undefined = no prompt) */
|
||||
readonly edit?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build execution metadata from instruction context.
|
||||
* Build execution metadata from instruction context and step config.
|
||||
*
|
||||
* Pure function: InstructionContext → ExecutionMetadata.
|
||||
* Pure function: (InstructionContext, edit?) → ExecutionMetadata.
|
||||
*/
|
||||
export function buildExecutionMetadata(context: InstructionContext): ExecutionMetadata {
|
||||
export function buildExecutionMetadata(context: InstructionContext, edit?: boolean): ExecutionMetadata {
|
||||
return {
|
||||
workingDirectory: context.cwd,
|
||||
language: context.language ?? 'en',
|
||||
edit,
|
||||
};
|
||||
}
|
||||
|
||||
@ -172,6 +175,8 @@ const METADATA_STRINGS = {
|
||||
rulesHeading: '## Execution Rules',
|
||||
noCommit: '**Do NOT run git commit.** Commits are handled automatically by the system after workflow completion.',
|
||||
noCd: '**Do NOT use `cd` in Bash commands.** Your working directory is already set correctly. Run commands directly without changing directories.',
|
||||
editEnabled: '**Editing is ENABLED for this step.** You may create, modify, and delete files as needed to fulfill the user\'s request.',
|
||||
editDisabled: '**Editing is DISABLED for this step.** Do NOT create, modify, or delete any project source files. You may only read/search code and write to report files in the Report Directory.',
|
||||
note: 'Note: This section is metadata. Follow the language used in the rest of the prompt.',
|
||||
},
|
||||
ja: {
|
||||
@ -180,6 +185,8 @@ const METADATA_STRINGS = {
|
||||
rulesHeading: '## 実行ルール',
|
||||
noCommit: '**git commit を実行しないでください。** コミットはワークフロー完了後にシステムが自動で行います。',
|
||||
noCd: '**Bashコマンドで `cd` を使用しないでください。** 作業ディレクトリは既に正しく設定されています。ディレクトリを変更せずにコマンドを実行してください。',
|
||||
editEnabled: '**このステップでは編集が許可されています。** ユーザーの要求に応じて、ファイルの作成・変更・削除を行ってください。',
|
||||
editDisabled: '**このステップでは編集が禁止されています。** プロジェクトのソースファイルを作成・変更・削除しないでください。コードの読み取り・検索と、Report Directoryへのレポート出力のみ行えます。',
|
||||
note: '',
|
||||
},
|
||||
} as const;
|
||||
@ -201,6 +208,11 @@ export function renderExecutionMetadata(metadata: ExecutionMetadata): string {
|
||||
`- ${strings.noCommit}`,
|
||||
`- ${strings.noCd}`,
|
||||
];
|
||||
if (metadata.edit === true) {
|
||||
lines.push(`- ${strings.editEnabled}`);
|
||||
} else if (metadata.edit === false) {
|
||||
lines.push(`- ${strings.editDisabled}`);
|
||||
}
|
||||
if (strings.note) {
|
||||
lines.push('');
|
||||
lines.push(strings.note);
|
||||
@ -219,7 +231,7 @@ function escapeTemplateChars(str: string): string {
|
||||
/**
|
||||
* Check if a report config is the object form (ReportObjectConfig).
|
||||
*/
|
||||
function isReportObjectConfig(report: string | ReportConfig[] | ReportObjectConfig): report is ReportObjectConfig {
|
||||
export function isReportObjectConfig(report: string | ReportConfig[] | ReportObjectConfig): report is ReportObjectConfig {
|
||||
return typeof report === 'object' && !Array.isArray(report) && 'name' in report;
|
||||
}
|
||||
|
||||
@ -384,8 +396,8 @@ export function buildInstruction(
|
||||
const s = SECTION_STRINGS[language];
|
||||
const sections: string[] = [];
|
||||
|
||||
// 1. Execution context metadata (working directory + rules)
|
||||
const metadata = buildExecutionMetadata(context);
|
||||
// 1. Execution context metadata (working directory + rules + edit permission)
|
||||
const metadata = buildExecutionMetadata(context, step.edit);
|
||||
sections.push(renderExecutionMetadata(metadata));
|
||||
|
||||
// 2. Workflow Context (iteration, step, report info)
|
||||
|
||||
@ -13,6 +13,7 @@ import type { PermissionHandler, AskUserQuestionHandler } from '../claude/proces
|
||||
export interface WorkflowEvents {
|
||||
'step:start': (step: WorkflowStep, iteration: number) => void;
|
||||
'step:complete': (step: WorkflowStep, response: AgentResponse, instruction: string) => void;
|
||||
'step:report': (step: WorkflowStep, filePath: string, fileName: string) => void;
|
||||
'step:blocked': (step: WorkflowStep, response: AgentResponse) => void;
|
||||
'step:user_input': (step: WorkflowStep, userInput: string) => void;
|
||||
'workflow:complete': (state: WorkflowState) => void;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user