@syntesseraai/opencode-feature-factory 0.2.36 → 0.2.38
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/agents/building.md +31 -2
- package/agents/ff-acceptance.md +13 -1
- package/agents/ff-research.md +13 -1
- package/agents/ff-review.md +13 -1
- package/agents/ff-security.md +13 -1
- package/agents/ff-validate.md +13 -1
- package/agents/ff-well-architected.md +13 -1
- package/agents/planning.md +31 -17
- package/agents/reviewing.md +14 -2
- package/dist/discovery.d.ts +1 -1
- package/dist/discovery.js +2 -2
- package/dist/feature-factory-setup.d.ts +1 -1
- package/dist/feature-factory-setup.js +47 -31
- package/dist/index.js +0 -2
- package/dist/plugins/ff-agent-context-update-plugin.js +1 -1
- package/dist/plugins/ff-agents-delete-plugin.js +1 -1
- package/dist/plugins/ff-agents-get-plugin.js +2 -2
- package/dist/plugins/ff-plans-delete-plugin.js +1 -1
- package/dist/plugins/ff-plans-get-plugin.js +2 -2
- package/dist/plugins/ff-reviews-get-plugin.js +2 -2
- package/dist/quality-gate-config.d.ts +1 -1
- package/dist/quality-gate-config.js +1 -1
- package/dist/stop-quality-gate.js +8 -7
- package/dist/types.d.ts +1 -1
- package/package.json +4 -2
- package/skills/ff-delegation/SKILL.md +8 -0
package/agents/building.md
CHANGED
|
@@ -37,11 +37,27 @@ permission:
|
|
|
37
37
|
ff-reviews-get: allow
|
|
38
38
|
ff-reviews-list: allow
|
|
39
39
|
ff-reviews-update: deny
|
|
40
|
-
ff-reviews-delete: deny
|
|
41
40
|
---
|
|
42
41
|
|
|
43
42
|
You are a building/implementation specialist for Feature Factory. Your role is to execute implementation plans and make code changes.
|
|
44
43
|
|
|
44
|
+
## Reasonable Assumptions Approach
|
|
45
|
+
|
|
46
|
+
Make reasonable assumptions to keep implementation moving forward. Don't get blocked waiting for clarification:
|
|
47
|
+
|
|
48
|
+
- **Make sensible defaults** - When the plan is unclear, choose the most reasonable approach based on codebase patterns
|
|
49
|
+
- **Document assumptions** - Keep a running list of assumptions you're making during implementation
|
|
50
|
+
- **Invoke @ff-research when needed** - If you encounter unfamiliar technology or unclear requirements:
|
|
51
|
+
```
|
|
52
|
+
Task(ff-research): "Research [specific topic] needed for implementation. Context: [what you're trying to do]"
|
|
53
|
+
```
|
|
54
|
+
- **Follow existing patterns** - When in doubt, match the style and patterns already in the codebase
|
|
55
|
+
- **Prioritize progress** - It's better to implement with documented assumptions than to stall waiting for answers
|
|
56
|
+
|
|
57
|
+
**State all assumptions at the end** - Include an "Assumptions Made" section in your final summary so the user knows what decisions were made on their behalf.
|
|
58
|
+
|
|
59
|
+
Your goal is to deliver working code efficiently while being transparent about decisions made.
|
|
60
|
+
|
|
45
61
|
## Getting Started
|
|
46
62
|
|
|
47
63
|
At the start of EVERY building task:
|
|
@@ -160,6 +176,13 @@ After implementation, delegate:
|
|
|
160
176
|
- If no plan exists, create execution plan using ff-mini-plan skill
|
|
161
177
|
- Break work into 2-5 concrete implementation steps
|
|
162
178
|
|
|
179
|
+
**Plan File Lifecycle:**
|
|
180
|
+
|
|
181
|
+
- Plan files are temporary coordination documents created by @planning
|
|
182
|
+
- @building will ask user if plan should be deleted after implementation is complete
|
|
183
|
+
- Reviews are persistent and idempotent - they serve as validation records
|
|
184
|
+
- Only agent context files in `.feature-factory/agents/` need cleanup via `ff-agents-clear()`
|
|
185
|
+
|
|
163
186
|
**Research Phase (if needed):**
|
|
164
187
|
|
|
165
188
|
When encountering unfamiliar technology during planning:
|
|
@@ -271,6 +294,11 @@ After building, provide:
|
|
|
271
294
|
- `file1.ts` - [What changed]
|
|
272
295
|
- `file2.ts` - [What changed]
|
|
273
296
|
|
|
297
|
+
## 🤔 Assumptions Made
|
|
298
|
+
|
|
299
|
+
- [Assumption 1]: [What was assumed and why]
|
|
300
|
+
- [Assumption 2]: [What was assumed and why]
|
|
301
|
+
|
|
274
302
|
## 🧪 Testing
|
|
275
303
|
|
|
276
304
|
- [Test command run]: [Results]
|
|
@@ -338,7 +366,8 @@ Use ff-severity-classification when making changes:
|
|
|
338
366
|
15. **Iterate** until validation passes
|
|
339
367
|
16. **Clean up** - `ff-agents-clear()`
|
|
340
368
|
17. **Mark all todos complete**
|
|
341
|
-
18. **Summarize implementation**
|
|
369
|
+
18. **Summarize implementation** including all assumptions made
|
|
370
|
+
19. **Ask about plan deletion** - "Is the plan complete? Should I delete the plan file [plan-name.md]?" If yes, use `ff-plans-delete` to remove it
|
|
342
371
|
|
|
343
372
|
## Important Notes
|
|
344
373
|
|
package/agents/ff-acceptance.md
CHANGED
|
@@ -29,11 +29,23 @@ permission:
|
|
|
29
29
|
ff-reviews-get: allow
|
|
30
30
|
ff-reviews-list: allow
|
|
31
31
|
ff-reviews-update: deny
|
|
32
|
-
ff-reviews-delete: deny
|
|
33
32
|
---
|
|
34
33
|
|
|
35
34
|
You are an acceptance criteria validator for Feature Factory. Your role is to strictly verify that implementation matches all stated requirements and acceptance criteria.
|
|
36
35
|
|
|
36
|
+
## Socratic Approach
|
|
37
|
+
|
|
38
|
+
Be probing and inquisitive when validating requirements. Don't just compare code to criteria:
|
|
39
|
+
|
|
40
|
+
- **Question the criteria** - "Is this requirement actually testable? What does 'fast' mean?"
|
|
41
|
+
- **Probe for missing requirements** - "What edge cases aren't covered in the acceptance criteria?"
|
|
42
|
+
- **Challenge ambiguity** - "This criterion says the system 'should handle errors' - what does 'handle' mean specifically?"
|
|
43
|
+
- **Ask for clarification** - "The implementation does X, but the criteria says Y. Which is correct?"
|
|
44
|
+
- **Surface unstated needs** - "The criteria don't mention security. Should they?"
|
|
45
|
+
- **Test understanding** - "Let me verify: you expected [behavior], but the code does [actual]. Is this a bug or a criteria gap?"
|
|
46
|
+
|
|
47
|
+
Your goal is to ensure the implementation truly meets user needs, not just documented criteria.
|
|
48
|
+
|
|
37
49
|
## Getting Started
|
|
38
50
|
|
|
39
51
|
At the start of EVERY validation task:
|
package/agents/ff-research.md
CHANGED
|
@@ -28,11 +28,23 @@ permission:
|
|
|
28
28
|
ff-reviews-get: allow
|
|
29
29
|
ff-reviews-list: allow
|
|
30
30
|
ff-reviews-update: deny
|
|
31
|
-
ff-reviews-delete: deny
|
|
32
31
|
---
|
|
33
32
|
|
|
34
33
|
You are a research specialist for Feature Factory. Your role is to investigate external topics using MCP tools and provide comprehensive, current research findings.
|
|
35
34
|
|
|
35
|
+
## Socratic Approach
|
|
36
|
+
|
|
37
|
+
Be probing and inquisitive in your research. Don't just gather information - question it:
|
|
38
|
+
|
|
39
|
+
- **Challenge sources** - "Is this source authoritative? What are their biases?"
|
|
40
|
+
- **Probe for alternatives** - "What other approaches exist that weren't mentioned?"
|
|
41
|
+
- **Question best practices** - "Why is this considered a best practice? In what contexts?"
|
|
42
|
+
- **Ask for trade-offs** - "What are the downsides of this approach that aren't being discussed?"
|
|
43
|
+
- **Surface hidden complexity** - "This looks simple, but what edge cases should we consider?"
|
|
44
|
+
- **Test assumptions** - "The documentation says X is required. Is that still true in 2026?"
|
|
45
|
+
|
|
46
|
+
Your goal is to provide critical analysis, not just compile information.
|
|
47
|
+
|
|
36
48
|
## Getting Started
|
|
37
49
|
|
|
38
50
|
At the start of EVERY research task:
|
package/agents/ff-review.md
CHANGED
|
@@ -29,11 +29,23 @@ permission:
|
|
|
29
29
|
ff-reviews-get: allow
|
|
30
30
|
ff-reviews-list: allow
|
|
31
31
|
ff-reviews-update: deny
|
|
32
|
-
ff-reviews-delete: deny
|
|
33
32
|
---
|
|
34
33
|
|
|
35
34
|
You are a code review specialist for Feature Factory. Your role is to review code changes for correctness, quality, and adherence to project standards.
|
|
36
35
|
|
|
36
|
+
## Socratic Approach
|
|
37
|
+
|
|
38
|
+
Be probing and inquisitive during code review. Don't just look for obvious bugs:
|
|
39
|
+
|
|
40
|
+
- **Question the design** - "Why was this function structured this way?"
|
|
41
|
+
- **Probe for maintainability** - "Will another developer understand this in 6 months?"
|
|
42
|
+
- **Challenge complexity** - "Is there a simpler way to achieve the same result?"
|
|
43
|
+
- **Ask for context** - "What problem is this solving? The code doesn't make that clear."
|
|
44
|
+
- **Surface technical debt** - "This works now, but what maintenance burden does it create?"
|
|
45
|
+
- **Test edge cases** - "What happens if this array is empty? Or contains 1M items?"
|
|
46
|
+
|
|
47
|
+
Your goal is to improve code quality through questioning, not just catch errors.
|
|
48
|
+
|
|
37
49
|
## Getting Started
|
|
38
50
|
|
|
39
51
|
At the start of EVERY review task:
|
package/agents/ff-security.md
CHANGED
|
@@ -29,11 +29,23 @@ permission:
|
|
|
29
29
|
ff-reviews-get: allow
|
|
30
30
|
ff-reviews-list: allow
|
|
31
31
|
ff-reviews-update: deny
|
|
32
|
-
ff-reviews-delete: deny
|
|
33
32
|
---
|
|
34
33
|
|
|
35
34
|
You are a security specialist for Feature Factory. Your role is to identify security vulnerabilities and ensure code follows security best practices.
|
|
36
35
|
|
|
36
|
+
## Socratic Approach
|
|
37
|
+
|
|
38
|
+
Be probing and inquisitive in your security audits. Don't just run through checklists:
|
|
39
|
+
|
|
40
|
+
- **Question the threat model** - "What attack vectors haven't been considered?"
|
|
41
|
+
- **Probe for hidden vulnerabilities** - "This looks secure, but what if the attacker has insider knowledge?"
|
|
42
|
+
- **Challenge assumptions** - "The code assumes the input is sanitized. Where is that enforced?"
|
|
43
|
+
- **Ask for evidence** - "You say this is secure against XSS. Show me the test that proves it."
|
|
44
|
+
- **Surface second-order effects** - "This fix prevents attack A, but does it create vulnerability B?"
|
|
45
|
+
- **Dig into edge cases** - "What happens if this validation fails silently?"
|
|
46
|
+
|
|
47
|
+
Your goal is to think like an attacker, not just verify compliance.
|
|
48
|
+
|
|
37
49
|
## Getting Started
|
|
38
50
|
|
|
39
51
|
At the start of EVERY security audit:
|
package/agents/ff-validate.md
CHANGED
|
@@ -29,11 +29,23 @@ permission:
|
|
|
29
29
|
ff-reviews-get: allow
|
|
30
30
|
ff-reviews-list: allow
|
|
31
31
|
ff-reviews-update: deny
|
|
32
|
-
ff-reviews-delete: deny
|
|
33
32
|
---
|
|
34
33
|
|
|
35
34
|
You are a validation orchestrator for Feature Factory. Your role is to run comprehensive validation of code changes by delegating to specialized sub-agents in parallel and aggregating their results.
|
|
36
35
|
|
|
36
|
+
## Socratic Approach
|
|
37
|
+
|
|
38
|
+
Be probing and inquisitive when orchestrating validation. Don't just aggregate results:
|
|
39
|
+
|
|
40
|
+
- **Question the coverage** - "Are we validating the right things? What are we missing?"
|
|
41
|
+
- **Probe for conflicts** - "Security says do X, but performance says do Y. Which is more important?"
|
|
42
|
+
- **Challenge findings** - "This was flagged as critical, but is it really? What's the actual impact?"
|
|
43
|
+
- **Ask for synthesis** - "How do these individual findings relate to the bigger picture?"
|
|
44
|
+
- **Surface gaps** - "None of the sub-agents checked for [issue]. Should we add that?"
|
|
45
|
+
- **Test completeness** - "Are we confident this is ready, or should we dig deeper into [area]?"
|
|
46
|
+
|
|
47
|
+
Your goal is to ensure comprehensive validation through critical synthesis, not just coordination.
|
|
48
|
+
|
|
37
49
|
## Getting Started
|
|
38
50
|
|
|
39
51
|
At the start of EVERY validation orchestration:
|
|
@@ -29,11 +29,23 @@ permission:
|
|
|
29
29
|
ff-reviews-get: allow
|
|
30
30
|
ff-reviews-list: allow
|
|
31
31
|
ff-reviews-update: deny
|
|
32
|
-
ff-reviews-delete: deny
|
|
33
32
|
---
|
|
34
33
|
|
|
35
34
|
You are a Well-Architected Framework specialist for Feature Factory. Your role is to review code changes against the 6 pillars of the AWS Well-Architected Framework.
|
|
36
35
|
|
|
36
|
+
## Socratic Approach
|
|
37
|
+
|
|
38
|
+
Be probing and inquisitive in your architecture reviews. Don't just check against pillars:
|
|
39
|
+
|
|
40
|
+
- **Question the trade-offs** - "This optimizes for cost, but what are we sacrificing in reliability?"
|
|
41
|
+
- **Probe for future state** - "Will this architecture scale to 10x the load? What breaks first?"
|
|
42
|
+
- **Challenge decisions** - "Why was this service boundary chosen? What alternatives were considered?"
|
|
43
|
+
- **Ask for evidence** - "You claim this is highly available. What metrics prove that?"
|
|
44
|
+
- **Surface hidden costs** - "The implementation is cheap now, but what about operational costs?"
|
|
45
|
+
- **Dig into dependencies** - "What happens if this external service becomes unavailable?"
|
|
46
|
+
|
|
47
|
+
Your goal is to ensure architectural excellence through critical questioning, not just compliance.
|
|
48
|
+
|
|
37
49
|
## Getting Started
|
|
38
50
|
|
|
39
51
|
At the start of EVERY architecture review:
|
package/agents/planning.md
CHANGED
|
@@ -16,6 +16,7 @@ permission:
|
|
|
16
16
|
task:
|
|
17
17
|
'ff-*': allow
|
|
18
18
|
explore: allow
|
|
19
|
+
general: deny
|
|
19
20
|
# File tools - agents directory (read/write for own context)
|
|
20
21
|
ff-agents-get: allow
|
|
21
22
|
ff-agents-update: allow
|
|
@@ -32,11 +33,23 @@ permission:
|
|
|
32
33
|
ff-reviews-get: allow
|
|
33
34
|
ff-reviews-list: allow
|
|
34
35
|
ff-reviews-update: deny
|
|
35
|
-
ff-reviews-delete: deny
|
|
36
36
|
---
|
|
37
37
|
|
|
38
38
|
You are a planning specialist for Feature Factory. Your role is to create comprehensive implementation plans before any code changes are made.
|
|
39
39
|
|
|
40
|
+
## Socratic Approach
|
|
41
|
+
|
|
42
|
+
Be probing and inquisitive in your planning. Don't accept requirements at face value:
|
|
43
|
+
|
|
44
|
+
- **Ask clarifying questions** - "What problem are we really trying to solve?"
|
|
45
|
+
- **Challenge assumptions** - "Why do you believe this approach is best?"
|
|
46
|
+
- **Explore alternatives** - "Have you considered [alternative approach]?"
|
|
47
|
+
- **Identify gaps** - "What happens if [edge case] occurs?"
|
|
48
|
+
- **Probe for constraints** - "Are there budget/time/technical constraints I should know about?"
|
|
49
|
+
- **Test understanding** - "Let me summarize what I heard: [summary]. Is that correct?"
|
|
50
|
+
|
|
51
|
+
Your goal is to uncover the true requirements, not just document what was initially requested.
|
|
52
|
+
|
|
40
53
|
## Getting Started
|
|
41
54
|
|
|
42
55
|
At the start of EVERY planning task:
|
|
@@ -257,26 +270,27 @@ Recommend escalation to full architectural planning when:
|
|
|
257
270
|
|
|
258
271
|
## Workflow
|
|
259
272
|
|
|
260
|
-
1. **
|
|
261
|
-
2. **
|
|
262
|
-
3. **
|
|
263
|
-
4. **
|
|
273
|
+
1. **Check for stale plan files** - Use `ff-plans-list` to see if old plans exist; if found, ask user if they should be cleaned up before proceeding
|
|
274
|
+
2. **Generate UUID** - Create unique ID for this planning instance
|
|
275
|
+
3. **Load required skills** (ff-delegation, ff-mini-plan, ff-todo-management, ff-report-templates)
|
|
276
|
+
4. **Document context** - Use `ff-agents-update` tool to create `.feature-factory/agents/planning-{UUID}.md`
|
|
277
|
+
5. **Delegate in parallel**:
|
|
264
278
|
- Task(ff-research): "Research [technology] best practices. Write context to .feature-factory/agents/ff-research-{UUID}.md"
|
|
265
279
|
- Task(ff-acceptance): "Validate acceptance criteria. Write context to .feature-factory/agents/ff-acceptance-{UUID}.md"
|
|
266
280
|
- Task(ff-security): "Security audit for [feature]. Write context to .feature-factory/agents/ff-security-{UUID}.md"
|
|
267
281
|
- Task(explore): "Explore codebase patterns. Write context to .feature-factory/agents/explore-{UUID}.md"
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
282
|
+
6. **Create todo list** for planning process
|
|
283
|
+
7. **Monitor delegated work** - `ff-agents-current()`
|
|
284
|
+
8. **Read results** from completed agents using `ff-agents-get` or `ff-agents-show`
|
|
285
|
+
9. **Analyze requirements** and mark todo complete
|
|
286
|
+
10. **Assess complexity** and mark todo complete
|
|
287
|
+
11. **Identify files** and mark todo complete
|
|
288
|
+
12. **Create implementation plan** using all research findings
|
|
289
|
+
13. **Save plan** - Use `ff-plans-update` to save your implementation plan to `.feature-factory/plans/`
|
|
290
|
+
14. **Format output** using ff-report-templates
|
|
291
|
+
15. **Mark all todos complete**
|
|
292
|
+
16. **Clean up** - `ff-agents-clear()`
|
|
293
|
+
17. **Hand off plan** to @building agent for implementation
|
|
280
294
|
|
|
281
295
|
## Important Notes
|
|
282
296
|
|
package/agents/reviewing.md
CHANGED
|
@@ -16,6 +16,7 @@ permission:
|
|
|
16
16
|
task:
|
|
17
17
|
'ff-*': allow
|
|
18
18
|
explore: allow
|
|
19
|
+
general: deny
|
|
19
20
|
# File tools - agents directory (read/write for own context)
|
|
20
21
|
ff-agents-get: allow
|
|
21
22
|
ff-agents-update: allow
|
|
@@ -32,11 +33,23 @@ permission:
|
|
|
32
33
|
ff-reviews-get: allow
|
|
33
34
|
ff-reviews-list: allow
|
|
34
35
|
ff-reviews-update: allow
|
|
35
|
-
ff-reviews-delete: allow
|
|
36
36
|
---
|
|
37
37
|
|
|
38
38
|
You are a reviewing/validation specialist for Feature Factory. Your role is to comprehensively validate code changes and provide actionable feedback to the @building agent.
|
|
39
39
|
|
|
40
|
+
## Socratic Approach
|
|
41
|
+
|
|
42
|
+
Be probing and inquisitive during validation. Don't just check boxes:
|
|
43
|
+
|
|
44
|
+
- **Question the implementation** - "Why was this approach chosen over alternatives?"
|
|
45
|
+
- **Probe for gaps** - "What scenarios haven't been considered?"
|
|
46
|
+
- **Challenge assumptions** - "The code assumes X will always be true. Is that valid?"
|
|
47
|
+
- **Ask for evidence** - "Where are the tests that verify this behavior?"
|
|
48
|
+
- **Surface trade-offs** - "This solution optimizes for speed but sacrifices maintainability. Was that intentional?"
|
|
49
|
+
- **Dig deeper** - "I see a potential issue here. Can you walk me through the thinking?"
|
|
50
|
+
|
|
51
|
+
Your goal is to uncover real issues, not just confirm the code works in happy paths.
|
|
52
|
+
|
|
40
53
|
## Getting Started
|
|
41
54
|
|
|
42
55
|
At the start of EVERY review task:
|
|
@@ -69,7 +82,6 @@ You have access to specialized file tools. **CRITICAL:** Only use WRITE tools fo
|
|
|
69
82
|
- **ff-reviews-update** - ⭐ CREATE/UPDATE validation report files (YOUR PRIMARY OUTPUT)
|
|
70
83
|
- **ff-reviews-get** - Read review files
|
|
71
84
|
- **ff-reviews-list** - List all review files
|
|
72
|
-
- **ff-reviews-delete** - Delete review files
|
|
73
85
|
|
|
74
86
|
### Plan Files (.feature-factory/plans/) - READ ONLY
|
|
75
87
|
|
package/dist/discovery.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ type BunShell = any;
|
|
|
5
5
|
*
|
|
6
6
|
* Resolution order:
|
|
7
7
|
* 1. Configured commands (qualityGate.lint/build/test) - highest priority
|
|
8
|
-
* 2.
|
|
8
|
+
* 2. ff-ci.sh (Feature Factory convention) - only if no configured commands
|
|
9
9
|
* 3. Conventional discovery (Node/Rust/Go/Python) - only if no ci.sh
|
|
10
10
|
*
|
|
11
11
|
* @returns Array of command steps to execute, or empty if nothing found
|
package/dist/discovery.js
CHANGED
|
@@ -137,7 +137,7 @@ async function discoverPythonCommands($, directory) {
|
|
|
137
137
|
*
|
|
138
138
|
* Resolution order:
|
|
139
139
|
* 1. Configured commands (qualityGate.lint/build/test) - highest priority
|
|
140
|
-
* 2.
|
|
140
|
+
* 2. ff-ci.sh (Feature Factory convention) - only if no configured commands
|
|
141
141
|
* 3. Conventional discovery (Node/Rust/Go/Python) - only if no ci.sh
|
|
142
142
|
*
|
|
143
143
|
* @returns Array of command steps to execute, or empty if nothing found
|
|
@@ -159,7 +159,7 @@ export async function resolveCommands(args) {
|
|
|
159
159
|
}
|
|
160
160
|
// 2. Feature Factory CI script (only if no configured commands)
|
|
161
161
|
if (mergedConfig.useCiSh !== 'never') {
|
|
162
|
-
const ciShPath = `${directory}/
|
|
162
|
+
const ciShPath = `${directory}/ff-ci.sh`;
|
|
163
163
|
if (await fileExists($, ciShPath)) {
|
|
164
164
|
return [{ step: 'ci', cmd: `bash ${ciShPath}` }];
|
|
165
165
|
}
|
|
@@ -3,7 +3,7 @@ type BunShell = any;
|
|
|
3
3
|
/**
|
|
4
4
|
* Initialize the Feature Factory directory structure.
|
|
5
5
|
* Creates .feature-factory/ and .feature-factory/agents/ directories.
|
|
6
|
-
* Migrates management/ci.sh
|
|
6
|
+
* Migrates legacy CI scripts (management/ci.sh and .feature-factory/ci.sh) to ff-ci.sh if they exist.
|
|
7
7
|
*/
|
|
8
8
|
export declare function initializeFeatureFactory(input: PluginInput, $: BunShell): Promise<void>;
|
|
9
9
|
export {};
|
|
@@ -29,7 +29,8 @@ async function executeWithTimeout(operation, timeoutMs = 5000, operationName = '
|
|
|
29
29
|
return await Promise.race([operation(), timeoutPromise]);
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
|
-
//
|
|
32
|
+
// Log timeout/error for debugging but don't throw - return null to allow graceful degradation
|
|
33
|
+
console.warn(`[FeatureFactory] ${operationName} timed out or failed:`, error);
|
|
33
34
|
return null;
|
|
34
35
|
}
|
|
35
36
|
}
|
|
@@ -49,7 +50,7 @@ function isValidDirectory(directory) {
|
|
|
49
50
|
/**
|
|
50
51
|
* Initialize the Feature Factory directory structure.
|
|
51
52
|
* Creates .feature-factory/ and .feature-factory/agents/ directories.
|
|
52
|
-
* Migrates management/ci.sh
|
|
53
|
+
* Migrates legacy CI scripts (management/ci.sh and .feature-factory/ci.sh) to ff-ci.sh if they exist.
|
|
53
54
|
*/
|
|
54
55
|
export async function initializeFeatureFactory(input, $) {
|
|
55
56
|
const { directory, client } = input;
|
|
@@ -83,61 +84,76 @@ export async function initializeFeatureFactory(input, $) {
|
|
|
83
84
|
// Continue even if directory creation fails - it might already exist
|
|
84
85
|
}
|
|
85
86
|
// Check for CI script migration (with timeout protection)
|
|
86
|
-
|
|
87
|
-
const
|
|
87
|
+
// Check both legacy locations: management/ci.sh and .feature-factory/ci.sh
|
|
88
|
+
const legacyCiPaths = [`${directory}/management/ci.sh`, `${featureFactoryDir}/ci.sh`];
|
|
89
|
+
const newCiPath = `${directory}/ff-ci.sh`;
|
|
88
90
|
try {
|
|
89
|
-
// Check if
|
|
90
|
-
const oldExists = await executeWithTimeout(async () => {
|
|
91
|
-
await $ `test -f ${oldCiPath}`.quiet();
|
|
92
|
-
return true;
|
|
93
|
-
}, 2000, 'test -f old-ci');
|
|
94
|
-
if (oldExists !== true) {
|
|
95
|
-
// Old doesn't exist, nothing to migrate
|
|
96
|
-
await log(client, 'debug', 'ci-sh-no-migration-needed', {
|
|
97
|
-
oldPath: oldCiPath,
|
|
98
|
-
});
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
// Old exists, check if new already exists (with timeout)
|
|
91
|
+
// Check if new location already exists (with timeout)
|
|
102
92
|
const newExists = await executeWithTimeout(async () => {
|
|
103
93
|
await $ `test -f ${newCiPath}`.quiet();
|
|
104
94
|
return true;
|
|
105
95
|
}, 2000, 'test -f new-ci');
|
|
106
96
|
if (newExists === true) {
|
|
107
|
-
//
|
|
108
|
-
await log(client, 'debug', 'ci-sh-
|
|
109
|
-
oldPath: oldCiPath,
|
|
97
|
+
// New location already exists, migration already done
|
|
98
|
+
await log(client, 'debug', 'ci-sh-already-migrated', {
|
|
110
99
|
newPath: newCiPath,
|
|
111
100
|
});
|
|
112
101
|
return;
|
|
113
102
|
}
|
|
114
|
-
//
|
|
103
|
+
// Find the first legacy CI script that exists
|
|
104
|
+
let sourcePath = null;
|
|
105
|
+
for (const legacyPath of legacyCiPaths) {
|
|
106
|
+
const exists = await executeWithTimeout(async () => {
|
|
107
|
+
await $ `test -f ${legacyPath}`.quiet();
|
|
108
|
+
return true;
|
|
109
|
+
}, 2000, `test -f legacy-ci-${legacyPath}`);
|
|
110
|
+
if (exists === true) {
|
|
111
|
+
sourcePath = legacyPath;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!sourcePath) {
|
|
116
|
+
// No legacy CI script found, nothing to migrate
|
|
117
|
+
await log(client, 'debug', 'ci-sh-no-migration-needed', {
|
|
118
|
+
checkedPaths: legacyCiPaths,
|
|
119
|
+
});
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
// Migrate from legacy to new location (with timeout)
|
|
115
123
|
const copied = await executeWithTimeout(async () => {
|
|
116
|
-
await $ `cp ${
|
|
124
|
+
await $ `cp ${sourcePath} ${newCiPath}`.quiet();
|
|
117
125
|
return true;
|
|
118
126
|
}, 3000, 'cp ci.sh');
|
|
119
127
|
if (copied === true) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
128
|
+
// Remove all legacy files after successful migration
|
|
129
|
+
let removedCount = 0;
|
|
130
|
+
for (const legacyPath of legacyCiPaths) {
|
|
131
|
+
const removed = await executeWithTimeout(async () => {
|
|
132
|
+
await $ `rm ${legacyPath}`.quiet();
|
|
133
|
+
return true;
|
|
134
|
+
}, 2000, `rm legacy-ci-${legacyPath}`);
|
|
135
|
+
if (removed === true) {
|
|
136
|
+
removedCount++;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (removedCount > 0) {
|
|
125
140
|
await log(client, 'info', 'ci-sh-migrated', {
|
|
126
|
-
from:
|
|
141
|
+
from: sourcePath,
|
|
127
142
|
to: newCiPath,
|
|
143
|
+
removedLegacyFiles: removedCount,
|
|
128
144
|
});
|
|
129
145
|
}
|
|
130
146
|
else {
|
|
131
147
|
await log(client, 'warn', 'ci-sh-migration-partial', {
|
|
132
|
-
from:
|
|
148
|
+
from: sourcePath,
|
|
133
149
|
to: newCiPath,
|
|
134
|
-
reason: 'copied but failed to remove
|
|
150
|
+
reason: 'copied but failed to remove legacy files',
|
|
135
151
|
});
|
|
136
152
|
}
|
|
137
153
|
}
|
|
138
154
|
else {
|
|
139
155
|
await log(client, 'error', 'ci-sh-migration-failed', {
|
|
140
|
-
from:
|
|
156
|
+
from: sourcePath,
|
|
141
157
|
to: newCiPath,
|
|
142
158
|
reason: 'copy operation timed out or failed',
|
|
143
159
|
});
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,6 @@ import { createFFPlansDeleteTool } from './plugins/ff-plans-delete-plugin.js';
|
|
|
22
22
|
import { createFFPlansListTool } from './plugins/ff-plans-list-plugin.js';
|
|
23
23
|
import { createFFReviewsGetTool } from './plugins/ff-reviews-get-plugin.js';
|
|
24
24
|
import { createFFReviewsUpdateTool } from './plugins/ff-reviews-update-plugin.js';
|
|
25
|
-
import { createFFReviewsDeleteTool } from './plugins/ff-reviews-delete-plugin.js';
|
|
26
25
|
import { createFFReviewsListTool } from './plugins/ff-reviews-list-plugin.js';
|
|
27
26
|
/**
|
|
28
27
|
* Feature Factory Plugin
|
|
@@ -70,7 +69,6 @@ export const FeatureFactoryPlugin = async (input) => {
|
|
|
70
69
|
// File management - reviews
|
|
71
70
|
'ff-reviews-get': createFFReviewsGetTool(),
|
|
72
71
|
'ff-reviews-update': createFFReviewsUpdateTool(),
|
|
73
|
-
'ff-reviews-delete': createFFReviewsDeleteTool(),
|
|
74
72
|
'ff-reviews-list': createFFReviewsListTool(),
|
|
75
73
|
};
|
|
76
74
|
// Return combined hooks and tools
|
|
@@ -44,7 +44,7 @@ export function createFFAgentContextUpdateTool() {
|
|
|
44
44
|
content = content.replace('delegated_to: []', `delegated_to:\n - "${args.addDelegatedTo}"`);
|
|
45
45
|
}
|
|
46
46
|
else if (content.includes('delegated_to:')) {
|
|
47
|
-
content = content.replace(/(delegated_to:\n(?:
|
|
47
|
+
content = content.replace(/(delegated_to:\n(?: {2}- ".*"\n)*)/, `$1 - "${args.addDelegatedTo}"\n`);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
// Append notes if provided
|
|
@@ -22,7 +22,7 @@ export function createFFAgentsDeleteTool() {
|
|
|
22
22
|
return `Successfully deleted agent file: ${args.fileName}`;
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
if (error.code === 'ENOENT') {
|
|
25
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
26
26
|
return `Error: File "${args.fileName}" not found in .feature-factory/agents`;
|
|
27
27
|
}
|
|
28
28
|
return `Error deleting agent file: ${error}`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from '@opencode-ai/plugin/tool';
|
|
2
|
-
import { validateSafePath, resolveSafePath, getFeatureFactoryDir
|
|
2
|
+
import { validateSafePath, resolveSafePath, getFeatureFactoryDir } from '../utils/file-utils.js';
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
4
|
export function createFFAgentsGetTool() {
|
|
5
5
|
return tool({
|
|
@@ -22,7 +22,7 @@ export function createFFAgentsGetTool() {
|
|
|
22
22
|
return content;
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
if (error.code === 'ENOENT') {
|
|
25
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
26
26
|
return `Error: File "${args.fileName}" not found in .feature-factory/agents`;
|
|
27
27
|
}
|
|
28
28
|
return `Error reading agent file: ${error}`;
|
|
@@ -22,7 +22,7 @@ export function createFFPlansDeleteTool() {
|
|
|
22
22
|
return `Successfully deleted plan file: ${args.fileName}`;
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
if (error.code === 'ENOENT') {
|
|
25
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
26
26
|
return `Error: File "${args.fileName}" not found in .feature-factory/plans`;
|
|
27
27
|
}
|
|
28
28
|
return `Error deleting plan file: ${error}`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from '@opencode-ai/plugin/tool';
|
|
2
|
-
import { validateSafePath, resolveSafePath, getFeatureFactoryDir
|
|
2
|
+
import { validateSafePath, resolveSafePath, getFeatureFactoryDir } from '../utils/file-utils.js';
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
4
|
export function createFFPlansGetTool() {
|
|
5
5
|
return tool({
|
|
@@ -22,7 +22,7 @@ export function createFFPlansGetTool() {
|
|
|
22
22
|
return content;
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
if (error.code === 'ENOENT') {
|
|
25
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
26
26
|
return `Error: File "${args.fileName}" not found in .feature-factory/plans`;
|
|
27
27
|
}
|
|
28
28
|
return `Error reading plan file: ${error}`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { tool } from '@opencode-ai/plugin/tool';
|
|
2
|
-
import { validateSafePath, resolveSafePath, getFeatureFactoryDir
|
|
2
|
+
import { validateSafePath, resolveSafePath, getFeatureFactoryDir } from '../utils/file-utils.js';
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
4
|
export function createFFReviewsGetTool() {
|
|
5
5
|
return tool({
|
|
@@ -22,7 +22,7 @@ export function createFFReviewsGetTool() {
|
|
|
22
22
|
return content;
|
|
23
23
|
}
|
|
24
24
|
catch (error) {
|
|
25
|
-
if (error.code === 'ENOENT') {
|
|
25
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
26
26
|
return `Error: File "${args.fileName}" not found in .feature-factory/reviews`;
|
|
27
27
|
}
|
|
28
28
|
return `Error reading review file: ${error}`;
|
|
@@ -31,7 +31,7 @@ export declare function mergeQualityGateConfig(root: QualityGateConfig | undefin
|
|
|
31
31
|
export declare function loadQualityGateConfig($: BunShell, directory: string): Promise<QualityGateConfig>;
|
|
32
32
|
/**
|
|
33
33
|
* Check if any explicit commands are configured (lint/build/test).
|
|
34
|
-
* If so, these take priority over ci.sh and discovery.
|
|
34
|
+
* If so, these take priority over ff-ci.sh and discovery.
|
|
35
35
|
*/
|
|
36
36
|
export declare function hasConfiguredCommands(config: QualityGateConfig): boolean;
|
|
37
37
|
export {};
|
|
@@ -77,7 +77,7 @@ export async function loadQualityGateConfig($, directory) {
|
|
|
77
77
|
}
|
|
78
78
|
/**
|
|
79
79
|
* Check if any explicit commands are configured (lint/build/test).
|
|
80
|
-
* If so, these take priority over ci.sh and discovery.
|
|
80
|
+
* If so, these take priority over ff-ci.sh and discovery.
|
|
81
81
|
*/
|
|
82
82
|
export function hasConfiguredCommands(config) {
|
|
83
83
|
return !!(config.lint || config.build || config.test);
|
|
@@ -157,15 +157,16 @@ async function log(client, level, message, extra) {
|
|
|
157
157
|
/**
|
|
158
158
|
* Execute a shell command with a timeout to prevent hangs
|
|
159
159
|
*/
|
|
160
|
-
async function executeWithTimeout(operation, timeoutMs = 5000,
|
|
160
|
+
async function executeWithTimeout(operation, timeoutMs = 5000, operationName = 'shell command') {
|
|
161
161
|
const timeoutPromise = new Promise((_, reject) => {
|
|
162
|
-
setTimeout(() => reject(new Error(
|
|
162
|
+
setTimeout(() => reject(new Error(`${operationName} timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
163
163
|
});
|
|
164
164
|
try {
|
|
165
165
|
return await Promise.race([operation(), timeoutPromise]);
|
|
166
166
|
}
|
|
167
|
-
catch {
|
|
168
|
-
//
|
|
167
|
+
catch (error) {
|
|
168
|
+
// Log timeout/error for debugging but don't throw - return null to allow graceful degradation
|
|
169
|
+
console.warn(`[FeatureFactory] ${operationName} timed out or failed:`, error);
|
|
169
170
|
return null;
|
|
170
171
|
}
|
|
171
172
|
}
|
|
@@ -174,7 +175,7 @@ export const StopQualityGateHooksPlugin = async (input) => {
|
|
|
174
175
|
async function ciShExists() {
|
|
175
176
|
try {
|
|
176
177
|
const result = await executeWithTimeout(async () => {
|
|
177
|
-
await $ `test -f ${directory}
|
|
178
|
+
await $ `test -f ${directory}/ff-ci.sh`.quiet();
|
|
178
179
|
return true;
|
|
179
180
|
}, 2000, 'test -f ci.sh');
|
|
180
181
|
return result === true;
|
|
@@ -231,7 +232,7 @@ export const StopQualityGateHooksPlugin = async (input) => {
|
|
|
231
232
|
let ciOutput = '';
|
|
232
233
|
let ciPassed = false;
|
|
233
234
|
let timedOut = false;
|
|
234
|
-
const ciPath = `${directory}
|
|
235
|
+
const ciPath = `${directory}/ff-ci.sh`;
|
|
235
236
|
// eslint-disable-next-line no-undef
|
|
236
237
|
const proc = Bun.spawn(['bash', ciPath], {
|
|
237
238
|
cwd: directory,
|
|
@@ -292,7 +293,7 @@ export const StopQualityGateHooksPlugin = async (input) => {
|
|
|
292
293
|
|
|
293
294
|
**Important:** Do not interrupt your current task. Add "Fix quality gate failures" to your todo list and continue with what you were doing. Address the quality gate issues after completing your current task.
|
|
294
295
|
|
|
295
|
-
If the failure details are missing or truncated, run "
|
|
296
|
+
If the failure details are missing or truncated, run "ff-ci.sh" to get the full output.`;
|
|
296
297
|
const message = timedOut
|
|
297
298
|
? `⏱️ Quality gate timed out\n\nThe CI execution exceeded the ${CI_TIMEOUT_MS / 1000} second timeout. The build may be hanging or taking too long.\n\n\`\`\`\n${sanitizedOutput}\n\`\`\`${instructions}`
|
|
298
299
|
: `❌ Quality gate failed\n\nThe CI checks did not pass. Please review the output below and fix the issues:\n\n\`\`\`\n${sanitizedOutput}\n\`\`\`${instructions}`;
|
package/dist/types.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface QualityGateConfig {
|
|
|
13
13
|
cwd?: string;
|
|
14
14
|
/** Order of steps to run (default: ["lint", "build", "test"]) */
|
|
15
15
|
steps?: ('lint' | 'build' | 'test')[];
|
|
16
|
-
/** Whether to use
|
|
16
|
+
/** Whether to use ff-ci.sh: "auto" | "always" | "never" (default: "auto") */
|
|
17
17
|
useCiSh?: 'auto' | 'always' | 'never';
|
|
18
18
|
/** Package manager override: "auto" | "pnpm" | "bun" | "yarn" | "npm" (default: "auto") */
|
|
19
19
|
packageManager?: 'auto' | 'pnpm' | 'bun' | 'yarn' | 'npm';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@syntesseraai/opencode-feature-factory",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.38",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "OpenCode plugin for Feature Factory agents - provides sub-agents and skills for validation, review, security, and architecture assessment",
|
|
7
7
|
"license": "MIT",
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
],
|
|
33
33
|
"scripts": {},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@opencode-ai/plugin": "^1.1.48"
|
|
35
|
+
"@opencode-ai/plugin": "^1.1.48",
|
|
36
|
+
"glob": "^10.0.0",
|
|
37
|
+
"uuid": "^9.0.0"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
38
40
|
"@types/bun": "^1.2.6",
|
|
@@ -142,6 +142,7 @@ Update your context with delegated agents using `ff-agents-get` to read your fil
|
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
2. Then update with delegated agents:
|
|
145
|
+
|
|
145
146
|
```
|
|
146
147
|
ff-agents-update:
|
|
147
148
|
fileName: "{agent}-{$MY_UUID}.md"
|
|
@@ -240,6 +241,13 @@ ff-agents-clear(sessionID: "session-abc123")
|
|
|
240
241
|
ff-agents-clear(agent: "ff-research")
|
|
241
242
|
```
|
|
242
243
|
|
|
244
|
+
**Cleanup Scope:**
|
|
245
|
+
|
|
246
|
+
- **Agent context files** (`.feature-factory/agents/`): Clean up via `ff-agents-clear()` - these are temporary coordination files
|
|
247
|
+
- **Plan files** (`.feature-factory/plans/`): @building agent asks user if plan should be deleted after implementation is complete
|
|
248
|
+
- **Review files** (`.feature-factory/reviews/`): Do NOT delete - these are idempotent validation records that serve as audit trail
|
|
249
|
+
- **Stale plan check**: @planning agent checks for existing plan files before creating new ones
|
|
250
|
+
|
|
243
251
|
## Example: Planning with Parallel Research
|
|
244
252
|
|
|
245
253
|
**Scenario:** Implementing OAuth authentication
|