@syntesseraai/opencode-feature-factory 0.2.37 → 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.
@@ -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** and hand off to user
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
 
@@ -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:
@@ -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:
@@ -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:
@@ -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:
@@ -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:
@@ -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. **Generate UUID** - Create unique ID for this planning instance
261
- 2. **Load required skills** (ff-delegation, ff-mini-plan, ff-todo-management, ff-report-templates)
262
- 3. **Document context** - Use `ff-agents-update` tool to create `.feature-factory/agents/planning-{UUID}.md`
263
- 4. **Delegate in parallel**:
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
- 5. **Create todo list** for planning process
269
- 6. **Monitor delegated work** - `ff-agents-current()`
270
- 7. **Read results** from completed agents using `ff-agents-get` or `ff-agents-show`
271
- 8. **Analyze requirements** and mark todo complete
272
- 9. **Assess complexity** and mark todo complete
273
- 10. **Identify files** and mark todo complete
274
- 11. **Create implementation plan** using all research findings
275
- 12. **Save plan** - Use `ff-plans-update` to save your implementation plan to `.feature-factory/plans/`
276
- 13. **Format output** using ff-report-templates
277
- 14. **Mark all todos complete**
278
- 15. **Clean up** - `ff-agents-clear()`
279
- 16. **Hand off plan** to @building agent for implementation
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
 
@@ -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
 
@@ -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. management/ci.sh (Feature Factory convention) - only if no configured commands
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. management/ci.sh (Feature Factory convention) - only if no configured commands
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}/management/ci.sh`;
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 to .feature-factory/ci.sh if it exists.
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
- // Return null on timeout or error
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 to .feature-factory/ci.sh if it exists.
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
- const oldCiPath = `${directory}/management/ci.sh`;
87
- const newCiPath = `${featureFactoryDir}/ci.sh`;
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 old CI exists (with timeout)
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
- // Both exist - migration already done or user has both
108
- await log(client, 'debug', 'ci-sh-both-locations-exist', {
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
- // Old exists, new doesn't - migrate (with timeout)
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 ${oldCiPath} ${newCiPath}`.quiet();
124
+ await $ `cp ${sourcePath} ${newCiPath}`.quiet();
117
125
  return true;
118
126
  }, 3000, 'cp ci.sh');
119
127
  if (copied === true) {
120
- const removed = await executeWithTimeout(async () => {
121
- await $ `rm ${oldCiPath}`.quiet();
122
- return true;
123
- }, 2000, 'rm old-ci');
124
- if (removed === true) {
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: oldCiPath,
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: oldCiPath,
148
+ from: sourcePath,
133
149
  to: newCiPath,
134
- reason: 'copied but failed to remove old file',
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: oldCiPath,
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(?: - ".*"\n)*)/, `$1 - "${args.addDelegatedTo}"\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, } from '../utils/file-utils.js';
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, } from '../utils/file-utils.js';
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, } from '../utils/file-utils.js';
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, _operationName = 'shell command') {
160
+ async function executeWithTimeout(operation, timeoutMs = 5000, operationName = 'shell command') {
161
161
  const timeoutPromise = new Promise((_, reject) => {
162
- setTimeout(() => reject(new Error(`timed out after ${timeoutMs}ms`)), timeoutMs);
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
- // Return null on timeout or error
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}/.feature-factory/ci.sh`.quiet();
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}/.feature-factory/ci.sh`;
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 ".feature-factory/ci.sh" to get the full output.`;
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 management/ci.sh: "auto" | "always" | "never" (default: "auto") */
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.37",
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",
@@ -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