feat: Builtin管理をバンドル埋め込み方式に移行し、/ejectコマンドを追加 (#4)
- ローダーがユーザーファイル優先、なければdist/resources/からbuiltinを読む方式に変更 - /ejectコマンドを追加(builtinを~/.takt/にコピーしてカスタマイズ可能に) - /refresh-builtinを簡素化(ejectへの移行案内) - config.yamlにdisabled_builtinsフィールドを追加 - ワークフローYAMLをrules形式に統一
This commit is contained in:
parent
dba25a539b
commit
5265cc0059
@ -29,7 +29,7 @@ initial_step: plan
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -89,7 +89,7 @@ steps:
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -144,7 +144,7 @@ steps:
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -194,7 +194,7 @@ steps:
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -224,7 +224,7 @@ steps:
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
format: |
|
||||
@ -275,7 +275,7 @@ steps:
|
||||
|
||||
- name: improve
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -307,7 +307,7 @@ steps:
|
||||
|
||||
- name: fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -334,7 +334,7 @@ steps:
|
||||
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/security-reviewer.md
|
||||
agent: ../agents/default/security-reviewer.md
|
||||
report:
|
||||
name: 05-security-review.md
|
||||
format: |
|
||||
@ -387,7 +387,7 @@ steps:
|
||||
|
||||
- name: security_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -413,7 +413,7 @@ steps:
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
agent: ../agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 06-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
|
||||
@ -32,7 +32,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -89,7 +89,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -146,7 +146,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -196,7 +196,7 @@ steps:
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -228,7 +228,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: cqrs_es_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert-cqrs/cqrs-es-reviewer.md
|
||||
agent: ../agents/expert-cqrs/cqrs-es-reviewer.md
|
||||
report:
|
||||
name: 04-cqrs-es-review.md
|
||||
format: |
|
||||
@ -282,7 +282,7 @@ steps:
|
||||
|
||||
- name: fix_cqrs_es
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -316,7 +316,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
agent: ../agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
format: |
|
||||
@ -370,7 +370,7 @@ steps:
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -404,7 +404,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
agent: ../agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
format: |
|
||||
@ -455,7 +455,7 @@ steps:
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -499,7 +499,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
agent: ../agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
format: |
|
||||
@ -550,7 +550,7 @@ steps:
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -598,7 +598,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
agent: ../agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
@ -691,7 +691,7 @@ steps:
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -44,7 +44,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -101,7 +101,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -158,7 +158,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -208,7 +208,7 @@ steps:
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -240,7 +240,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: architect_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
format: |
|
||||
@ -300,7 +300,7 @@ steps:
|
||||
|
||||
- name: fix_architect
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -330,7 +330,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
agent: ../agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
format: |
|
||||
@ -384,7 +384,7 @@ steps:
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -418,7 +418,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
agent: ../agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
format: |
|
||||
@ -469,7 +469,7 @@ steps:
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -513,7 +513,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
agent: ../agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
format: |
|
||||
@ -564,7 +564,7 @@ steps:
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -612,7 +612,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
agent: ../agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
@ -705,7 +705,7 @@ steps:
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -18,7 +18,7 @@ max_iterations: 5
|
||||
|
||||
steps:
|
||||
- name: melchior
|
||||
agent: ~/.takt/agents/magi/melchior.md
|
||||
agent: ../agents/magi/melchior.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -55,7 +55,7 @@ steps:
|
||||
next: balthasar
|
||||
|
||||
- name: balthasar
|
||||
agent: ~/.takt/agents/magi/balthasar.md
|
||||
agent: ../agents/magi/balthasar.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -97,7 +97,7 @@ steps:
|
||||
next: casper
|
||||
|
||||
- name: casper
|
||||
agent: ~/.takt/agents/magi/casper.md
|
||||
agent: ../agents/magi/casper.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -22,7 +22,7 @@ max_iterations: 10
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
agent: ~/.takt/agents/research/planner.md
|
||||
agent: ../agents/research/planner.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -59,7 +59,7 @@ steps:
|
||||
next: ABORT
|
||||
|
||||
- name: dig
|
||||
agent: ~/.takt/agents/research/digger.md
|
||||
agent: ../agents/research/digger.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -101,7 +101,7 @@ steps:
|
||||
next: ABORT
|
||||
|
||||
- name: supervise
|
||||
agent: ~/.takt/agents/research/supervisor.md
|
||||
agent: ../agents/research/supervisor.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -26,7 +26,7 @@ initial_step: plan
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -82,7 +82,7 @@ steps:
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -137,7 +137,7 @@ steps:
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -187,7 +187,7 @@ steps:
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
format: |
|
||||
@ -239,7 +239,7 @@ steps:
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
agent: ../agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 05-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
|
||||
@ -20,7 +20,7 @@ initial_step: plan
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -80,7 +80,7 @@ steps:
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -140,7 +140,7 @@ steps:
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -190,7 +190,7 @@ steps:
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -220,7 +220,7 @@ steps:
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
format: |
|
||||
@ -282,7 +282,7 @@ steps:
|
||||
|
||||
- name: improve
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -314,7 +314,7 @@ steps:
|
||||
|
||||
- name: fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -340,7 +340,7 @@ steps:
|
||||
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/security-reviewer.md
|
||||
agent: ../agents/default/security-reviewer.md
|
||||
report:
|
||||
name: 05-security-review.md
|
||||
format: |
|
||||
@ -393,7 +393,7 @@ steps:
|
||||
|
||||
- name: security_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -419,7 +419,7 @@ steps:
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
agent: ../agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 06-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
|
||||
@ -41,7 +41,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -98,7 +98,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -155,7 +155,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -205,7 +205,7 @@ steps:
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -237,7 +237,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: cqrs_es_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert-cqrs/cqrs-es-reviewer.md
|
||||
agent: ../agents/expert-cqrs/cqrs-es-reviewer.md
|
||||
report:
|
||||
name: 04-cqrs-es-review.md
|
||||
format: |
|
||||
@ -291,7 +291,7 @@ steps:
|
||||
|
||||
- name: fix_cqrs_es
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -325,7 +325,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
agent: ../agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
format: |
|
||||
@ -379,7 +379,7 @@ steps:
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -413,7 +413,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
agent: ../agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
format: |
|
||||
@ -464,7 +464,7 @@ steps:
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -508,7 +508,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
agent: ../agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
format: |
|
||||
@ -559,7 +559,7 @@ steps:
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -607,7 +607,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
agent: ../agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
@ -700,7 +700,7 @@ steps:
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -32,7 +32,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -89,7 +89,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -146,7 +146,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -196,7 +196,7 @@ steps:
|
||||
|
||||
- name: ai_fix
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -228,7 +228,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: architect_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
format: |
|
||||
@ -288,7 +288,7 @@ steps:
|
||||
|
||||
- name: fix_architect
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -318,7 +318,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: frontend_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/frontend-reviewer.md
|
||||
agent: ../agents/expert/frontend-reviewer.md
|
||||
report:
|
||||
name: 05-frontend-review.md
|
||||
format: |
|
||||
@ -372,7 +372,7 @@ steps:
|
||||
|
||||
- name: fix_frontend
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -406,7 +406,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: security_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/security-reviewer.md
|
||||
agent: ../agents/expert/security-reviewer.md
|
||||
report:
|
||||
name: 06-security-review.md
|
||||
format: |
|
||||
@ -457,7 +457,7 @@ steps:
|
||||
|
||||
- name: fix_security
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -501,7 +501,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: qa_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/qa-reviewer.md
|
||||
agent: ../agents/expert/qa-reviewer.md
|
||||
report:
|
||||
name: 07-qa-review.md
|
||||
format: |
|
||||
@ -552,7 +552,7 @@ steps:
|
||||
|
||||
- name: fix_qa
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -600,7 +600,7 @@ steps:
|
||||
# ===========================================
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/expert/supervisor.md
|
||||
agent: ../agents/expert/supervisor.md
|
||||
report:
|
||||
- Validation: 08-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
@ -693,7 +693,7 @@ steps:
|
||||
|
||||
- name: fix_supervisor
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -18,7 +18,7 @@ max_iterations: 5
|
||||
|
||||
steps:
|
||||
- name: melchior
|
||||
agent: ~/.takt/agents/magi/melchior.md
|
||||
agent: ../agents/magi/melchior.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -55,7 +55,7 @@ steps:
|
||||
next: balthasar
|
||||
|
||||
- name: balthasar
|
||||
agent: ~/.takt/agents/magi/balthasar.md
|
||||
agent: ../agents/magi/balthasar.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -97,7 +97,7 @@ steps:
|
||||
next: casper
|
||||
|
||||
- name: casper
|
||||
agent: ~/.takt/agents/magi/casper.md
|
||||
agent: ../agents/magi/casper.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -22,7 +22,7 @@ max_iterations: 10
|
||||
|
||||
steps:
|
||||
- name: plan
|
||||
agent: ~/.takt/agents/research/planner.md
|
||||
agent: ../agents/research/planner.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -59,7 +59,7 @@ steps:
|
||||
next: ABORT
|
||||
|
||||
- name: dig
|
||||
agent: ~/.takt/agents/research/digger.md
|
||||
agent: ../agents/research/digger.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
@ -101,7 +101,7 @@ steps:
|
||||
next: ABORT
|
||||
|
||||
- name: supervise
|
||||
agent: ~/.takt/agents/research/supervisor.md
|
||||
agent: ../agents/research/supervisor.md
|
||||
allowed_tools:
|
||||
- Read
|
||||
- Glob
|
||||
|
||||
@ -21,7 +21,7 @@ initial_step: plan
|
||||
steps:
|
||||
- name: plan
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/planner.md
|
||||
agent: ../agents/default/planner.md
|
||||
report:
|
||||
name: 00-plan.md
|
||||
format: |
|
||||
@ -81,7 +81,7 @@ steps:
|
||||
|
||||
- name: implement
|
||||
edit: true
|
||||
agent: ~/.takt/agents/default/coder.md
|
||||
agent: ../agents/default/coder.md
|
||||
report:
|
||||
- Scope: 01-coder-scope.md
|
||||
- Decisions: 02-coder-decisions.md
|
||||
@ -136,7 +136,7 @@ steps:
|
||||
|
||||
- name: ai_review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/ai-antipattern-reviewer.md
|
||||
agent: ../agents/default/ai-antipattern-reviewer.md
|
||||
report:
|
||||
name: 03-ai-review.md
|
||||
format: |
|
||||
@ -186,7 +186,7 @@ steps:
|
||||
|
||||
- name: review
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/architecture-reviewer.md
|
||||
agent: ../agents/default/architecture-reviewer.md
|
||||
report:
|
||||
name: 04-architect-review.md
|
||||
format: |
|
||||
@ -238,7 +238,7 @@ steps:
|
||||
|
||||
- name: supervise
|
||||
edit: false
|
||||
agent: ~/.takt/agents/default/supervisor.md
|
||||
agent: ../agents/default/supervisor.md
|
||||
report:
|
||||
- Validation: 05-supervisor-validation.md
|
||||
- Summary: summary.md
|
||||
|
||||
@ -10,11 +10,15 @@ import { randomUUID } from 'node:crypto';
|
||||
import {
|
||||
getBuiltinWorkflow,
|
||||
loadAllWorkflows,
|
||||
loadWorkflow,
|
||||
listWorkflows,
|
||||
loadAgentPromptFromPath,
|
||||
} from '../config/loader.js';
|
||||
import {
|
||||
getCurrentWorkflow,
|
||||
setCurrentWorkflow,
|
||||
getProjectConfigDir,
|
||||
getBuiltinAgentsDir,
|
||||
loadInputHistory,
|
||||
saveInputHistory,
|
||||
addToInputHistory,
|
||||
@ -27,11 +31,17 @@ import {
|
||||
loadWorktreeSessions,
|
||||
updateWorktreeSession,
|
||||
} from '../config/paths.js';
|
||||
import { getLanguage } from '../config/globalConfig.js';
|
||||
import { loadProjectConfig } from '../config/projectConfig.js';
|
||||
|
||||
describe('getBuiltinWorkflow', () => {
|
||||
it('should return null for all workflow names (no built-in workflows)', () => {
|
||||
expect(getBuiltinWorkflow('default')).toBeNull();
|
||||
it('should return builtin workflow when it exists in resources', () => {
|
||||
const workflow = getBuiltinWorkflow('default');
|
||||
expect(workflow).not.toBeNull();
|
||||
expect(workflow!.name).toBe('default');
|
||||
});
|
||||
|
||||
it('should return null for non-existent workflow names', () => {
|
||||
expect(getBuiltinWorkflow('passthrough')).toBeNull();
|
||||
expect(getBuiltinWorkflow('unknown')).toBeNull();
|
||||
expect(getBuiltinWorkflow('')).toBeNull();
|
||||
@ -78,6 +88,65 @@ steps:
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadWorkflow (builtin fallback)', () => {
|
||||
it('should load builtin workflow when user workflow does not exist', () => {
|
||||
const workflow = loadWorkflow('default');
|
||||
expect(workflow).not.toBeNull();
|
||||
expect(workflow!.name).toBe('default');
|
||||
});
|
||||
|
||||
it('should return null for non-existent workflow', () => {
|
||||
const workflow = loadWorkflow('does-not-exist');
|
||||
expect(workflow).toBeNull();
|
||||
});
|
||||
|
||||
it('should load builtin workflows like simple, research', () => {
|
||||
const simple = loadWorkflow('simple');
|
||||
expect(simple).not.toBeNull();
|
||||
expect(simple!.name).toBe('simple');
|
||||
|
||||
const research = loadWorkflow('research');
|
||||
expect(research).not.toBeNull();
|
||||
expect(research!.name).toBe('research');
|
||||
});
|
||||
});
|
||||
|
||||
describe('listWorkflows (builtin fallback)', () => {
|
||||
it('should include builtin workflows', () => {
|
||||
const workflows = listWorkflows();
|
||||
expect(workflows).toContain('default');
|
||||
expect(workflows).toContain('simple');
|
||||
});
|
||||
|
||||
it('should return sorted list', () => {
|
||||
const workflows = listWorkflows();
|
||||
const sorted = [...workflows].sort();
|
||||
expect(workflows).toEqual(sorted);
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadAllWorkflows (builtin fallback)', () => {
|
||||
it('should include builtin workflows in the map', () => {
|
||||
const workflows = loadAllWorkflows();
|
||||
expect(workflows.has('default')).toBe(true);
|
||||
expect(workflows.has('simple')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadAgentPromptFromPath (builtin paths)', () => {
|
||||
it('should load agent prompt from builtin resources path', () => {
|
||||
const lang = getLanguage();
|
||||
const builtinAgentsDir = getBuiltinAgentsDir(lang);
|
||||
const agentPath = join(builtinAgentsDir, 'default', 'coder.md');
|
||||
|
||||
if (existsSync(agentPath)) {
|
||||
const prompt = loadAgentPromptFromPath(agentPath);
|
||||
expect(prompt).toBeTruthy();
|
||||
expect(typeof prompt).toBe('string');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentWorkflow', () => {
|
||||
let testDir: string;
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@ vi.mock('../prompt/index.js', () => ({
|
||||
|
||||
// Import after mocks are set up
|
||||
const { needsLanguageSetup } = await import('../config/initialization.js');
|
||||
const { getGlobalAgentsDir, getGlobalWorkflowsDir } = await import('../config/paths.js');
|
||||
const { copyLanguageResourcesToDir, copyProjectResourcesToDir, getLanguageResourcesDir, getProjectResourcesDir } = await import('../resources/index.js');
|
||||
const { getGlobalConfigPath } = await import('../config/paths.js');
|
||||
const { copyProjectResourcesToDir, getLanguageResourcesDir, getProjectResourcesDir } = await import('../resources/index.js');
|
||||
|
||||
describe('initialization', () => {
|
||||
beforeEach(() => {
|
||||
@ -43,48 +43,17 @@ describe('initialization', () => {
|
||||
});
|
||||
|
||||
describe('needsLanguageSetup', () => {
|
||||
it('should return true when neither agents nor workflows exist', () => {
|
||||
it('should return true when config.yaml does not exist', () => {
|
||||
expect(needsLanguageSetup()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when only agents exists', () => {
|
||||
mkdirSync(getGlobalAgentsDir(), { recursive: true });
|
||||
expect(needsLanguageSetup()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when only workflows exists', () => {
|
||||
mkdirSync(getGlobalWorkflowsDir(), { recursive: true });
|
||||
expect(needsLanguageSetup()).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when both agents and workflows exist', () => {
|
||||
mkdirSync(getGlobalAgentsDir(), { recursive: true });
|
||||
mkdirSync(getGlobalWorkflowsDir(), { recursive: true });
|
||||
it('should return false when config.yaml exists', () => {
|
||||
mkdirSync(testTaktDir, { recursive: true });
|
||||
writeFileSync(getGlobalConfigPath(), 'language: en\n', 'utf-8');
|
||||
expect(needsLanguageSetup()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('copyLanguageResourcesToDir', () => {
|
||||
it('should throw error when language directory does not exist', () => {
|
||||
const nonExistentLang = 'xx' as 'en' | 'ja';
|
||||
expect(() => copyLanguageResourcesToDir(testTaktDir, nonExistentLang)).toThrow(
|
||||
/Language resources not found/
|
||||
);
|
||||
});
|
||||
|
||||
it('should copy language resources to target directory', () => {
|
||||
// This test requires actual language resources to exist
|
||||
const langDir = getLanguageResourcesDir('ja');
|
||||
if (existsSync(langDir)) {
|
||||
mkdirSync(testTaktDir, { recursive: true });
|
||||
copyLanguageResourcesToDir(testTaktDir, 'ja');
|
||||
|
||||
// Verify that agents and workflows directories were created
|
||||
expect(existsSync(join(testTaktDir, 'agents'))).toBe(true);
|
||||
expect(existsSync(join(testTaktDir, 'workflows'))).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('copyProjectResourcesToDir', () => {
|
||||
|
||||
@ -32,6 +32,7 @@ import {
|
||||
switchConfig,
|
||||
addTask,
|
||||
refreshBuiltin,
|
||||
ejectBuiltin,
|
||||
watchTasks,
|
||||
listTasks,
|
||||
} from './commands/index.js';
|
||||
@ -171,6 +172,10 @@ program
|
||||
await refreshBuiltin();
|
||||
return;
|
||||
|
||||
case 'eject':
|
||||
await ejectBuiltin(args[0]);
|
||||
return;
|
||||
|
||||
case 'watch':
|
||||
await watchTasks(cwd);
|
||||
return;
|
||||
@ -182,7 +187,7 @@ program
|
||||
|
||||
default:
|
||||
error(`Unknown command: /${command}`);
|
||||
info('Available: /run-tasks (/run), /watch, /add-task (/add), /list-tasks (/list), /switch (/sw), /clear, /refresh-builtin, /help, /config');
|
||||
info('Available: /run-tasks (/run), /watch, /add-task (/add), /list-tasks (/list), /switch (/sw), /clear, /eject, /help, /config');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
124
src/commands/eject.ts
Normal file
124
src/commands/eject.ts
Normal file
@ -0,0 +1,124 @@
|
||||
/**
|
||||
* /eject command implementation
|
||||
*
|
||||
* Copies a builtin workflow (and its agents) to ~/.takt/ for user customization.
|
||||
* Once ejected, the user copy takes priority over the builtin version.
|
||||
*/
|
||||
|
||||
import { existsSync, readdirSync, statSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
||||
import { join, basename, dirname } from 'node:path';
|
||||
import { getGlobalWorkflowsDir, getGlobalAgentsDir, getBuiltinWorkflowsDir, getBuiltinAgentsDir } from '../config/paths.js';
|
||||
import { getLanguage } from '../config/globalConfig.js';
|
||||
import { header, success, info, warn, error } from '../utils/ui.js';
|
||||
|
||||
/**
|
||||
* Eject a builtin workflow to user space for customization.
|
||||
* Copies the workflow YAML and related agent .md files to ~/.takt/.
|
||||
* Agent paths in the ejected workflow are rewritten from ../agents/ to ~/.takt/agents/.
|
||||
*/
|
||||
export async function ejectBuiltin(name?: string): Promise<void> {
|
||||
header('Eject Builtin');
|
||||
|
||||
const lang = getLanguage();
|
||||
const builtinWorkflowsDir = getBuiltinWorkflowsDir(lang);
|
||||
|
||||
if (!name) {
|
||||
// List available builtins
|
||||
listAvailableBuiltins(builtinWorkflowsDir);
|
||||
return;
|
||||
}
|
||||
|
||||
const builtinPath = join(builtinWorkflowsDir, `${name}.yaml`);
|
||||
if (!existsSync(builtinPath)) {
|
||||
error(`Builtin workflow not found: ${name}`);
|
||||
info('Run "takt /eject" to see available builtins.');
|
||||
return;
|
||||
}
|
||||
|
||||
const userWorkflowsDir = getGlobalWorkflowsDir();
|
||||
const userAgentsDir = getGlobalAgentsDir();
|
||||
const builtinAgentsDir = getBuiltinAgentsDir(lang);
|
||||
|
||||
// Copy workflow YAML (rewrite agent paths)
|
||||
const workflowDest = join(userWorkflowsDir, `${name}.yaml`);
|
||||
if (existsSync(workflowDest)) {
|
||||
warn(`User workflow already exists: ${workflowDest}`);
|
||||
warn('Skipping workflow copy (user version takes priority).');
|
||||
} else {
|
||||
mkdirSync(dirname(workflowDest), { recursive: true });
|
||||
const content = readFileSync(builtinPath, 'utf-8');
|
||||
// Rewrite relative agent paths to ~/.takt/agents/
|
||||
const rewritten = content.replace(
|
||||
/agent:\s*\.\.\/agents\//g,
|
||||
'agent: ~/.takt/agents/',
|
||||
);
|
||||
writeFileSync(workflowDest, rewritten, 'utf-8');
|
||||
success(`Ejected workflow: ${workflowDest}`);
|
||||
}
|
||||
|
||||
// Copy related agent files
|
||||
const agentPaths = extractAgentRelativePaths(builtinPath);
|
||||
let copiedAgents = 0;
|
||||
|
||||
for (const relPath of agentPaths) {
|
||||
const srcPath = join(builtinAgentsDir, relPath);
|
||||
const destPath = join(userAgentsDir, relPath);
|
||||
|
||||
if (!existsSync(srcPath)) continue;
|
||||
|
||||
if (existsSync(destPath)) {
|
||||
info(` Agent already exists: ${destPath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
mkdirSync(dirname(destPath), { recursive: true });
|
||||
writeFileSync(destPath, readFileSync(srcPath));
|
||||
info(` ✓ ${destPath}`);
|
||||
copiedAgents++;
|
||||
}
|
||||
|
||||
if (copiedAgents > 0) {
|
||||
success(`${copiedAgents} agent file(s) ejected.`);
|
||||
}
|
||||
}
|
||||
|
||||
/** List available builtin workflows for ejection */
|
||||
function listAvailableBuiltins(builtinWorkflowsDir: string): void {
|
||||
if (!existsSync(builtinWorkflowsDir)) {
|
||||
warn('No builtin workflows found.');
|
||||
return;
|
||||
}
|
||||
|
||||
info('Available builtin workflows:');
|
||||
console.log();
|
||||
|
||||
for (const entry of readdirSync(builtinWorkflowsDir).sort()) {
|
||||
if (!entry.endsWith('.yaml') && !entry.endsWith('.yml')) continue;
|
||||
if (!statSync(join(builtinWorkflowsDir, entry)).isFile()) continue;
|
||||
|
||||
const name = entry.replace(/\.ya?ml$/, '');
|
||||
info(` ${name}`);
|
||||
}
|
||||
|
||||
console.log();
|
||||
info('Usage: takt /eject {name}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract agent relative paths from a builtin workflow YAML.
|
||||
* Matches `agent: ../agents/{path}` and returns the {path} portions.
|
||||
*/
|
||||
function extractAgentRelativePaths(workflowPath: string): string[] {
|
||||
const content = readFileSync(workflowPath, 'utf-8');
|
||||
const paths = new Set<string>();
|
||||
const regex = /agent:\s*\.\.\/agents\/(.+)/g;
|
||||
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = regex.exec(content)) !== null) {
|
||||
if (match[1]) {
|
||||
paths.add(match[1].trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(paths);
|
||||
}
|
||||
@ -21,7 +21,8 @@ Usage:
|
||||
takt /list-tasks (/list) List task branches (merge/delete)
|
||||
takt /switch Switch workflow interactively
|
||||
takt /clear Clear agent conversation sessions (reset to initial state)
|
||||
takt /refresh-builtin Overwrite builtin agents/workflows with latest version
|
||||
takt /eject Copy builtin workflow/agents to ~/.takt/ for customization
|
||||
takt /eject {name} Eject a specific builtin workflow
|
||||
takt /help Show this help
|
||||
|
||||
Examples:
|
||||
@ -34,7 +35,8 @@ Examples:
|
||||
takt /add-task # Interactive task creation
|
||||
takt /clear # Clear sessions, start fresh
|
||||
takt /watch # Watch & auto-execute tasks
|
||||
takt /refresh-builtin # Update builtin resources
|
||||
takt /eject # List available builtins
|
||||
takt /eject default # Eject default workflow for customization
|
||||
takt /list-tasks # List & merge task branches
|
||||
takt /switch
|
||||
takt /run-tasks
|
||||
|
||||
@ -6,6 +6,7 @@ export { executeWorkflow, type WorkflowExecutionResult, type WorkflowExecutionOp
|
||||
export { executeTask, runAllTasks } from './taskExecution.js';
|
||||
export { addTask } from './addTask.js';
|
||||
export { refreshBuiltin } from './refreshBuiltin.js';
|
||||
export { ejectBuiltin } from './eject.js';
|
||||
export { watchTasks } from './watchTasks.js';
|
||||
export { showHelp } from './help.js';
|
||||
export { withAgentSession } from './session.js';
|
||||
|
||||
@ -1,43 +1,22 @@
|
||||
/**
|
||||
* /refresh-builtin command implementation
|
||||
* /refresh-builtin command — DEPRECATED
|
||||
*
|
||||
* Overwrites builtin workflow and agent files in ~/.takt/ with the latest
|
||||
* embedded resources. Does NOT touch config.yaml or user-added files.
|
||||
* Builtin resources are now loaded directly from the package bundle.
|
||||
* Use /eject to copy individual builtins to ~/.takt/ for customization.
|
||||
*/
|
||||
|
||||
import { getGlobalConfigDir } from '../config/paths.js';
|
||||
import { getLanguage } from '../config/globalConfig.js';
|
||||
import { forceRefreshLanguageResources } from '../resources/index.js';
|
||||
import { header, success, info, error } from '../utils/ui.js';
|
||||
import { createLogger } from '../utils/debug.js';
|
||||
|
||||
const log = createLogger('refresh-builtin');
|
||||
import { warn, info } from '../utils/ui.js';
|
||||
|
||||
/**
|
||||
* Refresh builtin agents and workflows to latest version.
|
||||
* Show deprecation notice and guide user to /eject.
|
||||
*/
|
||||
export async function refreshBuiltin(): Promise<void> {
|
||||
const globalDir = getGlobalConfigDir();
|
||||
const lang = getLanguage();
|
||||
|
||||
header('Refresh Builtin Resources');
|
||||
info(`Language: ${lang}`);
|
||||
info(`Target: ${globalDir}`);
|
||||
|
||||
try {
|
||||
const overwritten = forceRefreshLanguageResources(globalDir, lang);
|
||||
|
||||
log.info('Builtin resources refreshed', { count: overwritten.length, lang });
|
||||
|
||||
console.log();
|
||||
success(`${overwritten.length} files refreshed.`);
|
||||
|
||||
for (const filePath of overwritten) {
|
||||
info(` ✓ ${filePath}`);
|
||||
}
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
log.error('Failed to refresh builtin resources', { error: message });
|
||||
error(`Failed to refresh: ${message}`);
|
||||
}
|
||||
warn('/refresh-builtin is deprecated.');
|
||||
console.log();
|
||||
info('Builtin workflows and agents are now loaded directly from the package.');
|
||||
info('They no longer need to be copied to ~/.takt/.');
|
||||
console.log();
|
||||
info('To customize a builtin, use:');
|
||||
info(' takt /eject List available builtins');
|
||||
info(' takt /eject {name} Copy a builtin to ~/.takt/ for editing');
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
/**
|
||||
* Agent configuration loader
|
||||
*
|
||||
* Loads agents from ~/.takt/agents/ directory only.
|
||||
* Loads agents with user → builtin fallback:
|
||||
* 1. User agents: ~/.takt/agents/*.md
|
||||
* 2. Builtin agents: resources/global/{lang}/agents/*.md
|
||||
*/
|
||||
|
||||
import { readFileSync, existsSync, readdirSync } from 'node:fs';
|
||||
@ -10,8 +12,22 @@ import type { CustomAgentConfig } from '../models/types.js';
|
||||
import {
|
||||
getGlobalAgentsDir,
|
||||
getGlobalWorkflowsDir,
|
||||
getBuiltinAgentsDir,
|
||||
getBuiltinWorkflowsDir,
|
||||
isPathSafe,
|
||||
} from './paths.js';
|
||||
import { getLanguage } from './globalConfig.js';
|
||||
|
||||
/** Get all allowed base directories for agent prompt files */
|
||||
function getAllowedAgentBases(): string[] {
|
||||
const lang = getLanguage();
|
||||
return [
|
||||
getGlobalAgentsDir(),
|
||||
getGlobalWorkflowsDir(),
|
||||
getBuiltinAgentsDir(lang),
|
||||
getBuiltinWorkflowsDir(lang),
|
||||
];
|
||||
}
|
||||
|
||||
/** Load agents from markdown files in a directory */
|
||||
export function loadAgentsFromDir(dirPath: string): CustomAgentConfig[] {
|
||||
@ -61,19 +77,7 @@ export function loadAgentPrompt(agent: CustomAgentConfig): string {
|
||||
}
|
||||
|
||||
if (agent.promptFile) {
|
||||
const allowedBases = [
|
||||
getGlobalAgentsDir(),
|
||||
getGlobalWorkflowsDir(),
|
||||
];
|
||||
|
||||
let isValid = false;
|
||||
for (const base of allowedBases) {
|
||||
if (isPathSafe(base, agent.promptFile)) {
|
||||
isValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const isValid = getAllowedAgentBases().some((base) => isPathSafe(base, agent.promptFile!));
|
||||
if (!isValid) {
|
||||
throw new Error(`Agent prompt file path is not allowed: ${agent.promptFile}`);
|
||||
}
|
||||
@ -93,19 +97,7 @@ export function loadAgentPrompt(agent: CustomAgentConfig): string {
|
||||
* Used by workflow engine when agentPath is already resolved.
|
||||
*/
|
||||
export function loadAgentPromptFromPath(agentPath: string): string {
|
||||
const allowedBases = [
|
||||
getGlobalAgentsDir(),
|
||||
getGlobalWorkflowsDir(),
|
||||
];
|
||||
|
||||
let isValid = false;
|
||||
for (const base of allowedBases) {
|
||||
if (isPathSafe(base, agentPath)) {
|
||||
isValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const isValid = getAllowedAgentBases().some((base) => isPathSafe(base, agentPath));
|
||||
if (!isValid) {
|
||||
throw new Error(`Agent prompt file path is not allowed: ${agentPath}`);
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ export function loadGlobalConfig(): GlobalConfig {
|
||||
logFile: parsed.debug.log_file,
|
||||
} : undefined,
|
||||
worktreeDir: parsed.worktree_dir,
|
||||
disabledBuiltins: parsed.disabled_builtins,
|
||||
};
|
||||
}
|
||||
|
||||
@ -61,9 +62,22 @@ export function saveGlobalConfig(config: GlobalConfig): void {
|
||||
if (config.worktreeDir) {
|
||||
raw.worktree_dir = config.worktreeDir;
|
||||
}
|
||||
if (config.disabledBuiltins && config.disabledBuiltins.length > 0) {
|
||||
raw.disabled_builtins = config.disabledBuiltins;
|
||||
}
|
||||
writeFileSync(configPath, stringifyYaml(raw), 'utf-8');
|
||||
}
|
||||
|
||||
/** Get list of disabled builtin names */
|
||||
export function getDisabledBuiltins(): string[] {
|
||||
try {
|
||||
const config = loadGlobalConfig();
|
||||
return config.disabledBuiltins ?? [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/** Get current language setting */
|
||||
export function getLanguage(): Language {
|
||||
try {
|
||||
|
||||
@ -1,37 +1,32 @@
|
||||
/**
|
||||
* Initialization module for first-time setup
|
||||
*
|
||||
* Handles language selection and initial resource setup.
|
||||
* Separated from paths.ts to avoid UI dependencies in utility modules.
|
||||
* Handles language selection and initial config.yaml creation.
|
||||
* Builtin agents/workflows are loaded via fallback from resources/
|
||||
* and no longer copied to ~/.takt/ on setup.
|
||||
*/
|
||||
|
||||
import { existsSync } from 'node:fs';
|
||||
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import type { Language } from '../models/types.js';
|
||||
import { DEFAULT_LANGUAGE } from '../constants.js';
|
||||
import { selectOptionWithDefault } from '../prompt/index.js';
|
||||
import {
|
||||
getGlobalConfigDir,
|
||||
getGlobalAgentsDir,
|
||||
getGlobalWorkflowsDir,
|
||||
getGlobalConfigPath,
|
||||
getGlobalLogsDir,
|
||||
getProjectConfigDir,
|
||||
ensureDir,
|
||||
} from './paths.js';
|
||||
import {
|
||||
copyGlobalResourcesToDir,
|
||||
copyLanguageResourcesToDir,
|
||||
copyProjectResourcesToDir,
|
||||
} from '../resources/index.js';
|
||||
import { copyProjectResourcesToDir, getLanguageResourcesDir } from '../resources/index.js';
|
||||
import { setLanguage, setProvider } from './globalConfig.js';
|
||||
|
||||
/**
|
||||
* Check if language-specific resources need to be initialized.
|
||||
* Returns true if agents or workflows directories don't exist.
|
||||
* Check if initial setup is needed.
|
||||
* Returns true if config.yaml doesn't exist yet.
|
||||
*/
|
||||
export function needsLanguageSetup(): boolean {
|
||||
const agentsDir = getGlobalAgentsDir();
|
||||
const workflowsDir = getGlobalWorkflowsDir();
|
||||
return !existsSync(agentsDir) || !existsSync(workflowsDir);
|
||||
return !existsSync(getGlobalConfigPath());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,29 +78,32 @@ export async function promptProviderSelection(): Promise<'claude' | 'codex'> {
|
||||
|
||||
/**
|
||||
* Initialize global takt directory structure with language selection.
|
||||
* If agents/workflows don't exist, prompts user for language preference.
|
||||
* On first run, creates config.yaml from language template.
|
||||
* Agents/workflows are NOT copied — they are loaded via builtin fallback.
|
||||
*/
|
||||
export async function initGlobalDirs(): Promise<void> {
|
||||
ensureDir(getGlobalConfigDir());
|
||||
ensureDir(getGlobalLogsDir());
|
||||
|
||||
// Check if we need to set up language-specific resources
|
||||
const needsSetup = needsLanguageSetup();
|
||||
|
||||
if (needsSetup) {
|
||||
// Ask user for language preference
|
||||
if (needsLanguageSetup()) {
|
||||
const lang = await promptLanguageSelection();
|
||||
const provider = await promptProviderSelection();
|
||||
|
||||
// Copy language-specific resources (agents, workflows, config.yaml)
|
||||
copyLanguageResourcesToDir(getGlobalConfigDir(), lang);
|
||||
// Copy only config.yaml from language resources
|
||||
copyLanguageConfigYaml(lang);
|
||||
|
||||
// Explicitly save the selected language (handles case where config.yaml existed)
|
||||
setLanguage(lang);
|
||||
setProvider(provider);
|
||||
} else {
|
||||
// Just copy base global resources (won't overwrite existing)
|
||||
copyGlobalResourcesToDir(getGlobalConfigDir());
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy config.yaml from language resources to ~/.takt/ (if not already present) */
|
||||
function copyLanguageConfigYaml(lang: Language): void {
|
||||
const langDir = getLanguageResourcesDir(lang);
|
||||
const srcPath = join(langDir, 'config.yaml');
|
||||
const destPath = getGlobalConfigPath();
|
||||
if (existsSync(srcPath) && !existsSync(destPath)) {
|
||||
writeFileSync(destPath, readFileSync(srcPath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
import { homedir } from 'node:os';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { existsSync, mkdirSync } from 'node:fs';
|
||||
import type { Language } from '../models/types.js';
|
||||
import { getLanguageResourcesDir } from '../resources/index.js';
|
||||
|
||||
/** Get takt global config directory (~/.takt) */
|
||||
export function getGlobalConfigDir(): string {
|
||||
@ -34,6 +36,16 @@ export function getGlobalConfigPath(): string {
|
||||
return join(getGlobalConfigDir(), 'config.yaml');
|
||||
}
|
||||
|
||||
/** Get builtin workflows directory (resources/global/{lang}/workflows) */
|
||||
export function getBuiltinWorkflowsDir(lang: Language): string {
|
||||
return join(getLanguageResourcesDir(lang), 'workflows');
|
||||
}
|
||||
|
||||
/** Get builtin agents directory (resources/global/{lang}/agents) */
|
||||
export function getBuiltinAgentsDir(lang: Language): string {
|
||||
return join(getLanguageResourcesDir(lang), 'agents');
|
||||
}
|
||||
|
||||
/** Get project takt config directory (.takt in project) */
|
||||
export function getProjectConfigDir(projectDir: string): string {
|
||||
return join(resolve(projectDir), '.takt');
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
/**
|
||||
* Workflow configuration loader
|
||||
*
|
||||
* Loads workflows from ~/.takt/workflows/ directory only.
|
||||
* Loads workflows with user → builtin fallback:
|
||||
* 1. User workflows: ~/.takt/workflows/{name}.yaml
|
||||
* 2. Builtin workflows: resources/global/{lang}/workflows/{name}.yaml
|
||||
*/
|
||||
|
||||
import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
||||
@ -9,12 +11,20 @@ import { join, dirname, basename } from 'node:path';
|
||||
import { parse as parseYaml } from 'yaml';
|
||||
import { WorkflowConfigRawSchema } from '../models/schemas.js';
|
||||
import type { WorkflowConfig, WorkflowStep, WorkflowRule, ReportConfig, ReportObjectConfig } from '../models/types.js';
|
||||
import { getGlobalWorkflowsDir } from './paths.js';
|
||||
import { getGlobalWorkflowsDir, getBuiltinWorkflowsDir } from './paths.js';
|
||||
import { getLanguage, getDisabledBuiltins } from './globalConfig.js';
|
||||
|
||||
/** Get builtin workflow by name */
|
||||
export function getBuiltinWorkflow(name: string): WorkflowConfig | null {
|
||||
// No built-in workflows - all workflows must be defined in ~/.takt/workflows/
|
||||
void name;
|
||||
const lang = getLanguage();
|
||||
const disabled = getDisabledBuiltins();
|
||||
if (disabled.includes(name)) return null;
|
||||
|
||||
const builtinDir = getBuiltinWorkflowsDir(lang);
|
||||
const yamlPath = join(builtinDir, `${name}.yaml`);
|
||||
if (existsSync(yamlPath)) {
|
||||
return loadWorkflowFromFile(yamlPath);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -231,24 +241,47 @@ export function loadWorkflowFromFile(filePath: string): WorkflowConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load workflow by name from global directory.
|
||||
* Looks for ~/.takt/workflows/{name}.yaml
|
||||
* Load workflow by name.
|
||||
* Priority: user (~/.takt/workflows/) → builtin (resources/global/{lang}/workflows/)
|
||||
*/
|
||||
export function loadWorkflow(name: string): WorkflowConfig | null {
|
||||
// 1. User workflow
|
||||
const globalWorkflowsDir = getGlobalWorkflowsDir();
|
||||
const workflowYamlPath = join(globalWorkflowsDir, `${name}.yaml`);
|
||||
|
||||
if (existsSync(workflowYamlPath)) {
|
||||
return loadWorkflowFromFile(workflowYamlPath);
|
||||
}
|
||||
return null;
|
||||
|
||||
// 2. Builtin fallback
|
||||
return getBuiltinWorkflow(name);
|
||||
}
|
||||
|
||||
/** Load all workflows with descriptions (for switch command) */
|
||||
export function loadAllWorkflows(): Map<string, WorkflowConfig> {
|
||||
const workflows = new Map<string, WorkflowConfig>();
|
||||
const disabled = getDisabledBuiltins();
|
||||
|
||||
// Global workflows (~/.takt/workflows/{name}.yaml)
|
||||
// 1. Builtin workflows (lower priority — will be overridden by user)
|
||||
const lang = getLanguage();
|
||||
const builtinDir = getBuiltinWorkflowsDir(lang);
|
||||
if (existsSync(builtinDir)) {
|
||||
for (const entry of readdirSync(builtinDir)) {
|
||||
if (!entry.endsWith('.yaml') && !entry.endsWith('.yml')) continue;
|
||||
|
||||
const entryPath = join(builtinDir, entry);
|
||||
if (statSync(entryPath).isFile()) {
|
||||
const workflowName = entry.replace(/\.ya?ml$/, '');
|
||||
if (disabled.includes(workflowName)) continue;
|
||||
try {
|
||||
workflows.set(workflowName, loadWorkflowFromFile(entryPath));
|
||||
} catch {
|
||||
// Skip invalid workflows
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. User workflows (higher priority — overrides builtins)
|
||||
const globalWorkflowsDir = getGlobalWorkflowsDir();
|
||||
if (existsSync(globalWorkflowsDir)) {
|
||||
for (const entry of readdirSync(globalWorkflowsDir)) {
|
||||
@ -270,22 +303,34 @@ export function loadAllWorkflows(): Map<string, WorkflowConfig> {
|
||||
return workflows;
|
||||
}
|
||||
|
||||
/** List available workflows from global directory (~/.takt/workflows/) */
|
||||
/** List available workflows (user + builtin, excluding disabled) */
|
||||
export function listWorkflows(): string[] {
|
||||
const workflows = new Set<string>();
|
||||
const disabled = getDisabledBuiltins();
|
||||
|
||||
// 1. Builtin workflows
|
||||
const lang = getLanguage();
|
||||
const builtinDir = getBuiltinWorkflowsDir(lang);
|
||||
scanWorkflowDir(builtinDir, workflows, disabled);
|
||||
|
||||
// 2. User workflows
|
||||
const globalWorkflowsDir = getGlobalWorkflowsDir();
|
||||
if (existsSync(globalWorkflowsDir)) {
|
||||
for (const entry of readdirSync(globalWorkflowsDir)) {
|
||||
if (!entry.endsWith('.yaml') && !entry.endsWith('.yml')) continue;
|
||||
|
||||
const entryPath = join(globalWorkflowsDir, entry);
|
||||
if (statSync(entryPath).isFile()) {
|
||||
const workflowName = entry.replace(/\.ya?ml$/, '');
|
||||
workflows.add(workflowName);
|
||||
}
|
||||
}
|
||||
}
|
||||
scanWorkflowDir(globalWorkflowsDir, workflows);
|
||||
|
||||
return Array.from(workflows).sort();
|
||||
}
|
||||
|
||||
/** Scan a directory for .yaml/.yml files and add names to the set */
|
||||
function scanWorkflowDir(dir: string, target: Set<string>, disabled?: string[]): void {
|
||||
if (!existsSync(dir)) return;
|
||||
for (const entry of readdirSync(dir)) {
|
||||
if (!entry.endsWith('.yaml') && !entry.endsWith('.yml')) continue;
|
||||
|
||||
const entryPath = join(dir, entry);
|
||||
if (statSync(entryPath).isFile()) {
|
||||
const workflowName = entry.replace(/\.ya?ml$/, '');
|
||||
if (disabled?.includes(workflowName)) continue;
|
||||
target.add(workflowName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,6 +170,8 @@ export const GlobalConfigSchema = z.object({
|
||||
debug: DebugConfigSchema.optional(),
|
||||
/** Directory for shared clones (worktree_dir in config). If empty, uses ../{clone-name} relative to project */
|
||||
worktree_dir: z.string().optional(),
|
||||
/** List of builtin workflow/agent names to exclude from fallback loading */
|
||||
disabled_builtins: z.array(z.string()).optional().default([]),
|
||||
});
|
||||
|
||||
/** Project config schema */
|
||||
|
||||
@ -189,6 +189,8 @@ export interface GlobalConfig {
|
||||
debug?: DebugConfig;
|
||||
/** Directory for shared clones (worktree_dir in config). If empty, uses ../{clone-name} relative to project */
|
||||
worktreeDir?: string;
|
||||
/** List of builtin workflow/agent names to exclude from fallback loading */
|
||||
disabledBuiltins?: string[];
|
||||
}
|
||||
|
||||
/** Project-level configuration */
|
||||
|
||||
@ -3,9 +3,9 @@
|
||||
*
|
||||
* Contains default workflow definitions and resource paths.
|
||||
* Resources are organized into:
|
||||
* - resources/global/ - Files to copy to ~/.takt
|
||||
* - resources/global/en/ - English resources
|
||||
* - resources/global/ja/ - Japanese resources
|
||||
* - resources/global/{lang}/workflows/ - Builtin workflows (loaded via fallback)
|
||||
* - resources/global/{lang}/agents/ - Builtin agents (loaded via fallback)
|
||||
* - resources/project/ - Project-level template files (.gitignore)
|
||||
*/
|
||||
|
||||
import { readFileSync, readdirSync, existsSync, statSync, mkdirSync, writeFileSync } from 'fs';
|
||||
@ -44,20 +44,6 @@ export function getLanguageResourcesDir(lang: Language): string {
|
||||
return join(getGlobalResourcesDir(), lang);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy global resources directory to ~/.takt.
|
||||
* Only copies files that don't exist in target.
|
||||
* Skips language-specific directories (en/, ja/) which are handled by copyLanguageResourcesToDir.
|
||||
*/
|
||||
export function copyGlobalResourcesToDir(targetDir: string): void {
|
||||
const resourcesDir = getGlobalResourcesDir();
|
||||
if (!existsSync(resourcesDir)) {
|
||||
return;
|
||||
}
|
||||
// Skip language directories (they are handled by copyLanguageResourcesToDir)
|
||||
copyDirRecursive(resourcesDir, targetDir, { skipDirs: ['en', 'ja'] });
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy project resources directory to .takt in project.
|
||||
* Only copies files that don't exist in target (e.g., .gitignore).
|
||||
@ -72,72 +58,6 @@ export function copyProjectResourcesToDir(targetDir: string): void {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy language-specific resources (agents and workflows) to ~/.takt.
|
||||
* Copies from resources/global/{lang}/agents to ~/.takt/agents
|
||||
* and resources/global/{lang}/workflows to ~/.takt/workflows.
|
||||
* Also copies config.yaml from language directory.
|
||||
* @throws Error if language directory doesn't exist
|
||||
*/
|
||||
export function copyLanguageResourcesToDir(targetDir: string, lang: Language): void {
|
||||
const langDir = getLanguageResourcesDir(lang);
|
||||
if (!existsSync(langDir)) {
|
||||
throw new Error(`Language resources not found: ${langDir}`);
|
||||
}
|
||||
|
||||
// Copy agents directory
|
||||
const langAgentsDir = join(langDir, 'agents');
|
||||
const targetAgentsDir = join(targetDir, 'agents');
|
||||
if (existsSync(langAgentsDir)) {
|
||||
copyDirRecursive(langAgentsDir, targetAgentsDir);
|
||||
}
|
||||
|
||||
// Copy workflows directory
|
||||
const langWorkflowsDir = join(langDir, 'workflows');
|
||||
const targetWorkflowsDir = join(targetDir, 'workflows');
|
||||
if (existsSync(langWorkflowsDir)) {
|
||||
copyDirRecursive(langWorkflowsDir, targetWorkflowsDir);
|
||||
}
|
||||
|
||||
// Copy config.yaml if exists
|
||||
const langConfigPath = join(langDir, 'config.yaml');
|
||||
const targetConfigPath = join(targetDir, 'config.yaml');
|
||||
if (existsSync(langConfigPath) && !existsSync(targetConfigPath)) {
|
||||
const content = readFileSync(langConfigPath);
|
||||
writeFileSync(targetConfigPath, content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force-refresh language-specific resources (agents and workflows) to ~/.takt.
|
||||
* Overwrites existing builtin files. Does NOT touch config.yaml.
|
||||
*/
|
||||
export function forceRefreshLanguageResources(targetDir: string, lang: Language): string[] {
|
||||
const langDir = getLanguageResourcesDir(lang);
|
||||
if (!existsSync(langDir)) {
|
||||
throw new Error(`Language resources not found: ${langDir}`);
|
||||
}
|
||||
|
||||
const copiedFiles: string[] = [];
|
||||
const forceOptions = { overwrite: true, copiedFiles };
|
||||
|
||||
// Overwrite agents directory
|
||||
const langAgentsDir = join(langDir, 'agents');
|
||||
const targetAgentsDir = join(targetDir, 'agents');
|
||||
if (existsSync(langAgentsDir)) {
|
||||
copyDirRecursive(langAgentsDir, targetAgentsDir, forceOptions);
|
||||
}
|
||||
|
||||
// Overwrite workflows directory
|
||||
const langWorkflowsDir = join(langDir, 'workflows');
|
||||
const targetWorkflowsDir = join(targetDir, 'workflows');
|
||||
if (existsSync(langWorkflowsDir)) {
|
||||
copyDirRecursive(langWorkflowsDir, targetWorkflowsDir, forceOptions);
|
||||
}
|
||||
|
||||
return copiedFiles;
|
||||
}
|
||||
|
||||
/** Files to skip during resource copy (OS-generated files) */
|
||||
const SKIP_FILES = ['.DS_Store', 'Thumbs.db'];
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user