create-squirrel-opencode-harness 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/agents/evaluator.md +21 -21
- package/agents/generator.md +24 -23
- package/agents/harness.md +54 -42
- package/dist/cli.js +8 -9
- package/dist/cli.js.map +3 -3
- package/dist/fileOps.js +34 -53
- package/dist/fileOps.js.map +2 -2
- package/package.json +1 -1
- package/harness/templates/contract-template.md +0 -18
- package/harness/templates/evaluation-template.md +0 -39
- package/harness/templates/final-summary-template.md +0 -16
- package/harness/templates/handoff-template.md +0 -14
- package/harness/templates/self-eval-template.md +0 -14
- package/harness/templates/spec-template.md +0 -53
- package/harness/templates/sprint-status-template.md +0 -8
package/README.md
CHANGED
|
@@ -149,6 +149,18 @@ Options:
|
|
|
149
149
|
|
|
150
150
|
Once the harness is scaffolded, follow these steps to start working:
|
|
151
151
|
|
|
152
|
+
### Workflow Overview
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# 1. Run in your project directory
|
|
156
|
+
npm create squirrel-opencode-harness "your-model-id"
|
|
157
|
+
|
|
158
|
+
# 2. Start opencode
|
|
159
|
+
opencode
|
|
160
|
+
|
|
161
|
+
# 3. Press Tab to switch to the agent named "harness" and start collaborating
|
|
162
|
+
```
|
|
163
|
+
|
|
152
164
|
### 1. Start Opencode
|
|
153
165
|
|
|
154
166
|
```bash
|
|
@@ -369,6 +381,18 @@ create-squirrel-opencode-harness "模型id" --lang zh
|
|
|
369
381
|
|
|
370
382
|
脚手架搭建完成后,按以下步骤开始工作:
|
|
371
383
|
|
|
384
|
+
### 工作流程概览
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
# 1. 在项目目录运行创建命令
|
|
388
|
+
npm create squirrel-opencode-harness "your-model-id"
|
|
389
|
+
|
|
390
|
+
# 2. 启动 opencode
|
|
391
|
+
opencode
|
|
392
|
+
|
|
393
|
+
# 3. 按 Tab 键切换到名叫 "harness" 的 agent 开始协作
|
|
394
|
+
```
|
|
395
|
+
|
|
372
396
|
### 1. 启动 Opencode
|
|
373
397
|
|
|
374
398
|
```bash
|
package/agents/evaluator.md
CHANGED
|
@@ -7,7 +7,7 @@ model: <%= model %>
|
|
|
7
7
|
|
|
8
8
|
# Evaluator Agent
|
|
9
9
|
|
|
10
|
-
You are the Evaluator agent in a multi-agent harness system. Your role is to critically evaluate the Generator's work by interacting with the running application, identifying bugs and quality gaps, and providing detailed, actionable feedback. You are the quality gate — be skeptical, thorough, and precise.
|
|
10
|
+
You are the Evaluator agent in a multi-agent harness system. Your role is to critically evaluate the Generator's work by interacting with the running application, identifying bugs and quality gaps, and providing detailed, actionable feedback. You are the quality gate — be skeptical, thorough, and precise. Each sprint has its own directory under `harness/sprints/sprint-N/` where all sprint-specific artifacts are stored.
|
|
11
11
|
|
|
12
12
|
## Inter-Agent Communication
|
|
13
13
|
|
|
@@ -23,11 +23,11 @@ You can be invoked in three ways:
|
|
|
23
23
|
| File | Purpose | Written By |
|
|
24
24
|
|------|---------|------------|
|
|
25
25
|
| `harness/spec.md` | Full product specification | Planner |
|
|
26
|
-
| `harness/contract.md` | Current sprint contract | Generator |
|
|
27
|
-
| `harness/contract-accepted.md` | Your own acceptance of the contract | Evaluator (you) |
|
|
28
|
-
| `harness/self-eval.md` | Generator's self-evaluation | Generator |
|
|
29
|
-
| `harness/handoff.md` | Generator's handoff instructions | Generator |
|
|
30
|
-
| `harness/evaluation.md` | Your own previous evaluations (for re-evaluation) | Evaluator (you) |
|
|
26
|
+
| `harness/sprints/sprint-N/contract.md` | Current sprint contract | Generator |
|
|
27
|
+
| `harness/sprints/sprint-N/contract-accepted.md` | Your own acceptance of the contract | Evaluator (you) |
|
|
28
|
+
| `harness/sprints/sprint-N/self-eval.md` | Generator's self-evaluation | Generator |
|
|
29
|
+
| `harness/sprints/sprint-N/handoff.md` | Generator's handoff instructions | Generator |
|
|
30
|
+
| `harness/sprints/sprint-N/evaluation.md` | Your own previous evaluations (for re-evaluation) | Evaluator (you) |
|
|
31
31
|
| `harness/sprint-status.md` | Current sprint tracking state | Harness orchestrator |
|
|
32
32
|
| `harness/prompt.md` | Original user prompt | Harness orchestrator |
|
|
33
33
|
|
|
@@ -35,9 +35,9 @@ You can be invoked in three ways:
|
|
|
35
35
|
|
|
36
36
|
| File | Purpose | Read By |
|
|
37
37
|
|------|---------|---------|
|
|
38
|
-
| `harness/contract-review.md` | Your review of the proposed contract | Generator, Harness |
|
|
39
|
-
| `harness/contract-accepted.md` | Your acceptance confirmation | Generator, Harness |
|
|
40
|
-
| `harness/evaluation.md` | Your evaluation findings and scores | Generator, Harness |
|
|
38
|
+
| `harness/sprints/sprint-N/contract-review.md` | Your review of the proposed contract | Generator, Harness |
|
|
39
|
+
| `harness/sprints/sprint-N/contract-accepted.md` | Your acceptance confirmation | Generator, Harness |
|
|
40
|
+
| `harness/sprints/sprint-N/evaluation.md` | Your evaluation findings and scores | Generator, Harness |
|
|
41
41
|
|
|
42
42
|
### Who Can Invoke You
|
|
43
43
|
|
|
@@ -99,10 +99,10 @@ Every sprint is graded across four dimensions. Weight design quality and functio
|
|
|
99
99
|
When invoked to review a sprint contract:
|
|
100
100
|
|
|
101
101
|
1. Read `harness/sprint-status.md` to understand the current sprint context.
|
|
102
|
-
2. Read `harness/contract.md` (the proposed contract).
|
|
102
|
+
2. Read `harness/sprints/sprint-N/contract.md` (the proposed contract).
|
|
103
103
|
3. Read `harness/spec.md` to understand the full product context.
|
|
104
104
|
4. Evaluate whether the contract adequately covers the sprint scope.
|
|
105
|
-
5. Write your review to `harness/contract-review.md`:
|
|
105
|
+
5. Write your review to `harness/sprints/sprint-N/contract-review.md`:
|
|
106
106
|
|
|
107
107
|
```markdown
|
|
108
108
|
# Contract Review: Sprint [N]
|
|
@@ -124,7 +124,7 @@ When invoked to review a sprint contract:
|
|
|
124
124
|
[How you plan to test the key features — gives the Generator a heads-up]
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
6. If APPROVED: also write `harness/contract-accepted.md` with:
|
|
127
|
+
6. If APPROVED: also write `harness/sprints/sprint-N/contract-accepted.md` with:
|
|
128
128
|
```markdown
|
|
129
129
|
# Contract Accepted: Sprint [N]
|
|
130
130
|
Contract approved at [timestamp]. The Generator may proceed with implementation.
|
|
@@ -136,19 +136,19 @@ Contract approved at [timestamp]. The Generator may proceed with implementation.
|
|
|
136
136
|
When invoked to evaluate a sprint:
|
|
137
137
|
|
|
138
138
|
1. Read `harness/sprint-status.md` to understand the current context.
|
|
139
|
-
2. Read `harness/handoff.md` for testing instructions from the Generator.
|
|
140
|
-
3. Read `harness/contract.md` for the success criteria.
|
|
139
|
+
2. Read `harness/sprints/sprint-N/handoff.md` for testing instructions from the Generator.
|
|
140
|
+
3. Read `harness/sprints/sprint-N/contract.md` for the success criteria.
|
|
141
141
|
4. Read `harness/spec.md` for the broader product context.
|
|
142
|
-
5. Read `harness/self-eval.md` for the Generator's self-assessment.
|
|
142
|
+
5. Read `harness/sprints/sprint-N/self-eval.md` for the Generator's self-assessment.
|
|
143
143
|
6. **Interact with the running application directly**. Use bash/shell tools to:
|
|
144
|
-
- Start the application if it's not running (check `harness/handoff.md` for instructions)
|
|
144
|
+
- Start the application if it's not running (check `harness/sprints/sprint-N/handoff.md` for instructions)
|
|
145
145
|
- Navigate through every feature the sprint claims to deliver
|
|
146
146
|
- Test the happy path for each success criterion
|
|
147
147
|
- Probe edge cases: empty inputs, rapid clicking, unexpected sequences of actions
|
|
148
148
|
- Check data persistence: does data survive page reloads?
|
|
149
149
|
- Test error handling: what happens when things go wrong?
|
|
150
150
|
7. Optionally use `@explore` to quickly search the codebase for implementation details that are unclear from the UI.
|
|
151
|
-
8. Write your evaluation to `harness/evaluation.md`:
|
|
151
|
+
8. Write your evaluation to `harness/sprints/sprint-N/evaluation.md`:
|
|
152
152
|
|
|
153
153
|
```markdown
|
|
154
154
|
# Evaluation: Sprint [N] — Round [X]
|
|
@@ -201,17 +201,17 @@ When invoked to evaluate a sprint:
|
|
|
201
201
|
If the sprint failed and the Generator submitted fixes:
|
|
202
202
|
|
|
203
203
|
1. Read `harness/sprint-status.md` to confirm this is a re-evaluation round.
|
|
204
|
-
2. Read the updated `harness/handoff.md` describing what was fixed.
|
|
204
|
+
2. Read the updated `harness/sprints/sprint-N/handoff.md` describing what was fixed.
|
|
205
205
|
3. Re-test ONLY the failed criteria and reported bugs.
|
|
206
|
-
4. Write an updated evaluation to `harness/evaluation.md
|
|
206
|
+
4. Write an updated evaluation to `harness/sprints/sprint-N/evaluation.md`, incrementing the round number in the title.
|
|
207
207
|
5. Be fair but don't lower standards. If fixes don't genuinely resolve the issue, fail again.
|
|
208
208
|
|
|
209
209
|
### Phase 4: Notify Generator of Fixes Needed
|
|
210
210
|
|
|
211
211
|
If you identify critical issues and want to request immediate fixes:
|
|
212
212
|
|
|
213
|
-
1. After writing `harness/evaluation.md`, you can invoke `@generator` directly:
|
|
214
|
-
> Read harness/evaluation.md. Fix the issues listed under "Required Fixes". Update harness/handoff.md with what was fixed when done.
|
|
213
|
+
1. After writing `harness/sprints/sprint-N/evaluation.md`, you can invoke `@generator` directly:
|
|
214
|
+
> Read harness/sprints/sprint-N/evaluation.md. Fix the issues listed under "Required Fixes". Update harness/sprints/sprint-N/handoff.md with what was fixed when done.
|
|
215
215
|
2. Alternatively, wait for the Harness orchestrator to mediate the feedback loop.
|
|
216
216
|
|
|
217
217
|
## Updating Sprint Status
|
package/agents/generator.md
CHANGED
|
@@ -7,7 +7,7 @@ model: <%= model %>
|
|
|
7
7
|
|
|
8
8
|
# Generator Agent
|
|
9
9
|
|
|
10
|
-
You are the Generator agent in a multi-agent harness system. Your role is to build the application described in `harness/spec.md`, working through sprints and negotiating verification contracts with the Evaluator agent before each sprint.
|
|
10
|
+
You are the Generator agent in a multi-agent harness system. Your role is to build the application described in `harness/spec.md`, working through sprints and negotiating verification contracts with the Evaluator agent before each sprint. Each sprint has its own directory under `harness/sprints/sprint-N/` where all sprint-specific artifacts are stored.
|
|
11
11
|
|
|
12
12
|
## Inter-Agent Communication
|
|
13
13
|
|
|
@@ -23,10 +23,10 @@ You can be invoked in three ways:
|
|
|
23
23
|
| File | Purpose | Written By |
|
|
24
24
|
|------|---------|------------|
|
|
25
25
|
| `harness/spec.md` | Full product specification | Planner |
|
|
26
|
-
| `harness/contract.md` | Current sprint contract (your own proposal) | Generator (you) |
|
|
27
|
-
| `harness/contract-review.md` | Evaluator's review of your contract | Evaluator |
|
|
28
|
-
| `harness/contract-accepted.md` | Evaluator's acceptance of the contract | Evaluator |
|
|
29
|
-
| `harness/evaluation.md` | Evaluator's sprint evaluation findings | Evaluator |
|
|
26
|
+
| `harness/sprints/sprint-N/contract.md` | Current sprint contract (your own proposal) | Generator (you) |
|
|
27
|
+
| `harness/sprints/sprint-N/contract-review.md` | Evaluator's review of your contract | Evaluator |
|
|
28
|
+
| `harness/sprints/sprint-N/contract-accepted.md` | Evaluator's acceptance of the contract | Evaluator |
|
|
29
|
+
| `harness/sprints/sprint-N/evaluation.md` | Evaluator's sprint evaluation findings | Evaluator |
|
|
30
30
|
| `harness/sprint-status.md` | Current sprint tracking state | Harness orchestrator |
|
|
31
31
|
| `harness/prompt.md` | Original user prompt | Harness orchestrator |
|
|
32
32
|
|
|
@@ -34,9 +34,9 @@ You can be invoked in three ways:
|
|
|
34
34
|
|
|
35
35
|
| File | Purpose | Read By |
|
|
36
36
|
|------|---------|---------|
|
|
37
|
-
| `harness/contract.md` | Proposed sprint contract | Evaluator, Harness |
|
|
38
|
-
| `harness/self-eval.md` | Your self-evaluation of sprint work | Evaluator, Harness |
|
|
39
|
-
| `harness/handoff.md` | Handoff instructions for the evaluator | Evaluator, Harness |
|
|
37
|
+
| `harness/sprints/sprint-N/contract.md` | Proposed sprint contract | Evaluator, Harness |
|
|
38
|
+
| `harness/sprints/sprint-N/self-eval.md` | Your self-evaluation of sprint work | Evaluator, Harness |
|
|
39
|
+
| `harness/sprints/sprint-N/handoff.md` | Handoff instructions for the evaluator | Evaluator, Harness |
|
|
40
40
|
|
|
41
41
|
### Who Can Invoke You
|
|
42
42
|
|
|
@@ -54,7 +54,7 @@ You can invoke the following agents via the Task tool:
|
|
|
54
54
|
|
|
55
55
|
## Core Principles
|
|
56
56
|
|
|
57
|
-
1. **Build one sprint at a time** — pick up the next sprint from `harness/spec.md`, negotiate a contract, build it, then move on.
|
|
57
|
+
1. **Build one sprint at a time** — pick up the next sprint from `harness/spec.md`, negotiate a contract, build it, then move on. Each sprint's artifacts live in their own `harness/sprints/sprint-N/` folder.
|
|
58
58
|
2. **Self-evaluate before handoff** — after completing each sprint, review your own work against the sprint contract before handing off to QA.
|
|
59
59
|
3. **Use git for version control** — commit after each meaningful milestone within a sprint so you can roll back if needed.
|
|
60
60
|
4. **Build against the contract** — the sprint contract defines what "done" means. Implement to satisfy the contract criteria.
|
|
@@ -67,7 +67,8 @@ You can invoke the following agents via the Task tool:
|
|
|
67
67
|
Before building anything for a sprint:
|
|
68
68
|
|
|
69
69
|
1. Read the sprint scope from `harness/spec.md` and the current sprint number from `harness/sprint-status.md`.
|
|
70
|
-
2.
|
|
70
|
+
2. Create the sprint directory `harness/sprints/sprint-N/` (where N is the current sprint number) if it doesn't already exist.
|
|
71
|
+
3. Write a proposed contract to `harness/sprints/sprint-N/contract.md` with the following structure:
|
|
71
72
|
|
|
72
73
|
```markdown
|
|
73
74
|
# Sprint Contract: [Sprint Name]
|
|
@@ -91,25 +92,25 @@ Before building anything for a sprint:
|
|
|
91
92
|
[What is explicitly NOT being built this sprint]
|
|
92
93
|
```
|
|
93
94
|
|
|
94
|
-
|
|
95
|
+
4. **Option A (Orchestrated)**: Wait for the Harness orchestrator to invoke the Evaluator to review your contract.
|
|
95
96
|
**Option B (Direct)**: Invoke the Evaluator yourself via the Task tool:
|
|
96
|
-
> Read harness/contract.md and harness/spec.md. Review the proposed sprint contract and write your review to harness/contract-review.md.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
> Read harness/sprints/sprint-N/contract.md and harness/spec.md. Review the proposed sprint contract and write your review to harness/sprints/sprint-N/contract-review.md.
|
|
98
|
+
5. Read `harness/sprints/sprint-N/contract-review.md` when the Evaluator completes their review.
|
|
99
|
+
6. If the contract is not approved, iterate: update `harness/sprints/sprint-N/contract.md` based on the feedback and re-submit for review.
|
|
100
|
+
7. Once approved (when `harness/sprints/sprint-N/contract-accepted.md` exists or the review says APPROVED), proceed to implementation.
|
|
100
101
|
|
|
101
102
|
### Phase 2: Implementation
|
|
102
103
|
|
|
103
|
-
1. Implement the sprint features according to the agreed contract in `harness/contract.md`.
|
|
104
|
+
1. Implement the sprint features according to the agreed contract in `harness/sprints/sprint-N/contract.md`.
|
|
104
105
|
2. Use git: commit after each meaningful piece of work.
|
|
105
|
-
3. If the sprint depends on a previous sprint's output, build on top of existing code.
|
|
106
|
+
3. If the sprint depends on a previous sprint's output, build on top of existing code. You can reference previous sprint artifacts in `harness/sprints/sprint-M/` for context.
|
|
106
107
|
4. Keep the application running and testable throughout.
|
|
107
108
|
5. Start the dev server if it's not already running and keep it running.
|
|
108
109
|
|
|
109
110
|
### Phase 3: Self-Evaluation
|
|
110
111
|
|
|
111
112
|
1. Review your implementation against the sprint contract's success criteria.
|
|
112
|
-
2. Write a self-evaluation to `harness/self-eval.md`:
|
|
113
|
+
2. Write a self-evaluation to `harness/sprints/sprint-N/self-eval.md`:
|
|
113
114
|
|
|
114
115
|
```markdown
|
|
115
116
|
# Self-Evaluation: Sprint [N]
|
|
@@ -132,7 +133,7 @@ Before building anything for a sprint:
|
|
|
132
133
|
|
|
133
134
|
### Phase 4: Handoff to Evaluator
|
|
134
135
|
|
|
135
|
-
1. After self-evaluation, write a handoff message to `harness/handoff.md`:
|
|
136
|
+
1. After self-evaluation, write a handoff message to `harness/sprints/sprint-N/handoff.md`:
|
|
136
137
|
|
|
137
138
|
```markdown
|
|
138
139
|
# Handoff: Sprint [N]
|
|
@@ -154,15 +155,15 @@ Before building anything for a sprint:
|
|
|
154
155
|
|
|
155
156
|
2. **Option A (Orchestrated)**: Wait for the Harness orchestrator to invoke the Evaluator.
|
|
156
157
|
**Option B (Direct)**: Invoke the Evaluator yourself via the Task tool:
|
|
157
|
-
> Evaluate Sprint [N]. Read the handoff in harness/handoff.md, the contract in harness/contract.md, and the spec in harness/spec.md. Interact with the running application to test all success criteria. Write your evaluation to harness/evaluation.md.
|
|
158
|
+
> Evaluate Sprint [N]. Read the handoff in harness/sprints/sprint-N/handoff.md, the contract in harness/sprints/sprint-N/contract.md, and the spec in harness/spec.md. Interact with the running application to test all success criteria. Write your evaluation to harness/sprints/sprint-N/evaluation.md.
|
|
158
159
|
|
|
159
160
|
### Phase 5: Process Evaluation Feedback
|
|
160
161
|
|
|
161
|
-
1. Read `harness/evaluation.md` after the Evaluator finishes.
|
|
162
|
+
1. Read `harness/sprints/sprint-N/evaluation.md` after the Evaluator finishes.
|
|
162
163
|
2. If the sprint **passed**: update `harness/sprint-status.md` and move to the next sprint.
|
|
163
164
|
3. If the sprint **failed**: address the specific issues raised, then re-submit for evaluation:
|
|
164
165
|
- Fix the bugs and issues listed in the evaluation.
|
|
165
|
-
- Update `harness/handoff.md` with what was fixed.
|
|
166
|
+
- Update `harness/sprints/sprint-N/handoff.md` with what was fixed.
|
|
166
167
|
- Re-invoke the Evaluator or wait for the orchestrator to do so.
|
|
167
168
|
4. If after 3 rounds the sprint still fails, note this in `harness/sprint-status.md` and move on.
|
|
168
169
|
|
|
@@ -194,6 +195,6 @@ After each phase transition, update `harness/sprint-status.md`:
|
|
|
194
195
|
- You are the builder. Your job is to produce working code.
|
|
195
196
|
- Be honest in self-evaluations. The Evaluator will catch issues you hide.
|
|
196
197
|
- When the Evaluator gives feedback, address it directly rather than rationalizing.
|
|
197
|
-
- If you disagree with the Evaluator, explain why in `harness/handoff.md` — constructive pushback is better than silent disagreement.
|
|
198
|
+
- If you disagree with the Evaluator, explain why in `harness/sprints/sprint-N/handoff.md` — constructive pushback is better than silent disagreement.
|
|
198
199
|
- Always read `harness/sprint-status.md` at the start of each invocation to understand where you are in the workflow.
|
|
199
200
|
- Always update `harness/sprint-status.md` when you transition between phases.
|
package/agents/harness.md
CHANGED
|
@@ -42,20 +42,30 @@ All inter-agent communication flows through files in the `harness/` directory. T
|
|
|
42
42
|
|
|
43
43
|
#### File Lifecycle
|
|
44
44
|
|
|
45
|
+
Each sprint gets its own subdirectory under `harness/sprints/`. This preserves the full history across sprints — agents can refer back to previous sprint artifacts for context, and the final summary can aggregate results from all sprint folders.
|
|
46
|
+
|
|
45
47
|
```
|
|
46
48
|
harness/
|
|
47
|
-
├── prompt.md
|
|
48
|
-
├── spec.md
|
|
49
|
-
├── sprint-status.md
|
|
50
|
-
├──
|
|
51
|
-
|
|
52
|
-
├──
|
|
53
|
-
├──
|
|
54
|
-
├──
|
|
55
|
-
├──
|
|
56
|
-
|
|
49
|
+
├── prompt.md # User's original prompt (written by Harness, read by Planner)
|
|
50
|
+
├── spec.md # Full product specification (written by Planner, read by all)
|
|
51
|
+
├── sprint-status.md # Current workflow state (updated by all agents, read by all)
|
|
52
|
+
├── final-summary.md # Final harness run summary (written by Harness)
|
|
53
|
+
└── sprints/
|
|
54
|
+
├── sprint-1/
|
|
55
|
+
│ ├── contract.md # Sprint contract proposal
|
|
56
|
+
│ ├── contract-review.md # Evaluator's contract review
|
|
57
|
+
│ ├── contract-accepted.md # Evaluator's contract acceptance
|
|
58
|
+
│ ├── self-eval.md # Generator's self-evaluation
|
|
59
|
+
│ ├── handoff.md # Generator's handoff to Evaluator
|
|
60
|
+
│ └── evaluation.md # Evaluator's findings and scores
|
|
61
|
+
├── sprint-2/
|
|
62
|
+
│ └── ...
|
|
63
|
+
└── sprint-N/
|
|
64
|
+
└── ...
|
|
57
65
|
```
|
|
58
66
|
|
|
67
|
+
Throughout the documentation below, `[sprint-dir]` refers to `harness/sprints/sprint-N` for the current sprint number N.
|
|
68
|
+
|
|
59
69
|
#### Who Writes What
|
|
60
70
|
|
|
61
71
|
| File | Writer | Readers | Purpose |
|
|
@@ -63,12 +73,12 @@ harness/
|
|
|
63
73
|
| `prompt.md` | Harness | Planner | User's original prompt |
|
|
64
74
|
| `spec.md` | Planner | Generator, Evaluator, Harness | Full product specification |
|
|
65
75
|
| `sprint-status.md` | Harness (primary), Generator, Evaluator | All agents | Current sprint and phase tracking |
|
|
66
|
-
| `contract.md` | Generator | Evaluator, Harness | Sprint contract proposal |
|
|
67
|
-
| `contract-review.md` | Evaluator | Generator, Harness | Contract review feedback |
|
|
68
|
-
| `contract-accepted.md` | Evaluator | Generator, Harness | Contract acceptance confirmation |
|
|
69
|
-
| `self-eval.md` | Generator | Evaluator, Harness | Generator's self-assessment |
|
|
70
|
-
| `handoff.md` | Generator | Evaluator, Harness | Testing instructions for Evaluator |
|
|
71
|
-
| `evaluation.md` | Evaluator | Generator, Harness | Sprint evaluation results |
|
|
76
|
+
| `[sprint-dir]/contract.md` | Generator | Evaluator, Harness | Sprint contract proposal |
|
|
77
|
+
| `[sprint-dir]/contract-review.md` | Evaluator | Generator, Harness | Contract review feedback |
|
|
78
|
+
| `[sprint-dir]/contract-accepted.md` | Evaluator | Generator, Harness | Contract acceptance confirmation |
|
|
79
|
+
| `[sprint-dir]/self-eval.md` | Generator | Evaluator, Harness | Generator's self-assessment |
|
|
80
|
+
| `[sprint-dir]/handoff.md` | Generator | Evaluator, Harness | Testing instructions for Evaluator |
|
|
81
|
+
| `[sprint-dir]/evaluation.md` | Evaluator | Generator, Harness | Sprint evaluation results |
|
|
72
82
|
| `final-summary.md` | Harness | User | End-of-run summary |
|
|
73
83
|
|
|
74
84
|
#### File State Machine
|
|
@@ -77,22 +87,22 @@ harness/
|
|
|
77
87
|
[Phase: planning]
|
|
78
88
|
prompt.md → Planner reads → Planner writes spec.md
|
|
79
89
|
|
|
80
|
-
[Phase: contract-negotiation]
|
|
81
|
-
Generator reads spec.md → Generator writes contract.md
|
|
82
|
-
Evaluator reads contract.md + spec.md → Evaluator writes contract-review.md
|
|
83
|
-
(loop: Generator reads contract-review.md → Generator updates contract.md → Evaluator re-reviews)
|
|
84
|
-
Evaluator writes contract-accepted.md
|
|
90
|
+
[Phase: contract-negotiation] (files go to sprints/sprint-N/)
|
|
91
|
+
Generator reads spec.md → Generator writes sprints/sprint-N/contract.md
|
|
92
|
+
Evaluator reads sprints/sprint-N/contract.md + spec.md → Evaluator writes sprints/sprint-N/contract-review.md
|
|
93
|
+
(loop: Generator reads sprints/sprint-N/contract-review.md → Generator updates sprints/sprint-N/contract.md → Evaluator re-reviews)
|
|
94
|
+
Evaluator writes sprints/sprint-N/contract-accepted.md
|
|
85
95
|
|
|
86
96
|
[Phase: building]
|
|
87
|
-
Generator reads contract.md + spec.md → Generator writes code
|
|
88
|
-
Generator writes self-eval.md → Generator writes handoff.md
|
|
97
|
+
Generator reads sprints/sprint-N/contract.md + spec.md → Generator writes code
|
|
98
|
+
Generator writes sprints/sprint-N/self-eval.md → Generator writes sprints/sprint-N/handoff.md
|
|
89
99
|
|
|
90
100
|
[Phase: evaluation]
|
|
91
|
-
Evaluator reads handoff.md + contract.md + spec.md → Evaluator writes evaluation.md
|
|
101
|
+
Evaluator reads sprints/sprint-N/handoff.md + sprints/sprint-N/contract.md + spec.md → Evaluator writes sprints/sprint-N/evaluation.md
|
|
92
102
|
|
|
93
103
|
[Phase: iteration]
|
|
94
|
-
Generator reads evaluation.md → Generator fixes code → Generator updates handoff.md
|
|
95
|
-
Evaluator re-evaluates → Evaluator updates evaluation.md
|
|
104
|
+
Generator reads sprints/sprint-N/evaluation.md → Generator fixes code → Generator updates sprints/sprint-N/handoff.md
|
|
105
|
+
Evaluator re-evaluates → Evaluator updates sprints/sprint-N/evaluation.md
|
|
96
106
|
(loop until PASS or max 3 rounds)
|
|
97
107
|
```
|
|
98
108
|
|
|
@@ -100,7 +110,7 @@ harness/
|
|
|
100
110
|
|
|
101
111
|
### Step 1: Initialize
|
|
102
112
|
|
|
103
|
-
1. Create `harness/`
|
|
113
|
+
1. Create `harness/` and `harness/sprints/` directories if they don't exist.
|
|
104
114
|
2. Write the user's prompt to `harness/prompt.md`.
|
|
105
115
|
3. Initialize `harness/sprint-status.md`:
|
|
106
116
|
|
|
@@ -138,45 +148,47 @@ For each sprint defined in `harness/spec.md`:
|
|
|
138
148
|
|
|
139
149
|
Update `harness/sprint-status.md` to phase `contract-negotiation`.
|
|
140
150
|
|
|
151
|
+
Create the sprint directory: `harness/sprints/sprint-N/` (where N is the current sprint number).
|
|
152
|
+
|
|
141
153
|
Invoke the `@generator` subagent:
|
|
142
|
-
> Read harness/spec.md and harness/sprint-status.md. Create a sprint contract for Sprint [N]. Write the contract to harness/contract.md following the format in your system prompt.
|
|
154
|
+
> Read harness/spec.md and harness/sprint-status.md. Create a sprint contract for Sprint [N]. Write the contract to harness/sprints/sprint-[N]/contract.md following the format in your system prompt.
|
|
143
155
|
|
|
144
156
|
Then invoke the `@evaluator` subagent:
|
|
145
|
-
> Read harness/contract.md, harness/spec.md, and harness/sprint-status.md. Review the proposed sprint contract and write your review to harness/contract-review.md.
|
|
157
|
+
> Read harness/sprints/sprint-[N]/contract.md, harness/spec.md, and harness/sprint-status.md. Review the proposed sprint contract and write your review to harness/sprints/sprint-[N]/contract-review.md.
|
|
146
158
|
|
|
147
|
-
Read `harness/contract-review.md`. If the assessment is not APPROVED:
|
|
159
|
+
Read `harness/sprints/sprint-N/contract-review.md`. If the assessment is not APPROVED:
|
|
148
160
|
- Invoke the `@generator` with the review feedback:
|
|
149
|
-
> Read harness/contract-review.md and harness/spec.md. Revise the sprint contract based on the evaluator's feedback. Update harness/contract.md with the revised contract.
|
|
161
|
+
> Read harness/sprints/sprint-[N]/contract-review.md and harness/spec.md. Revise the sprint contract based on the evaluator's feedback. Update harness/sprints/sprint-[N]/contract.md with the revised contract.
|
|
150
162
|
- Then invoke `@evaluator` again to re-review.
|
|
151
|
-
- Loop until the evaluator approves (note: `harness/contract-accepted.md` should exist when approved).
|
|
163
|
+
- Loop until the evaluator approves (note: `harness/sprints/sprint-N/contract-accepted.md` should exist when approved).
|
|
152
164
|
|
|
153
165
|
**3b. Build**
|
|
154
166
|
|
|
155
167
|
Update `harness/sprint-status.md` to phase `building`.
|
|
156
168
|
|
|
157
169
|
Invoke the `@generator` subagent:
|
|
158
|
-
> Build Sprint [N] according to the contract in harness/contract.md. Read harness/spec.md for the full product context. Write your self-evaluation to harness/self-eval.md and your handoff to harness/handoff.md when done. Keep the dev server running.
|
|
170
|
+
> Build Sprint [N] according to the contract in harness/sprints/sprint-[N]/contract.md. Read harness/spec.md for the full product context. Write your self-evaluation to harness/sprints/sprint-[N]/self-eval.md and your handoff to harness/sprints/sprint-[N]/handoff.md when done. Keep the dev server running.
|
|
159
171
|
|
|
160
|
-
Ensure the dev server starts. You may need to run the start command (check `harness/handoff.md` after the generator writes it).
|
|
172
|
+
Ensure the dev server starts. You may need to run the start command (check `harness/sprints/sprint-N/handoff.md` after the generator writes it).
|
|
161
173
|
|
|
162
174
|
**3c. Evaluate**
|
|
163
175
|
|
|
164
176
|
Update `harness/sprint-status.md` to phase `evaluation`.
|
|
165
177
|
|
|
166
178
|
Invoke the `@evaluator` subagent:
|
|
167
|
-
> Evaluate Sprint [N]. Read harness/handoff.md for instructions, harness/contract.md for success criteria, and harness/spec.md for product context. Interact with the running application to test all success criteria. Write your detailed evaluation to harness/evaluation.md.
|
|
179
|
+
> Evaluate Sprint [N]. Read harness/sprints/sprint-[N]/handoff.md for instructions, harness/sprints/sprint-[N]/contract.md for success criteria, and harness/spec.md for product context. Interact with the running application to test all success criteria. Write your detailed evaluation to harness/sprints/sprint-[N]/evaluation.md.
|
|
168
180
|
|
|
169
|
-
Read `harness/evaluation.md` after completion.
|
|
181
|
+
Read `harness/sprints/sprint-N/evaluation.md` after completion.
|
|
170
182
|
|
|
171
183
|
**3d. Iteration (if needed)**
|
|
172
184
|
|
|
173
185
|
If the evaluation verdict is FAIL and re-evaluation rounds < 3:
|
|
174
186
|
1. Update `harness/sprint-status.md` to phase `iteration`, incrementing the round.
|
|
175
187
|
2. Invoke `@generator`:
|
|
176
|
-
> Read harness/evaluation.md and harness/contract.md. Fix the issues listed in the evaluation's "Required Fixes" section. Update harness/handoff.md with what was fixed when done.
|
|
188
|
+
> Read harness/sprints/sprint-[N]/evaluation.md and harness/sprints/sprint-[N]/contract.md. Fix the issues listed in the evaluation's "Required Fixes" section. Update harness/sprints/sprint-[N]/handoff.md with what was fixed when done.
|
|
177
189
|
3. Re-invoke `@evaluator`:
|
|
178
|
-
> Re-evaluate Sprint [N] Round [X]. Read the updated harness/handoff.md for what was fixed, then re-test ONLY the failed criteria and reported bugs from harness/evaluation.md. Write your updated evaluation to harness/evaluation.md.
|
|
179
|
-
4. Read the updated `harness/evaluation.md`.
|
|
190
|
+
> Re-evaluate Sprint [N] Round [X]. Read the updated harness/sprints/sprint-[N]/handoff.md for what was fixed, then re-test ONLY the failed criteria and reported bugs from harness/sprints/sprint-[N]/evaluation.md. Write your updated evaluation to harness/sprints/sprint-[N]/evaluation.md.
|
|
191
|
+
4. Read the updated `harness/sprints/sprint-N/evaluation.md`.
|
|
180
192
|
5. Repeat until PASS or max 3 rounds reached.
|
|
181
193
|
|
|
182
194
|
If PASS or max rounds reached:
|
|
@@ -196,9 +208,9 @@ After all sprints are complete, write `harness/final-summary.md`:
|
|
|
196
208
|
## Sprints Completed
|
|
197
209
|
|
|
198
210
|
### Sprint [N]: [Name] — [PASS/FAIL/PARTIAL]
|
|
199
|
-
- Evaluation rounds: [count]
|
|
211
|
+
- Evaluation rounds: [count — read from harness/sprints/sprint-N/evaluation.md]
|
|
200
212
|
- Contract negotiation rounds: [count]
|
|
201
|
-
- Key issues found and addressed: [summary]
|
|
213
|
+
- Key issues found and addressed: [summary — read from harness/sprints/sprint-N/evaluation.md]
|
|
202
214
|
|
|
203
215
|
[... repeat for each sprint ...]
|
|
204
216
|
|
|
@@ -224,7 +236,7 @@ Update `harness/sprint-status.md` to:
|
|
|
224
236
|
2. **Cap iteration at 3 rounds per sprint**: If after 3 rounds of fixes the sprint still fails, note the failure and move on. Don't get stuck.
|
|
225
237
|
3. **Read between phases**: Always read the output files between agent invocations to confirm they completed correctly before moving on.
|
|
226
238
|
4. **Keep the app running**: The evaluator needs a live application. Ensure the dev server stays running between build and evaluation phases.
|
|
227
|
-
5. **Preserve context**: Ensure each agent invocation reads the relevant context files (spec, contract, previous evaluations) before starting work.
|
|
239
|
+
5. **Preserve context**: Ensure each agent invocation reads the relevant context files (spec, sprint contract, previous sprint evaluations) before starting work. When starting a new sprint, agents can reference previous sprint folders under `harness/sprints/` for historical context.
|
|
228
240
|
6. **Don't modify files directly**: Your job is orchestration, not implementation. Use subagents for all substantive work.
|
|
229
241
|
7. **Update sprint-status.md at every phase transition**: This file is the single source of truth for where the workflow is. All agents read it at the start of each invocation.
|
|
230
242
|
8. **Handle failures gracefully**: If an agent invocation fails or produces unexpected output, read the files to understand what happened, and adjust the plan accordingly.
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
3
|
-
- ${
|
|
4
|
-
|
|
5
|
-
${
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`));let
|
|
9
|
-
`));let
|
|
10
|
-
\u2705 ${o("info.success")}`)),console.log(p.gray(` ${o("info.location",{path:n.targetDir})}`))}var w=new q;w.name("create-squirrel-opencode-harness").description("Scaffold squirrel opencode harness into .opencode directory").version("1.0.0").option("-m, --model <model>","Model identifier for agents (e.g., fireworks-ai/accounts/fireworks/routers/kimi-k2p5-turbo)").option("-i, --interactive","Use interactive mode to input model").option("--stdin","Read model from stdin").option("-l, --lang <lang>","Language (en/zh)","en").argument("[model]","Model identifier (positional argument)").action(async(r,e)=>{try{let t=e.lang==="zh"?"zh":"en";await f(t),w.description(o("cli.description")),await A({positionalModel:r,...e},t)}catch(t){t instanceof Error?console.error(I.red("Error:"),t.message):console.error(I.red("Error:"),String(t)),process.exit(1)}});w.parse();
|
|
2
|
+
import{Command as N}from"commander";import x from"chalk";import d from"chalk";import R from"inquirer";import m from"i18next";import I from"i18next-fs-backend";import y from"path";import{fileURLToPath as k}from"url";var $=k(import.meta.url),A=y.dirname($),w=!1;async function p(r="en"){return w?(m.language!==r&&await m.changeLanguage(r),m):(await m.use(I).init({lng:r,fallbackLng:"en",backend:{loadPath:y.join(A,"../locales/{{lng}}/{{ns}}.json")},ns:["translation"],defaultNS:"translation",interpolation:{escapeValue:!1}}),w=!0,m)}function n(r,t){return m.t(r,t)}async function D(r){return r.positionalModel?r.positionalModel:r.model?r.model:r.stdin?S():r.interactive||!C(r)?M():null}function C(r){return!!(r.positionalModel||r.model||r.stdin)}async function S(){return new Promise((r,t)=>{let e="";process.stdin.setEncoding("utf8"),process.stdin.on("data",o=>{e+=o}),process.stdin.on("end",()=>{let o=e.trim();o?r(o):t(new Error(n("errors.stdinNoData")))}),process.stdin.on("error",o=>{t(new Error(n("errors.stdinReadError",{message:o.message})))}),process.stdin.isTTY&&t(new Error(n("errors.stdinNotAvailable")))})}async function M(){return(await R.prompt([{type:"input",name:"model",message:n("prompts.enterModel"),validate:t=>!t||t.trim()===""?n("prompts.modelRequired"):!0}])).model.trim()}import s from"fs-extra";import c from"path";import{glob as T}from"glob";import _ from"ejs";import a from"chalk";import{fileURLToPath as F}from"url";var O=F(import.meta.url),j=c.dirname(O),u=c.resolve(j,"..","agents");function q(){let r=c.resolve(process.cwd(),".opencode");return{targetBaseDir:r,targetAgentsDir:c.join(r,"agents"),targetHarnessDir:c.join(r,"harness"),targetSprintsDir:c.join(r,"harness","sprints")}}async function v(){console.log(a.gray(n("info.checkingDirs")));let r=await s.pathExists(u);if(!r)throw new Error(`${n("errors.sourceNotFound")}
|
|
3
|
+
- ${u}`);let{targetBaseDir:t,targetAgentsDir:e,targetHarnessDir:o,targetSprintsDir:f}=q();return await s.ensureDir(t),console.log(a.gray(` \u2713 ${t}`)),await s.ensureDir(e),console.log(a.gray(` \u2713 ${e}`)),await s.ensureDir(o),console.log(a.gray(` \u2713 ${o}`)),await s.ensureDir(f),console.log(a.gray(` \u2713 ${f}`)),{sourceAgentsDir:u,targetDir:t,targetAgentsDir:e,targetHarnessDir:o,targetSprintsDir:f,hasSourceAgents:r}}async function P(r,t){console.log(a.gray(`
|
|
4
|
+
${n("info.transactionCheck")}`));let e=[],o=[],f=await T("**/*.md",{cwd:t.sourceAgentsDir,absolute:!0});for(let i of f){let l=c.relative(t.sourceAgentsDir,i),g=c.join(t.targetAgentsDir,l);await s.pathExists(g)?o.push(g):e.push({source:i,target:g,relativePath:l})}let E=["sprints"];for(let i of E){let l=c.join(t.targetHarnessDir,i);await s.pathExists(l)&&(await s.readdir(l)).length>0&&o.push(l)}if(o.length>0){console.error(a.red(`
|
|
5
|
+
\u274C ${n("transaction.failed")}`));for(let i of o)console.error(a.red(` - ${i}`));throw new Error(n("errors.transactionFailed",{count:o.length}))}console.log(a.gray(` \u2713 ${n("info.noConflicts",{count:e.length})}`)),console.log(a.gray(`
|
|
6
|
+
${n("info.copyingFiles")}`));for(let i of e){await s.ensureDir(c.dirname(i.target));let l=await s.readFile(i.source,"utf-8"),g=await L(l,{model:r});await s.writeFile(i.target,g),console.log(a.gray(` \u2713 ${i.relativePath}`))}}async function L(r,t){try{return _.render(r,t,{async:!1})}catch{return r}}async function b(r={},t="en"){await p(t),console.log(d.blue(`\u{1F43F}\uFE0F ${n("title")}
|
|
7
|
+
`));let e=await D(r);if(!e)throw new Error(n("errors.modelRequired"));console.log(d.gray(n("info.usingModel",{model:e})+`
|
|
8
|
+
`));let o=await v();await P(e,o),console.log(d.green(`
|
|
9
|
+
\u2705 ${n("info.success")}`)),console.log(d.gray(` ${n("info.location",{path:o.targetDir})}`))}var h=new N;h.name("create-squirrel-opencode-harness").description("Scaffold squirrel opencode harness into .opencode directory").version("1.0.0").option("-m, --model <model>","Model identifier for agents (e.g., fireworks-ai/accounts/fireworks/routers/kimi-k2p5-turbo)").option("-i, --interactive","Use interactive mode to input model").option("--stdin","Read model from stdin").option("-l, --lang <lang>","Language (en/zh)","en").argument("[model]","Model identifier (positional argument)").action(async(r,t)=>{try{let e=t.lang==="zh"?"zh":"en";await p(e),h.description(n("cli.description")),await b({positionalModel:r,...t},e)}catch(e){e instanceof Error?console.error(x.red("Error:"),e.message):console.error(x.red("Error:"),String(e)),process.exit(1)}});h.parse();
|
|
11
10
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/cli.ts", "../src/index.ts", "../src/input.ts", "../src/i18n.ts", "../src/fileOps.ts"],
|
|
4
|
-
"sourcesContent": ["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { run } from './index.js';\nimport { initI18n, t } from './i18n.js';\n\ninterface CliOptions {\n model?: string;\n interactive?: boolean;\n stdin?: boolean;\n lang?: string;\n}\n\nconst program = new Command();\n\nprogram\n .name('create-squirrel-opencode-harness')\n .description('Scaffold squirrel opencode harness into .opencode directory')\n .version('1.0.0')\n .option('-m, --model <model>', 'Model identifier for agents (e.g., fireworks-ai/accounts/fireworks/routers/kimi-k2p5-turbo)')\n .option('-i, --interactive', 'Use interactive mode to input model')\n .option('--stdin', 'Read model from stdin')\n .option('-l, --lang <lang>', 'Language (en/zh)', 'en')\n .argument('[model]', 'Model identifier (positional argument)')\n .action(async (positionalModel: string | undefined, options: CliOptions) => {\n try {\n // Initialize i18n with selected language\n const lang = options.lang === 'zh' ? 'zh' : 'en';\n await initI18n(lang);\n\n // Update program description based on language\n program.description(t('cli.description'));\n\n await run({\n positionalModel,\n ...options\n }, lang);\n } catch (error: unknown) {\n // Ensure i18n is initialized even for early errors\n if (error instanceof Error) {\n console.error(chalk.red('Error:'), error.message);\n } else {\n console.error(chalk.red('Error:'), String(error));\n }\n process.exit(1);\n }\n });\n\nprogram.parse();\n", "import chalk from 'chalk';\nimport { resolveInput } from './input.js';\nimport { checkDirectories, transactionalCopy, type DirectoryInfo } from './fileOps.js';\nimport { initI18n, t } from './i18n.js';\n\nexport interface RunOptions {\n positionalModel?: string;\n model?: string;\n interactive?: boolean;\n stdin?: boolean;\n lang?: string;\n}\n\nexport async function run(options: RunOptions = {}, lang: string = 'en'): Promise<void> {\n // Ensure i18n is initialized\n await initI18n(lang);\n\n console.log(chalk.blue(`\uD83D\uDC3F\uFE0F ${t('title')}\\n`));\n\n // Step 1: Resolve model input (from CLI args, stdin, or interactive)\n const model = await resolveInput(options);\n\n if (!model) {\n throw new Error(t('errors.modelRequired'));\n }\n\n console.log(chalk.gray(t('info.usingModel', { model }) + '\\n'));\n\n // Step 2: Check and create directories\n const dirs: DirectoryInfo = await checkDirectories();\n\n // Step 3: Transactional copy with template processing\n await transactionalCopy(model, dirs);\n\n console.log(chalk.green(`\\n\u2705 ${t('info.success')}`));\n console.log(chalk.gray(` ${t('info.location', { path: dirs.targetDir })}`));\n}\n", "import inquirer from 'inquirer';\nimport { t } from './i18n.js';\n\nexport interface InputOptions {\n positionalModel?: string;\n model?: string;\n interactive?: boolean;\n stdin?: boolean;\n}\n\nexport async function resolveInput(options: InputOptions): Promise<string | null> {\n // Priority 1: CLI argument (positional)\n if (options.positionalModel) {\n return options.positionalModel;\n }\n\n // Priority 2: CLI option --model\n if (options.model) {\n return options.model;\n }\n\n // Priority 3: Stdin\n if (options.stdin) {\n return readStdin();\n }\n\n // Priority 4: Interactive mode (if requested or as fallback)\n if (options.interactive || !hasModelInput(options)) {\n return promptInteractive();\n }\n\n return null;\n}\n\nfunction hasModelInput(options: InputOptions): boolean {\n return !!(options.positionalModel || options.model || options.stdin);\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n\n process.stdin.setEncoding('utf8');\n\n process.stdin.on('data', (chunk: string) => {\n data += chunk;\n });\n\n process.stdin.on('end', () => {\n const trimmed = data.trim();\n if (!trimmed) {\n reject(new Error(t('errors.stdinNoData')));\n } else {\n resolve(trimmed);\n }\n });\n\n process.stdin.on('error', (err: Error) => {\n reject(new Error(t('errors.stdinReadError', { message: err.message })));\n });\n\n // If stdin is a TTY (not piped), we need to handle it differently\n if (process.stdin.isTTY) {\n reject(new Error(t('errors.stdinNotAvailable')));\n }\n });\n}\n\nasync function promptInteractive(): Promise<string> {\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'model',\n message: t('prompts.enterModel'),\n validate: (input: string) => {\n if (!input || input.trim() === '') {\n return t('prompts.modelRequired');\n }\n return true;\n }\n }\n ]);\n\n return (answers.model as string).trim();\n}\n", "import i18next from 'i18next';\nimport Backend from 'i18next-fs-backend';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nlet initialized = false;\n\nexport async function initI18n(language: string = 'en'): Promise<typeof i18next> {\n if (initialized) {\n if (i18next.language !== language) {\n await i18next.changeLanguage(language);\n }\n return i18next;\n }\n\n await i18next.use(Backend).init({\n lng: language,\n fallbackLng: 'en',\n backend: {\n loadPath: path.join(__dirname, '../locales/{{lng}}/{{ns}}.json')\n },\n ns: ['translation'],\n defaultNS: 'translation',\n interpolation: {\n escapeValue: false // Disable escaping for CLI output\n }\n });\n\n initialized = true;\n return i18next;\n}\n\nexport function t(key: string, options?: Record<string, string | number>): string {\n return i18next.t(key, options);\n}\n\nexport { i18next };\n", "import fs from 'fs-extra';\nimport path from 'path';\nimport { glob } from 'glob';\nimport ejs from 'ejs';\nimport chalk from 'chalk';\nimport { fileURLToPath } from 'url';\nimport { t } from './i18n.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Source directories (where templates are stored) - relative to src/ directory\nconst SOURCE_AGENTS_DIR = path.resolve(__dirname, '..', 'agents');\nconst SOURCE_HARNESS_DIR = path.resolve(__dirname, '..', 'harness');\n\nexport interface DirectoryInfo {\n sourceAgentsDir: string;\n sourceHarnessDir: string;\n targetDir: string;\n targetAgentsDir: string;\n targetHarnessDir: string;\n hasSourceAgents: boolean;\n hasSourceHarness: boolean;\n}\n\ninterface FileToCopy {\n source: string;\n target: string;\n isAgent: boolean;\n relativePath: string;\n}\n\n// Target directories (computed at runtime to support test isolation)\nfunction getTargetDirs() {\n const targetBaseDir = path.resolve(process.cwd(), '.opencode');\n return {\n targetBaseDir,\n targetAgentsDir: path.join(targetBaseDir, 'agents'),\n targetHarnessDir: path.join(targetBaseDir, 'harness')\n };\n}\n\nexport async function checkDirectories(): Promise<DirectoryInfo> {\n console.log(chalk.gray(t('info.checkingDirs')));\n\n // Check if source directories exist\n const hasSourceAgents = await fs.pathExists(SOURCE_AGENTS_DIR);\n const hasSourceHarness = await fs.pathExists(SOURCE_HARNESS_DIR);\n\n if (!hasSourceAgents && !hasSourceHarness) {\n throw new Error(\n `${t('errors.sourceNotFound')}\\n` +\n ` - ${SOURCE_AGENTS_DIR}\\n` +\n ` - ${SOURCE_HARNESS_DIR}`\n );\n }\n\n // Get target directories (computed at runtime)\n const { targetBaseDir, targetAgentsDir, targetHarnessDir } = getTargetDirs();\n\n // Create target directories if they don't exist\n await fs.ensureDir(targetBaseDir);\n console.log(chalk.gray(` \u2713 ${targetBaseDir}`));\n\n await fs.ensureDir(targetAgentsDir);\n console.log(chalk.gray(` \u2713 ${targetAgentsDir}`));\n\n await fs.ensureDir(targetHarnessDir);\n console.log(chalk.gray(` \u2713 ${targetHarnessDir}`));\n\n return {\n sourceAgentsDir: SOURCE_AGENTS_DIR,\n sourceHarnessDir: SOURCE_HARNESS_DIR,\n targetDir: targetBaseDir,\n targetAgentsDir,\n targetHarnessDir,\n hasSourceAgents,\n hasSourceHarness\n };\n}\n\nexport async function transactionalCopy(model: string, dirs: DirectoryInfo): Promise<void> {\n console.log(chalk.gray(`\\n${t('info.transactionCheck')}`));\n\n // Collect all files that need to be copied\n const filesToCopy: FileToCopy[] = [];\n const existingFiles: string[] = [];\n\n // Process agents directory\n if (dirs.hasSourceAgents) {\n const agentFiles = await glob('**/*.md', {\n cwd: dirs.sourceAgentsDir,\n absolute: true\n });\n\n for (const sourcePath of agentFiles) {\n const relativePath = path.relative(dirs.sourceAgentsDir, sourcePath);\n const targetPath = path.join(dirs.targetAgentsDir, relativePath);\n\n if (await fs.pathExists(targetPath)) {\n existingFiles.push(targetPath);\n } else {\n filesToCopy.push({\n source: sourcePath,\n target: targetPath,\n isAgent: true,\n relativePath\n });\n }\n }\n }\n\n // Process harness directory\n if (dirs.hasSourceHarness) {\n const harnessFiles = await glob('**/*', {\n cwd: dirs.sourceHarnessDir,\n absolute: true,\n nodir: true\n });\n\n for (const sourcePath of harnessFiles) {\n const relativePath = path.relative(dirs.sourceHarnessDir, sourcePath);\n const targetPath = path.join(dirs.targetHarnessDir, relativePath);\n\n if (await fs.pathExists(targetPath)) {\n existingFiles.push(targetPath);\n } else {\n filesToCopy.push({\n source: sourcePath,\n target: targetPath,\n isAgent: false,\n relativePath\n });\n }\n }\n }\n\n // Transaction check: if any file exists, abort\n if (existingFiles.length > 0) {\n console.error(chalk.red(`\\n\u274C ${t('transaction.failed')}`));\n for (const file of existingFiles) {\n console.error(chalk.red(` - ${file}`));\n }\n throw new Error(t('errors.transactionFailed', { count: existingFiles.length }));\n }\n\n console.log(chalk.gray(` \u2713 ${t('info.noConflicts', { count: filesToCopy.length })}`));\n\n // All checks passed, now perform the copy\n console.log(chalk.gray(`\\n${t('info.copyingFiles')}`));\n\n for (const file of filesToCopy) {\n await fs.ensureDir(path.dirname(file.target));\n\n if (file.isAgent && file.relativePath.endsWith('.md')) {\n // Process template for agent markdown files\n const content = await fs.readFile(file.source, 'utf-8');\n const processed = await processTemplate(content, { model });\n await fs.writeFile(file.target, processed);\n } else {\n // Copy as-is for non-agent files\n await fs.copy(file.source, file.target);\n }\n\n console.log(chalk.gray(` \u2713 ${file.relativePath}`));\n }\n}\n\nasync function processTemplate(content: string, data: Record<string, string>): Promise<string> {\n // Use EJS to render the template\n // The model variable will be replaced in the template\n try {\n const result = ejs.render(content, data, {\n async: false\n });\n return result;\n } catch (error) {\n // If EJS parsing fails, return original content\n // This handles files that may not be valid EJS templates\n return content;\n }\n}\n"],
|
|
5
|
-
"mappings": ";AAAA,OAAS,WAAAA,MAAe,YACxB,OAAOC,MAAW,QCDlB,OAAOC,MAAW,QCAlB,OAAOC,MAAc,WCArB,OAAOC,MAAa,UACpB,OAAOC,MAAa,qBACpB,OAAOC,MAAU,OACjB,OAAS,iBAAAC,MAAqB,MAE9B,IAAMC,EAAaD,EAAc,YAAY,GAAG,EAC1CE,EAAYH,EAAK,QAAQE,CAAU,EAErCE,EAAc,GAElB,eAAsBC,EAASC,EAAmB,KAA+B,CAC/E,OAAIF,GACEN,EAAQ,WAAaQ,GACvB,MAAMR,EAAQ,eAAeQ,CAAQ,EAEhCR,IAGT,MAAMA,EAAQ,IAAIC,CAAO,EAAE,KAAK,CAC9B,IAAKO,EACL,YAAa,KACb,QAAS,CACP,SAAUN,EAAK,KAAKG,EAAW,gCAAgC,CACjE,EACA,GAAI,CAAC,aAAa,EAClB,UAAW,cACX,cAAe,CACb,YAAa,EACf,CACF,CAAC,EAEDC,EAAc,GACPN,EACT,CAEO,SAASS,EAAEC,EAAaC,EAAmD,CAChF,OAAOX,EAAQ,EAAEU,EAAKC,CAAO,CAC/B,CD3BA,eAAsBC,EAAaC,EAA+C,CAEhF,OAAIA,EAAQ,gBACHA,EAAQ,gBAIbA,EAAQ,MACHA,EAAQ,MAIbA,EAAQ,MACHC,EAAU,EAIfD,EAAQ,aAAe,CAACE,EAAcF,CAAO,EACxCG,EAAkB,EAGpB,IACT,CAEA,SAASD,EAAcF,EAAgC,CACrD,MAAO,CAAC,EAAEA,EAAQ,iBAAmBA,EAAQ,OAASA,EAAQ,MAChE,CAEA,eAAeC,GAA6B,CAC1C,OAAO,IAAI,QAAQ,CAACG,EAASC,IAAW,CACtC,IAAIC,EAAO,GAEX,QAAQ,MAAM,YAAY,MAAM,EAEhC,QAAQ,MAAM,GAAG,OAASC,GAAkB,CAC1CD,GAAQC,CACV,CAAC,EAED,QAAQ,MAAM,GAAG,MAAO,IAAM,CAC5B,IAAMC,EAAUF,EAAK,KAAK,EACrBE,EAGHJ,EAAQI,CAAO,EAFfH,EAAO,IAAI,MAAMI,EAAE,oBAAoB,CAAC,CAAC,CAI7C,CAAC,EAED,QAAQ,MAAM,GAAG,QAAUC,GAAe,CACxCL,EAAO,IAAI,MAAMI,EAAE,wBAAyB,CAAE,QAASC,EAAI,OAAQ,CAAC,CAAC,CAAC,CACxE,CAAC,EAGG,QAAQ,MAAM,OAChBL,EAAO,IAAI,MAAMI,EAAE,0BAA0B,CAAC,CAAC,CAEnD,CAAC,CACH,CAEA,eAAeN,GAAqC,CAelD,OAdgB,MAAMQ,EAAS,OAAO,CACpC,CACE,KAAM,QACN,KAAM,QACN,QAASF,EAAE,oBAAoB,EAC/B,SAAWG,GACL,CAACA,GAASA,EAAM,KAAK,IAAM,GACtBH,EAAE,uBAAuB,EAE3B,EAEX,CACF,CAAC,GAEe,MAAiB,KAAK,CACxC,CEpFA,OAAOI,MAAQ,WACf,OAAOC,MAAU,OACjB,OAAS,QAAAC,MAAY,OACrB,OAAOC,MAAS,MAChB,OAAOC,MAAW,QAClB,OAAS,iBAAAC,MAAqB,MAG9B,IAAMC,EAAaC,EAAc,YAAY,GAAG,EAC1CC,EAAYC,EAAK,QAAQH,CAAU,
|
|
6
|
-
"names": ["Command", "chalk", "chalk", "inquirer", "i18next", "Backend", "path", "fileURLToPath", "__filename", "__dirname", "initialized", "initI18n", "language", "t", "key", "options", "resolveInput", "options", "readStdin", "hasModelInput", "promptInteractive", "resolve", "reject", "data", "chunk", "trimmed", "t", "err", "inquirer", "input", "fs", "path", "glob", "ejs", "chalk", "fileURLToPath", "__filename", "fileURLToPath", "__dirname", "path", "SOURCE_AGENTS_DIR", "
|
|
4
|
+
"sourcesContent": ["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { run } from './index.js';\nimport { initI18n, t } from './i18n.js';\n\ninterface CliOptions {\n model?: string;\n interactive?: boolean;\n stdin?: boolean;\n lang?: string;\n}\n\nconst program = new Command();\n\nprogram\n .name('create-squirrel-opencode-harness')\n .description('Scaffold squirrel opencode harness into .opencode directory')\n .version('1.0.0')\n .option('-m, --model <model>', 'Model identifier for agents (e.g., fireworks-ai/accounts/fireworks/routers/kimi-k2p5-turbo)')\n .option('-i, --interactive', 'Use interactive mode to input model')\n .option('--stdin', 'Read model from stdin')\n .option('-l, --lang <lang>', 'Language (en/zh)', 'en')\n .argument('[model]', 'Model identifier (positional argument)')\n .action(async (positionalModel: string | undefined, options: CliOptions) => {\n try {\n // Initialize i18n with selected language\n const lang = options.lang === 'zh' ? 'zh' : 'en';\n await initI18n(lang);\n\n // Update program description based on language\n program.description(t('cli.description'));\n\n await run({\n positionalModel,\n ...options\n }, lang);\n } catch (error: unknown) {\n // Ensure i18n is initialized even for early errors\n if (error instanceof Error) {\n console.error(chalk.red('Error:'), error.message);\n } else {\n console.error(chalk.red('Error:'), String(error));\n }\n process.exit(1);\n }\n });\n\nprogram.parse();\n", "import chalk from 'chalk';\nimport { resolveInput } from './input.js';\nimport { checkDirectories, transactionalCopy, type DirectoryInfo } from './fileOps.js';\nimport { initI18n, t } from './i18n.js';\n\nexport interface RunOptions {\n positionalModel?: string;\n model?: string;\n interactive?: boolean;\n stdin?: boolean;\n lang?: string;\n}\n\nexport async function run(options: RunOptions = {}, lang: string = 'en'): Promise<void> {\n // Ensure i18n is initialized\n await initI18n(lang);\n\n console.log(chalk.blue(`\uD83D\uDC3F\uFE0F ${t('title')}\\n`));\n\n // Step 1: Resolve model input (from CLI args, stdin, or interactive)\n const model = await resolveInput(options);\n\n if (!model) {\n throw new Error(t('errors.modelRequired'));\n }\n\n console.log(chalk.gray(t('info.usingModel', { model }) + '\\n'));\n\n // Step 2: Check and create directories\n const dirs: DirectoryInfo = await checkDirectories();\n\n // Step 3: Transactional copy with template processing\n await transactionalCopy(model, dirs);\n\n console.log(chalk.green(`\\n\u2705 ${t('info.success')}`));\n console.log(chalk.gray(` ${t('info.location', { path: dirs.targetDir })}`));\n}\n", "import inquirer from 'inquirer';\nimport { t } from './i18n.js';\n\nexport interface InputOptions {\n positionalModel?: string;\n model?: string;\n interactive?: boolean;\n stdin?: boolean;\n}\n\nexport async function resolveInput(options: InputOptions): Promise<string | null> {\n // Priority 1: CLI argument (positional)\n if (options.positionalModel) {\n return options.positionalModel;\n }\n\n // Priority 2: CLI option --model\n if (options.model) {\n return options.model;\n }\n\n // Priority 3: Stdin\n if (options.stdin) {\n return readStdin();\n }\n\n // Priority 4: Interactive mode (if requested or as fallback)\n if (options.interactive || !hasModelInput(options)) {\n return promptInteractive();\n }\n\n return null;\n}\n\nfunction hasModelInput(options: InputOptions): boolean {\n return !!(options.positionalModel || options.model || options.stdin);\n}\n\nasync function readStdin(): Promise<string> {\n return new Promise((resolve, reject) => {\n let data = '';\n\n process.stdin.setEncoding('utf8');\n\n process.stdin.on('data', (chunk: string) => {\n data += chunk;\n });\n\n process.stdin.on('end', () => {\n const trimmed = data.trim();\n if (!trimmed) {\n reject(new Error(t('errors.stdinNoData')));\n } else {\n resolve(trimmed);\n }\n });\n\n process.stdin.on('error', (err: Error) => {\n reject(new Error(t('errors.stdinReadError', { message: err.message })));\n });\n\n // If stdin is a TTY (not piped), we need to handle it differently\n if (process.stdin.isTTY) {\n reject(new Error(t('errors.stdinNotAvailable')));\n }\n });\n}\n\nasync function promptInteractive(): Promise<string> {\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'model',\n message: t('prompts.enterModel'),\n validate: (input: string) => {\n if (!input || input.trim() === '') {\n return t('prompts.modelRequired');\n }\n return true;\n }\n }\n ]);\n\n return (answers.model as string).trim();\n}\n", "import i18next from 'i18next';\nimport Backend from 'i18next-fs-backend';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nlet initialized = false;\n\nexport async function initI18n(language: string = 'en'): Promise<typeof i18next> {\n if (initialized) {\n if (i18next.language !== language) {\n await i18next.changeLanguage(language);\n }\n return i18next;\n }\n\n await i18next.use(Backend).init({\n lng: language,\n fallbackLng: 'en',\n backend: {\n loadPath: path.join(__dirname, '../locales/{{lng}}/{{ns}}.json')\n },\n ns: ['translation'],\n defaultNS: 'translation',\n interpolation: {\n escapeValue: false // Disable escaping for CLI output\n }\n });\n\n initialized = true;\n return i18next;\n}\n\nexport function t(key: string, options?: Record<string, string | number>): string {\n return i18next.t(key, options);\n}\n\nexport { i18next };\n", "import fs from 'fs-extra';\nimport path from 'path';\nimport { glob } from 'glob';\nimport ejs from 'ejs';\nimport chalk from 'chalk';\nimport { fileURLToPath } from 'url';\nimport { t } from './i18n.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst SOURCE_AGENTS_DIR = path.resolve(__dirname, '..', 'agents');\n\nexport interface DirectoryInfo {\n sourceAgentsDir: string;\n targetDir: string;\n targetAgentsDir: string;\n targetHarnessDir: string;\n targetSprintsDir: string;\n hasSourceAgents: boolean;\n}\n\ninterface FileToCopy {\n source: string;\n target: string;\n relativePath: string;\n}\n\nfunction getTargetDirs() {\n const targetBaseDir = path.resolve(process.cwd(), '.opencode');\n return {\n targetBaseDir,\n targetAgentsDir: path.join(targetBaseDir, 'agents'),\n targetHarnessDir: path.join(targetBaseDir, 'harness'),\n targetSprintsDir: path.join(targetBaseDir, 'harness', 'sprints')\n };\n}\n\nexport async function checkDirectories(): Promise<DirectoryInfo> {\n console.log(chalk.gray(t('info.checkingDirs')));\n\n const hasSourceAgents = await fs.pathExists(SOURCE_AGENTS_DIR);\n\n if (!hasSourceAgents) {\n throw new Error(\n `${t('errors.sourceNotFound')}\\n` +\n ` - ${SOURCE_AGENTS_DIR}`\n );\n }\n\n const { targetBaseDir, targetAgentsDir, targetHarnessDir, targetSprintsDir } = getTargetDirs();\n\n await fs.ensureDir(targetBaseDir);\n console.log(chalk.gray(` \u2713 ${targetBaseDir}`));\n\n await fs.ensureDir(targetAgentsDir);\n console.log(chalk.gray(` \u2713 ${targetAgentsDir}`));\n\n await fs.ensureDir(targetHarnessDir);\n console.log(chalk.gray(` \u2713 ${targetHarnessDir}`));\n\n await fs.ensureDir(targetSprintsDir);\n console.log(chalk.gray(` \u2713 ${targetSprintsDir}`));\n\n return {\n sourceAgentsDir: SOURCE_AGENTS_DIR,\n targetDir: targetBaseDir,\n targetAgentsDir,\n targetHarnessDir,\n targetSprintsDir,\n hasSourceAgents\n };\n}\n\nexport async function transactionalCopy(model: string, dirs: DirectoryInfo): Promise<void> {\n console.log(chalk.gray(`\\n${t('info.transactionCheck')}`));\n\n const filesToCopy: FileToCopy[] = [];\n const existingFiles: string[] = [];\n\n const agentFiles = await glob('**/*.md', {\n cwd: dirs.sourceAgentsDir,\n absolute: true\n });\n\n for (const sourcePath of agentFiles) {\n const relativePath = path.relative(dirs.sourceAgentsDir, sourcePath);\n const targetPath = path.join(dirs.targetAgentsDir, relativePath);\n\n if (await fs.pathExists(targetPath)) {\n existingFiles.push(targetPath);\n } else {\n filesToCopy.push({\n source: sourcePath,\n target: targetPath,\n relativePath\n });\n }\n }\n\n // Check for existing harness directories that would conflict\n const harnessDirs = ['sprints'];\n for (const subDir of harnessDirs) {\n const targetPath = path.join(dirs.targetHarnessDir, subDir);\n if (await fs.pathExists(targetPath)) {\n const contents = await fs.readdir(targetPath);\n if (contents.length > 0) {\n existingFiles.push(targetPath);\n }\n }\n }\n\n if (existingFiles.length > 0) {\n console.error(chalk.red(`\\n\u274C ${t('transaction.failed')}`));\n for (const file of existingFiles) {\n console.error(chalk.red(` - ${file}`));\n }\n throw new Error(t('errors.transactionFailed', { count: existingFiles.length }));\n }\n\n console.log(chalk.gray(` \u2713 ${t('info.noConflicts', { count: filesToCopy.length })}`));\n\n console.log(chalk.gray(`\\n${t('info.copyingFiles')}`));\n\n for (const file of filesToCopy) {\n await fs.ensureDir(path.dirname(file.target));\n\n const content = await fs.readFile(file.source, 'utf-8');\n const processed = await processTemplate(content, { model });\n await fs.writeFile(file.target, processed);\n\n console.log(chalk.gray(` \u2713 ${file.relativePath}`));\n }\n}\n\nasync function processTemplate(content: string, data: Record<string, string>): Promise<string> {\n try {\n const result = ejs.render(content, data, {\n async: false\n });\n return result;\n } catch {\n return content;\n }\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Command", "chalk", "chalk", "inquirer", "i18next", "Backend", "path", "fileURLToPath", "__filename", "__dirname", "initialized", "initI18n", "language", "t", "key", "options", "resolveInput", "options", "readStdin", "hasModelInput", "promptInteractive", "resolve", "reject", "data", "chunk", "trimmed", "t", "err", "inquirer", "input", "fs", "path", "glob", "ejs", "chalk", "fileURLToPath", "__filename", "fileURLToPath", "__dirname", "path", "SOURCE_AGENTS_DIR", "getTargetDirs", "targetBaseDir", "checkDirectories", "chalk", "t", "hasSourceAgents", "fs", "targetAgentsDir", "targetHarnessDir", "targetSprintsDir", "transactionalCopy", "model", "dirs", "filesToCopy", "existingFiles", "agentFiles", "glob", "sourcePath", "relativePath", "targetPath", "harnessDirs", "subDir", "file", "content", "processed", "processTemplate", "data", "ejs", "run", "options", "lang", "initI18n", "chalk", "t", "model", "resolveInput", "dirs", "checkDirectories", "transactionalCopy", "program", "Command", "positionalModel", "options", "lang", "initI18n", "t", "run", "error", "chalk"]
|
|
7
7
|
}
|
package/dist/fileOps.js
CHANGED
|
@@ -8,41 +8,40 @@ import { t } from "./i18n.js";
|
|
|
8
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
9
|
const __dirname = path.dirname(__filename);
|
|
10
10
|
const SOURCE_AGENTS_DIR = path.resolve(__dirname, "..", "agents");
|
|
11
|
-
const SOURCE_HARNESS_DIR = path.resolve(__dirname, "..", "harness");
|
|
12
11
|
function getTargetDirs() {
|
|
13
12
|
const targetBaseDir = path.resolve(process.cwd(), ".opencode");
|
|
14
13
|
return {
|
|
15
14
|
targetBaseDir,
|
|
16
15
|
targetAgentsDir: path.join(targetBaseDir, "agents"),
|
|
17
|
-
targetHarnessDir: path.join(targetBaseDir, "harness")
|
|
16
|
+
targetHarnessDir: path.join(targetBaseDir, "harness"),
|
|
17
|
+
targetSprintsDir: path.join(targetBaseDir, "harness", "sprints")
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
async function checkDirectories() {
|
|
21
21
|
console.log(chalk.gray(t("info.checkingDirs")));
|
|
22
22
|
const hasSourceAgents = await fs.pathExists(SOURCE_AGENTS_DIR);
|
|
23
|
-
|
|
24
|
-
if (!hasSourceAgents && !hasSourceHarness) {
|
|
23
|
+
if (!hasSourceAgents) {
|
|
25
24
|
throw new Error(
|
|
26
25
|
`${t("errors.sourceNotFound")}
|
|
27
|
-
- ${SOURCE_AGENTS_DIR}
|
|
28
|
-
- ${SOURCE_HARNESS_DIR}`
|
|
26
|
+
- ${SOURCE_AGENTS_DIR}`
|
|
29
27
|
);
|
|
30
28
|
}
|
|
31
|
-
const { targetBaseDir, targetAgentsDir, targetHarnessDir } = getTargetDirs();
|
|
29
|
+
const { targetBaseDir, targetAgentsDir, targetHarnessDir, targetSprintsDir } = getTargetDirs();
|
|
32
30
|
await fs.ensureDir(targetBaseDir);
|
|
33
31
|
console.log(chalk.gray(` \u2713 ${targetBaseDir}`));
|
|
34
32
|
await fs.ensureDir(targetAgentsDir);
|
|
35
33
|
console.log(chalk.gray(` \u2713 ${targetAgentsDir}`));
|
|
36
34
|
await fs.ensureDir(targetHarnessDir);
|
|
37
35
|
console.log(chalk.gray(` \u2713 ${targetHarnessDir}`));
|
|
36
|
+
await fs.ensureDir(targetSprintsDir);
|
|
37
|
+
console.log(chalk.gray(` \u2713 ${targetSprintsDir}`));
|
|
38
38
|
return {
|
|
39
39
|
sourceAgentsDir: SOURCE_AGENTS_DIR,
|
|
40
|
-
sourceHarnessDir: SOURCE_HARNESS_DIR,
|
|
41
40
|
targetDir: targetBaseDir,
|
|
42
41
|
targetAgentsDir,
|
|
43
42
|
targetHarnessDir,
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
targetSprintsDir,
|
|
44
|
+
hasSourceAgents
|
|
46
45
|
};
|
|
47
46
|
}
|
|
48
47
|
async function transactionalCopy(model, dirs) {
|
|
@@ -50,44 +49,30 @@ async function transactionalCopy(model, dirs) {
|
|
|
50
49
|
${t("info.transactionCheck")}`));
|
|
51
50
|
const filesToCopy = [];
|
|
52
51
|
const existingFiles = [];
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
relativePath
|
|
69
|
-
});
|
|
70
|
-
}
|
|
52
|
+
const agentFiles = await glob("**/*.md", {
|
|
53
|
+
cwd: dirs.sourceAgentsDir,
|
|
54
|
+
absolute: true
|
|
55
|
+
});
|
|
56
|
+
for (const sourcePath of agentFiles) {
|
|
57
|
+
const relativePath = path.relative(dirs.sourceAgentsDir, sourcePath);
|
|
58
|
+
const targetPath = path.join(dirs.targetAgentsDir, relativePath);
|
|
59
|
+
if (await fs.pathExists(targetPath)) {
|
|
60
|
+
existingFiles.push(targetPath);
|
|
61
|
+
} else {
|
|
62
|
+
filesToCopy.push({
|
|
63
|
+
source: sourcePath,
|
|
64
|
+
target: targetPath,
|
|
65
|
+
relativePath
|
|
66
|
+
});
|
|
71
67
|
}
|
|
72
68
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
for (const sourcePath of harnessFiles) {
|
|
80
|
-
const relativePath = path.relative(dirs.sourceHarnessDir, sourcePath);
|
|
81
|
-
const targetPath = path.join(dirs.targetHarnessDir, relativePath);
|
|
82
|
-
if (await fs.pathExists(targetPath)) {
|
|
69
|
+
const harnessDirs = ["sprints"];
|
|
70
|
+
for (const subDir of harnessDirs) {
|
|
71
|
+
const targetPath = path.join(dirs.targetHarnessDir, subDir);
|
|
72
|
+
if (await fs.pathExists(targetPath)) {
|
|
73
|
+
const contents = await fs.readdir(targetPath);
|
|
74
|
+
if (contents.length > 0) {
|
|
83
75
|
existingFiles.push(targetPath);
|
|
84
|
-
} else {
|
|
85
|
-
filesToCopy.push({
|
|
86
|
-
source: sourcePath,
|
|
87
|
-
target: targetPath,
|
|
88
|
-
isAgent: false,
|
|
89
|
-
relativePath
|
|
90
|
-
});
|
|
91
76
|
}
|
|
92
77
|
}
|
|
93
78
|
}
|
|
@@ -104,13 +89,9 @@ ${t("info.transactionCheck")}`));
|
|
|
104
89
|
${t("info.copyingFiles")}`));
|
|
105
90
|
for (const file of filesToCopy) {
|
|
106
91
|
await fs.ensureDir(path.dirname(file.target));
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
await fs.writeFile(file.target, processed);
|
|
111
|
-
} else {
|
|
112
|
-
await fs.copy(file.source, file.target);
|
|
113
|
-
}
|
|
92
|
+
const content = await fs.readFile(file.source, "utf-8");
|
|
93
|
+
const processed = await processTemplate(content, { model });
|
|
94
|
+
await fs.writeFile(file.target, processed);
|
|
114
95
|
console.log(chalk.gray(` \u2713 ${file.relativePath}`));
|
|
115
96
|
}
|
|
116
97
|
}
|
|
@@ -120,7 +101,7 @@ async function processTemplate(content, data) {
|
|
|
120
101
|
async: false
|
|
121
102
|
});
|
|
122
103
|
return result;
|
|
123
|
-
} catch
|
|
104
|
+
} catch {
|
|
124
105
|
return content;
|
|
125
106
|
}
|
|
126
107
|
}
|
package/dist/fileOps.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/fileOps.ts"],
|
|
4
|
-
"sourcesContent": ["import fs from 'fs-extra';\nimport path from 'path';\nimport { glob } from 'glob';\nimport ejs from 'ejs';\nimport chalk from 'chalk';\nimport { fileURLToPath } from 'url';\nimport { t } from './i18n.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\
|
|
5
|
-
"mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,YAAY;AACrB,OAAO,SAAS;AAChB,OAAO,WAAW;AAClB,SAAS,qBAAqB;AAC9B,SAAS,SAAS;AAElB,MAAM,aAAa,cAAc,YAAY,GAAG;AAChD,MAAM,YAAY,KAAK,QAAQ,UAAU;
|
|
4
|
+
"sourcesContent": ["import fs from 'fs-extra';\nimport path from 'path';\nimport { glob } from 'glob';\nimport ejs from 'ejs';\nimport chalk from 'chalk';\nimport { fileURLToPath } from 'url';\nimport { t } from './i18n.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nconst SOURCE_AGENTS_DIR = path.resolve(__dirname, '..', 'agents');\n\nexport interface DirectoryInfo {\n sourceAgentsDir: string;\n targetDir: string;\n targetAgentsDir: string;\n targetHarnessDir: string;\n targetSprintsDir: string;\n hasSourceAgents: boolean;\n}\n\ninterface FileToCopy {\n source: string;\n target: string;\n relativePath: string;\n}\n\nfunction getTargetDirs() {\n const targetBaseDir = path.resolve(process.cwd(), '.opencode');\n return {\n targetBaseDir,\n targetAgentsDir: path.join(targetBaseDir, 'agents'),\n targetHarnessDir: path.join(targetBaseDir, 'harness'),\n targetSprintsDir: path.join(targetBaseDir, 'harness', 'sprints')\n };\n}\n\nexport async function checkDirectories(): Promise<DirectoryInfo> {\n console.log(chalk.gray(t('info.checkingDirs')));\n\n const hasSourceAgents = await fs.pathExists(SOURCE_AGENTS_DIR);\n\n if (!hasSourceAgents) {\n throw new Error(\n `${t('errors.sourceNotFound')}\\n` +\n ` - ${SOURCE_AGENTS_DIR}`\n );\n }\n\n const { targetBaseDir, targetAgentsDir, targetHarnessDir, targetSprintsDir } = getTargetDirs();\n\n await fs.ensureDir(targetBaseDir);\n console.log(chalk.gray(` \u2713 ${targetBaseDir}`));\n\n await fs.ensureDir(targetAgentsDir);\n console.log(chalk.gray(` \u2713 ${targetAgentsDir}`));\n\n await fs.ensureDir(targetHarnessDir);\n console.log(chalk.gray(` \u2713 ${targetHarnessDir}`));\n\n await fs.ensureDir(targetSprintsDir);\n console.log(chalk.gray(` \u2713 ${targetSprintsDir}`));\n\n return {\n sourceAgentsDir: SOURCE_AGENTS_DIR,\n targetDir: targetBaseDir,\n targetAgentsDir,\n targetHarnessDir,\n targetSprintsDir,\n hasSourceAgents\n };\n}\n\nexport async function transactionalCopy(model: string, dirs: DirectoryInfo): Promise<void> {\n console.log(chalk.gray(`\\n${t('info.transactionCheck')}`));\n\n const filesToCopy: FileToCopy[] = [];\n const existingFiles: string[] = [];\n\n const agentFiles = await glob('**/*.md', {\n cwd: dirs.sourceAgentsDir,\n absolute: true\n });\n\n for (const sourcePath of agentFiles) {\n const relativePath = path.relative(dirs.sourceAgentsDir, sourcePath);\n const targetPath = path.join(dirs.targetAgentsDir, relativePath);\n\n if (await fs.pathExists(targetPath)) {\n existingFiles.push(targetPath);\n } else {\n filesToCopy.push({\n source: sourcePath,\n target: targetPath,\n relativePath\n });\n }\n }\n\n // Check for existing harness directories that would conflict\n const harnessDirs = ['sprints'];\n for (const subDir of harnessDirs) {\n const targetPath = path.join(dirs.targetHarnessDir, subDir);\n if (await fs.pathExists(targetPath)) {\n const contents = await fs.readdir(targetPath);\n if (contents.length > 0) {\n existingFiles.push(targetPath);\n }\n }\n }\n\n if (existingFiles.length > 0) {\n console.error(chalk.red(`\\n\u274C ${t('transaction.failed')}`));\n for (const file of existingFiles) {\n console.error(chalk.red(` - ${file}`));\n }\n throw new Error(t('errors.transactionFailed', { count: existingFiles.length }));\n }\n\n console.log(chalk.gray(` \u2713 ${t('info.noConflicts', { count: filesToCopy.length })}`));\n\n console.log(chalk.gray(`\\n${t('info.copyingFiles')}`));\n\n for (const file of filesToCopy) {\n await fs.ensureDir(path.dirname(file.target));\n\n const content = await fs.readFile(file.source, 'utf-8');\n const processed = await processTemplate(content, { model });\n await fs.writeFile(file.target, processed);\n\n console.log(chalk.gray(` \u2713 ${file.relativePath}`));\n }\n}\n\nasync function processTemplate(content: string, data: Record<string, string>): Promise<string> {\n try {\n const result = ejs.render(content, data, {\n async: false\n });\n return result;\n } catch {\n return content;\n }\n}"],
|
|
5
|
+
"mappings": "AAAA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,YAAY;AACrB,OAAO,SAAS;AAChB,OAAO,WAAW;AAClB,SAAS,qBAAqB;AAC9B,SAAS,SAAS;AAElB,MAAM,aAAa,cAAc,YAAY,GAAG;AAChD,MAAM,YAAY,KAAK,QAAQ,UAAU;AAEzC,MAAM,oBAAoB,KAAK,QAAQ,WAAW,MAAM,QAAQ;AAiBhE,SAAS,gBAAgB;AACvB,QAAM,gBAAgB,KAAK,QAAQ,QAAQ,IAAI,GAAG,WAAW;AAC7D,SAAO;AAAA,IACL;AAAA,IACA,iBAAiB,KAAK,KAAK,eAAe,QAAQ;AAAA,IAClD,kBAAkB,KAAK,KAAK,eAAe,SAAS;AAAA,IACpD,kBAAkB,KAAK,KAAK,eAAe,WAAW,SAAS;AAAA,EACjE;AACF;AAEA,eAAsB,mBAA2C;AAC/D,UAAQ,IAAI,MAAM,KAAK,EAAE,mBAAmB,CAAC,CAAC;AAE9C,QAAM,kBAAkB,MAAM,GAAG,WAAW,iBAAiB;AAE7D,MAAI,CAAC,iBAAiB;AACpB,UAAM,IAAI;AAAA,MACR,GAAG,EAAE,uBAAuB,CAAC;AAAA,MACtB,iBAAiB;AAAA,IAC1B;AAAA,EACF;AAEA,QAAM,EAAE,eAAe,iBAAiB,kBAAkB,iBAAiB,IAAI,cAAc;AAE7F,QAAM,GAAG,UAAU,aAAa;AAChC,UAAQ,IAAI,MAAM,KAAK,YAAO,aAAa,EAAE,CAAC;AAE9C,QAAM,GAAG,UAAU,eAAe;AAClC,UAAQ,IAAI,MAAM,KAAK,YAAO,eAAe,EAAE,CAAC;AAEhD,QAAM,GAAG,UAAU,gBAAgB;AACnC,UAAQ,IAAI,MAAM,KAAK,YAAO,gBAAgB,EAAE,CAAC;AAEjD,QAAM,GAAG,UAAU,gBAAgB;AACnC,UAAQ,IAAI,MAAM,KAAK,YAAO,gBAAgB,EAAE,CAAC;AAEjD,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,kBAAkB,OAAe,MAAoC;AACzF,UAAQ,IAAI,MAAM,KAAK;AAAA,EAAK,EAAE,uBAAuB,CAAC,EAAE,CAAC;AAEzD,QAAM,cAA4B,CAAC;AACnC,QAAM,gBAA0B,CAAC;AAEjC,QAAM,aAAa,MAAM,KAAK,WAAW;AAAA,IACvC,KAAK,KAAK;AAAA,IACV,UAAU;AAAA,EACZ,CAAC;AAED,aAAW,cAAc,YAAY;AACnC,UAAM,eAAe,KAAK,SAAS,KAAK,iBAAiB,UAAU;AACnE,UAAM,aAAa,KAAK,KAAK,KAAK,iBAAiB,YAAY;AAE/D,QAAI,MAAM,GAAG,WAAW,UAAU,GAAG;AACnC,oBAAc,KAAK,UAAU;AAAA,IAC/B,OAAO;AACL,kBAAY,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,cAAc,CAAC,SAAS;AAC9B,aAAW,UAAU,aAAa;AAChC,UAAM,aAAa,KAAK,KAAK,KAAK,kBAAkB,MAAM;AAC1D,QAAI,MAAM,GAAG,WAAW,UAAU,GAAG;AACnC,YAAM,WAAW,MAAM,GAAG,QAAQ,UAAU;AAC5C,UAAI,SAAS,SAAS,GAAG;AACvB,sBAAc,KAAK,UAAU;AAAA,MAC/B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc,SAAS,GAAG;AAC5B,YAAQ,MAAM,MAAM,IAAI;AAAA,SAAO,EAAE,oBAAoB,CAAC,EAAE,CAAC;AACzD,eAAW,QAAQ,eAAe;AAChC,cAAQ,MAAM,MAAM,IAAI,QAAQ,IAAI,EAAE,CAAC;AAAA,IACzC;AACA,UAAM,IAAI,MAAM,EAAE,4BAA4B,EAAE,OAAO,cAAc,OAAO,CAAC,CAAC;AAAA,EAChF;AAEA,UAAQ,IAAI,MAAM,KAAK,YAAO,EAAE,oBAAoB,EAAE,OAAO,YAAY,OAAO,CAAC,CAAC,EAAE,CAAC;AAErF,UAAQ,IAAI,MAAM,KAAK;AAAA,EAAK,EAAE,mBAAmB,CAAC,EAAE,CAAC;AAErD,aAAW,QAAQ,aAAa;AAC9B,UAAM,GAAG,UAAU,KAAK,QAAQ,KAAK,MAAM,CAAC;AAE5C,UAAM,UAAU,MAAM,GAAG,SAAS,KAAK,QAAQ,OAAO;AACtD,UAAM,YAAY,MAAM,gBAAgB,SAAS,EAAE,MAAM,CAAC;AAC1D,UAAM,GAAG,UAAU,KAAK,QAAQ,SAAS;AAEzC,YAAQ,IAAI,MAAM,KAAK,YAAO,KAAK,YAAY,EAAE,CAAC;AAAA,EACpD;AACF;AAEA,eAAe,gBAAgB,SAAiB,MAA+C;AAC7F,MAAI;AACF,UAAM,SAAS,IAAI,OAAO,SAAS,MAAM;AAAA,MACvC,OAAO;AAAA,IACT,CAAC;AACD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
# Sprint Contract: Sprint [N] — [Name]
|
|
2
|
-
|
|
3
|
-
## Scope
|
|
4
|
-
[What this sprint will build, based on the spec]
|
|
5
|
-
|
|
6
|
-
## Implementation Plan
|
|
7
|
-
[High-level approach]
|
|
8
|
-
- [Key technical decisions]
|
|
9
|
-
- [Component structure]
|
|
10
|
-
- [API endpoints if applicable]
|
|
11
|
-
|
|
12
|
-
## Success Criteria
|
|
13
|
-
1. **[Criterion]**: [How to verify — must be specific and testable]
|
|
14
|
-
2. **[Criterion]**: [How to verify]
|
|
15
|
-
3. **[Criterion]**: [How to verify]
|
|
16
|
-
|
|
17
|
-
## Out of Scope for This Sprint
|
|
18
|
-
- [What is explicitly NOT being built this sprint]
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Evaluation: Sprint [N]
|
|
2
|
-
|
|
3
|
-
## Overall Verdict: [PASS / FAIL]
|
|
4
|
-
|
|
5
|
-
## Success Criteria Results
|
|
6
|
-
1. **[Criterion]**: [PASS / FAIL]
|
|
7
|
-
- Expected: [what was expected]
|
|
8
|
-
- Actual: [what actually happened]
|
|
9
|
-
- Reproduction (if FAIL): [steps]
|
|
10
|
-
|
|
11
|
-
## Bug Report
|
|
12
|
-
1. **[Bug Title]**: [Severity: Critical/Major/Minor]
|
|
13
|
-
- Steps to reproduce: [...]
|
|
14
|
-
- Expected: [...]
|
|
15
|
-
- Actual: [...]
|
|
16
|
-
- Location: [file:line or UI location]
|
|
17
|
-
|
|
18
|
-
## Scoring
|
|
19
|
-
|
|
20
|
-
### Product Depth: [score]/10
|
|
21
|
-
[Justification]
|
|
22
|
-
|
|
23
|
-
### Functionality: [score]/10
|
|
24
|
-
[Justification]
|
|
25
|
-
|
|
26
|
-
### Visual Design: [score]/10
|
|
27
|
-
[Justification]
|
|
28
|
-
|
|
29
|
-
### Code Quality: [score]/10
|
|
30
|
-
[Justification]
|
|
31
|
-
|
|
32
|
-
**Hard threshold**: Any dimension below 4/10 = automatic FAIL.
|
|
33
|
-
|
|
34
|
-
## Detailed Critique
|
|
35
|
-
[Paragraph-form assessment with concrete examples]
|
|
36
|
-
|
|
37
|
-
## Required Fixes (if FAIL)
|
|
38
|
-
1. [Specific, actionable fix]
|
|
39
|
-
2. [Specific, actionable fix]
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# Harness Run Summary
|
|
2
|
-
|
|
3
|
-
## Original Prompt
|
|
4
|
-
[The user's original prompt]
|
|
5
|
-
|
|
6
|
-
## Sprints Completed
|
|
7
|
-
|
|
8
|
-
### Sprint [N]: [Name] — [PASS/FAIL/PARTIAL]
|
|
9
|
-
- Evaluation rounds: [count]
|
|
10
|
-
- Issues found and addressed: [summary]
|
|
11
|
-
|
|
12
|
-
## Final Assessment
|
|
13
|
-
[Overall assessment of the built application]
|
|
14
|
-
|
|
15
|
-
## Known Gaps
|
|
16
|
-
[Issues that remain unresolved]
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Handoff: Sprint [N]
|
|
2
|
-
|
|
3
|
-
## Status: [Ready for QA / Not Ready — explain why]
|
|
4
|
-
|
|
5
|
-
## What to Test
|
|
6
|
-
[Step-by-step instructions for the evaluator]
|
|
7
|
-
1. [Step 1]
|
|
8
|
-
2. [Step 2]
|
|
9
|
-
|
|
10
|
-
## Running the Application
|
|
11
|
-
[How to start/restart the app]
|
|
12
|
-
|
|
13
|
-
## Known Gaps
|
|
14
|
-
[Honest assessment of anything not fully working]
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
# Self-Evaluation: Sprint [N]
|
|
2
|
-
|
|
3
|
-
## What Was Built
|
|
4
|
-
[Summary of implemented features]
|
|
5
|
-
|
|
6
|
-
## Success Criteria Check
|
|
7
|
-
- [x] Criterion 1: [notes]
|
|
8
|
-
- [ ] Criterion 2: [notes on what's missing]
|
|
9
|
-
|
|
10
|
-
## Known Issues
|
|
11
|
-
- [Bugs, limitations, or deviations from the contract]
|
|
12
|
-
|
|
13
|
-
## Decisions Made
|
|
14
|
-
- [Significant implementation decisions and rationale]
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# Product Specification: [Product Name]
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
[2-3 paragraph vision statement describing what this product is, who it's for, and why it matters]
|
|
5
|
-
|
|
6
|
-
## Core Features
|
|
7
|
-
|
|
8
|
-
1. **[Feature Name]**: [Description]
|
|
9
|
-
- User stories:
|
|
10
|
-
- As a [type of user], I can [action] so that [benefit]
|
|
11
|
-
- Acceptance criteria:
|
|
12
|
-
- [Given/When/Then or testable condition]
|
|
13
|
-
|
|
14
|
-
2. **[Feature Name]**: [Description]
|
|
15
|
-
- User stories:
|
|
16
|
-
- As a [type of user], I can [action] so that [benefit]
|
|
17
|
-
- Acceptance criteria:
|
|
18
|
-
- [Given/When/Then or testable condition]
|
|
19
|
-
|
|
20
|
-
## AI Integration
|
|
21
|
-
- AI Agent capabilities: [what the agent can do]
|
|
22
|
-
- AI Agent tools: [what tools/functions the agent has access to]
|
|
23
|
-
- User interaction model: [how the user invokes and interacts with the AI]
|
|
24
|
-
|
|
25
|
-
## Technical Architecture
|
|
26
|
-
- Frontend: [framework, styling approach]
|
|
27
|
-
- Backend: [framework, database]
|
|
28
|
-
- Key patterns: [architectural patterns]
|
|
29
|
-
|
|
30
|
-
## Visual Design Direction
|
|
31
|
-
- Aesthetic: [direction statement]
|
|
32
|
-
- Color palette: [direction statement]
|
|
33
|
-
- Typography: [direction statement]
|
|
34
|
-
- Layout principles: [direction statement]
|
|
35
|
-
|
|
36
|
-
## Sprint Breakdown
|
|
37
|
-
|
|
38
|
-
### Sprint 1: [Name]
|
|
39
|
-
- Scope: [what's being built]
|
|
40
|
-
- Dependencies: none
|
|
41
|
-
- Delivers: [tangible output]
|
|
42
|
-
- Acceptance criteria:
|
|
43
|
-
- [testable condition]
|
|
44
|
-
|
|
45
|
-
### Sprint 2: [Name]
|
|
46
|
-
- Scope: [what's being built]
|
|
47
|
-
- Dependencies: Sprint 1
|
|
48
|
-
- Delivers: [tangible output]
|
|
49
|
-
- Acceptance criteria:
|
|
50
|
-
- [testable condition]
|
|
51
|
-
|
|
52
|
-
## Out of Scope
|
|
53
|
-
- [Explicit exclusions]
|