@syntesseraai/opencode-feature-factory 0.6.8 → 0.6.10

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.
Files changed (104) hide show
  1. package/README.md +24 -17
  2. package/agents/building.md +28 -541
  3. package/agents/documenting.md +39 -0
  4. package/agents/ff-research.md +18 -410
  5. package/agents/pipeline.md +27 -69
  6. package/agents/planning.md +28 -350
  7. package/agents/reviewing.md +27 -475
  8. package/bin/ff-deploy.js +7 -7
  9. package/{commands → command}/pipeline/building/breakdown.md +3 -3
  10. package/{commands → command}/pipeline/building/implement-batch.md +3 -3
  11. package/command/pipeline/building/run.md +19 -0
  12. package/{commands → command}/pipeline/building/validate-batch.md +3 -3
  13. package/{commands → command}/pipeline/complete.md +1 -2
  14. package/{commands/pipeline/documentation/run-codex.md → command/pipeline/documentation/document.md} +4 -6
  15. package/{commands → command}/pipeline/documentation/gate.md +3 -4
  16. package/{commands/pipeline/documentation/run-gemini.md → command/pipeline/documentation/review.md} +3 -3
  17. package/command/pipeline/documentation/run.md +25 -0
  18. package/command/pipeline/planning/gate.md +23 -0
  19. package/command/pipeline/planning/plan.md +25 -0
  20. package/command/pipeline/planning/run.md +24 -0
  21. package/command/pipeline/planning/synthesize.md +21 -0
  22. package/{commands → command}/pipeline/reviewing/gate.md +3 -4
  23. package/command/pipeline/reviewing/review.md +20 -0
  24. package/command/pipeline/reviewing/run.md +23 -0
  25. package/{commands → command}/pipeline/reviewing/synthesize.md +3 -4
  26. package/{commands → command}/pipeline/reviewing/triage.md +2 -3
  27. package/command/pipeline/start.md +29 -0
  28. package/dist/index.d.ts +1 -2
  29. package/dist/index.js +3 -52
  30. package/package.json +2 -2
  31. package/skills/ff-reviewing-architecture/SKILL.md +34 -0
  32. package/skills/ff-reviewing-code-quality/SKILL.md +34 -0
  33. package/skills/ff-reviewing-documentation/SKILL.md +34 -0
  34. package/skills/ff-reviewing-security/SKILL.md +34 -0
  35. package/agents/ff-acceptance.md +0 -285
  36. package/agents/ff-building-codex.md +0 -305
  37. package/agents/ff-building-gemini.md +0 -305
  38. package/agents/ff-building-opus.md +0 -305
  39. package/agents/ff-planning-codex.md +0 -335
  40. package/agents/ff-planning-gemini.md +0 -335
  41. package/agents/ff-planning-opus.md +0 -335
  42. package/agents/ff-review.md +0 -288
  43. package/agents/ff-reviewing-codex.md +0 -259
  44. package/agents/ff-reviewing-gemini.md +0 -259
  45. package/agents/ff-reviewing-opus.md +0 -259
  46. package/agents/ff-security.md +0 -322
  47. package/agents/ff-validate.md +0 -316
  48. package/agents/ff-well-architected.md +0 -284
  49. package/commands/pipeline/building/run.md +0 -19
  50. package/commands/pipeline/documentation/run.md +0 -27
  51. package/commands/pipeline/planning/gate.md +0 -22
  52. package/commands/pipeline/planning/run-codex.md +0 -22
  53. package/commands/pipeline/planning/run-gemini.md +0 -21
  54. package/commands/pipeline/planning/run-opus.md +0 -21
  55. package/commands/pipeline/planning/run.md +0 -25
  56. package/commands/pipeline/planning/synthesize.md +0 -18
  57. package/commands/pipeline/reviewing/run-codex.md +0 -12
  58. package/commands/pipeline/reviewing/run-gemini.md +0 -11
  59. package/commands/pipeline/reviewing/run-opus.md +0 -11
  60. package/commands/pipeline/reviewing/run.md +0 -24
  61. package/commands/pipeline/start.md +0 -22
  62. package/dist/agent-context.d.ts +0 -57
  63. package/dist/agent-context.js +0 -282
  64. package/dist/plugins/ff-agent-context-create-plugin.d.ts +0 -2
  65. package/dist/plugins/ff-agent-context-create-plugin.js +0 -82
  66. package/dist/plugins/ff-agent-context-update-plugin.d.ts +0 -2
  67. package/dist/plugins/ff-agent-context-update-plugin.js +0 -78
  68. package/dist/plugins/ff-agents-clear-plugin.d.ts +0 -2
  69. package/dist/plugins/ff-agents-clear-plugin.js +0 -40
  70. package/dist/plugins/ff-agents-current-plugin.d.ts +0 -2
  71. package/dist/plugins/ff-agents-current-plugin.js +0 -45
  72. package/dist/plugins/ff-agents-delete-plugin.d.ts +0 -2
  73. package/dist/plugins/ff-agents-delete-plugin.js +0 -32
  74. package/dist/plugins/ff-agents-get-plugin.d.ts +0 -2
  75. package/dist/plugins/ff-agents-get-plugin.js +0 -32
  76. package/dist/plugins/ff-agents-list-plugin.d.ts +0 -2
  77. package/dist/plugins/ff-agents-list-plugin.js +0 -42
  78. package/dist/plugins/ff-agents-show-plugin.d.ts +0 -2
  79. package/dist/plugins/ff-agents-show-plugin.js +0 -22
  80. package/dist/plugins/ff-agents-update-plugin.d.ts +0 -2
  81. package/dist/plugins/ff-agents-update-plugin.js +0 -32
  82. package/dist/plugins/ff-plan-create-plugin.d.ts +0 -2
  83. package/dist/plugins/ff-plan-create-plugin.js +0 -61
  84. package/dist/plugins/ff-plan-update-plugin.d.ts +0 -2
  85. package/dist/plugins/ff-plan-update-plugin.js +0 -142
  86. package/dist/plugins/ff-plans-delete-plugin.d.ts +0 -2
  87. package/dist/plugins/ff-plans-delete-plugin.js +0 -32
  88. package/dist/plugins/ff-plans-get-plugin.d.ts +0 -2
  89. package/dist/plugins/ff-plans-get-plugin.js +0 -32
  90. package/dist/plugins/ff-plans-list-plugin.d.ts +0 -2
  91. package/dist/plugins/ff-plans-list-plugin.js +0 -42
  92. package/dist/plugins/ff-plans-update-plugin.d.ts +0 -2
  93. package/dist/plugins/ff-plans-update-plugin.js +0 -32
  94. package/dist/plugins/ff-review-create-plugin.d.ts +0 -2
  95. package/dist/plugins/ff-review-create-plugin.js +0 -256
  96. package/dist/plugins/ff-reviews-get-plugin.d.ts +0 -2
  97. package/dist/plugins/ff-reviews-get-plugin.js +0 -32
  98. package/dist/plugins/ff-reviews-list-plugin.d.ts +0 -2
  99. package/dist/plugins/ff-reviews-list-plugin.js +0 -42
  100. package/dist/plugins/ff-reviews-update-plugin.d.ts +0 -2
  101. package/dist/plugins/ff-reviews-update-plugin.js +0 -32
  102. package/skills/ff-context-tracking/SKILL.md +0 -573
  103. package/skills/ff-delegation/SKILL.md +0 -457
  104. package/skills/ff-swarm/SKILL.md +0 -209
@@ -1,21 +0,0 @@
1
- ---
2
- description: Generate Gemini planning proposal
3
- subtask: true
4
- agent: ff-planning-gemini
5
- ---
6
-
7
- Create a comprehensive implementation plan from the current pipeline requirements.
8
-
9
- Requirements brief:
10
-
11
- $ARGUMENTS
12
-
13
- Persist plan content using `ff-plans-update` into `.feature-factory/plans/plan-gemini-{UUID}.md`.
14
-
15
- Include:
16
-
17
- - requirements summary
18
- - architecture validation for the proposed implementation approach
19
- - ordered implementation steps with file targets
20
- - risks and mitigations
21
- - testing and validation strategy
@@ -1,21 +0,0 @@
1
- ---
2
- description: Generate Opus planning proposal
3
- subtask: true
4
- agent: ff-planning-opus
5
- ---
6
-
7
- Create a comprehensive implementation plan from the current pipeline requirements.
8
-
9
- Requirements brief:
10
-
11
- $ARGUMENTS
12
-
13
- Persist plan content using `ff-plans-update` into `.feature-factory/plans/plan-opus-{UUID}.md`.
14
-
15
- Include:
16
-
17
- - requirements summary
18
- - architecture validation for the proposed implementation approach
19
- - ordered implementation steps with file targets
20
- - risks and mitigations
21
- - testing and validation strategy
@@ -1,25 +0,0 @@
1
- ---
2
- description: Execute one planning iteration
3
- subtask: true
4
- model: openai/gpt-5.4
5
- parallel:
6
- - /pipeline/planning/run-opus {as:plan-opus}
7
- - /pipeline/planning/run-gemini {as:plan-gemini}
8
- - /pipeline/planning/run-codex {as:plan-codex}
9
- return:
10
- - /pipeline/planning/synthesize
11
- - /pipeline/planning/gate
12
- ---
13
-
14
- Run one complete planning iteration for the active pipeline.
15
-
16
- Requirements brief:
17
-
18
- $ARGUMENTS
19
-
20
- Rules:
21
-
22
- 1. Persist each planner output to `.feature-factory/plans/plan-{model}-{UUID}.md`.
23
- 2. Preserve prior planning artifacts for audit.
24
- 3. Each planning model must include architecture validation in its proposal.
25
- 4. Continue only through gate outcomes defined in `/pipeline/planning/gate`.
@@ -1,18 +0,0 @@
1
- ---
2
- description: Synthesize planning consensus
3
- subtask: true
4
- agent: ff-planning-codex
5
- model: openai/gpt-5.4
6
- ---
7
-
8
- Read the latest planning artifacts (`plan-opus-{UUID}.md`, `plan-gemini-{UUID}.md`, `plan-codex-{UUID}.md`) and produce a consensus report.
9
-
10
- Persist as `.feature-factory/plans/plan-consensus-{UUID}.md`.
11
-
12
- Required output sections:
13
-
14
- 1. `CONSENSUS_SCORE` (0-100)
15
- 2. `AGREED_ELEMENTS`
16
- 3. `DIVERGENT_ELEMENTS`
17
- 4. `SYNTHESIZED_PLAN`
18
- 5. `OPEN_QUESTIONS`
@@ -1,12 +0,0 @@
1
- ---
2
- description: Independent Codex review
3
- subtask: true
4
- agent: ff-reviewing-codex
5
- model: openai/gpt-5.3-codex
6
- ---
7
-
8
- Review the current task from triage brief for correctness, quality, architecture validity, testing, security, and edge cases.
9
-
10
- Classify findings as critical/high/medium/low and include confidence score.
11
-
12
- Persist to `.feature-factory/agents/ff-reviewing-codex-{UUID}-T{N}.md`.
@@ -1,11 +0,0 @@
1
- ---
2
- description: Independent Gemini review
3
- subtask: true
4
- agent: ff-reviewing-gemini
5
- ---
6
-
7
- Review the current task from triage brief for correctness, quality, architecture validity, testing, security, and edge cases.
8
-
9
- Classify findings as critical/high/medium/low and include confidence score.
10
-
11
- Persist to `.feature-factory/agents/ff-reviewing-gemini-{UUID}-T{N}.md`.
@@ -1,11 +0,0 @@
1
- ---
2
- description: Independent Opus review
3
- subtask: true
4
- agent: ff-reviewing-opus
5
- ---
6
-
7
- Review the current task from triage brief for correctness, quality, architecture validity, testing, security, and edge cases.
8
-
9
- Classify findings as critical/high/medium/low and include confidence score.
10
-
11
- Persist to `.feature-factory/agents/ff-reviewing-opus-{UUID}-T{N}.md`.
@@ -1,24 +0,0 @@
1
- ---
2
- description: Run review loop for completed tasks
3
- subtask: true
4
- model: openai/gpt-5.4
5
- loop:
6
- max: 10
7
- until: all tasks in the active batch are approved with confidence >=95 and zero unresolved issues
8
- return:
9
- - /pipeline/reviewing/triage
10
- - /pipeline/reviewing/run-opus {as:review-opus}
11
- - /pipeline/reviewing/run-gemini {as:review-gemini}
12
- - /pipeline/reviewing/run-codex {as:review-codex}
13
- - /pipeline/reviewing/synthesize
14
- - /pipeline/reviewing/gate
15
- - If `REVIEW_GATE=REWORK`, invoke `/pipeline/building/implement-batch` to apply fixes before the next loop iteration.
16
- ---
17
-
18
- Execute the review loop for the current completed tasks/rework report.
19
-
20
- Stop criteria:
21
-
22
- - approve when `>=95` confidence and zero unresolved issues
23
- - continue loop while unresolved issues exist and iteration < 10
24
- - escalate to user when iteration reaches 10 without approval
@@ -1,22 +0,0 @@
1
- ---
2
- description: Pipeline workflow entrypoint
3
- subtask: true
4
- model: openai/gpt-5.4
5
- return:
6
- - /pipeline/planning/run {loop:5 && until:planning gate is APPROVED or planning gate is BLOCKED and waiting for user confirmation}
7
- - If planning is BLOCKED or loop max was reached, stop and ask the user whether to continue planning iterations. Otherwise continue.
8
- - /pipeline/building/run
9
- - /pipeline/documentation/run
10
- - /pipeline/complete
11
- ---
12
-
13
- Start the deterministic Feature Factory pipeline with this requirements brief:
14
-
15
- $ARGUMENTS
16
-
17
- Execution requirements:
18
-
19
- 1. Create a pipeline UUID and persist orchestrator state in `.feature-factory/agents/pipeline-{UUID}.md` via `ff-agents-update`.
20
- 2. Keep all phase artifacts in `.feature-factory/plans/` and `.feature-factory/reviews/`.
21
- 3. Use command chaining, parallel fan-out, and loop gates from the `/pipeline/...` command tree.
22
- 4. Do not skip planning, review, and documentation gates.
@@ -1,57 +0,0 @@
1
- export interface AgentContext {
2
- /** Unique UUID for this agent instance */
3
- id: string;
4
- /** Agent type (planning, building, reviewing, etc.) */
5
- agent: string;
6
- /** Task title */
7
- title: string;
8
- /** Task description */
9
- description: string;
10
- /** Working directory/folder */
11
- folder: string;
12
- /** Current status */
13
- status: 'in-progress' | 'completed' | 'delegated' | 'failed';
14
- /** ISO timestamp when agent started */
15
- started: string;
16
- /** OpenCode session ID */
17
- session: string;
18
- /** Parent agent UUID (if delegated) */
19
- parent?: string;
20
- /** List of child agent UUIDs (if this agent delegated work) */
21
- delegated_to?: string[];
22
- /** Additional notes */
23
- notes?: string;
24
- }
25
- /**
26
- * Write an agent context file
27
- * File naming: {agent}-{uuid}.md
28
- */
29
- export declare function writeAgentContext(directory: string, context: AgentContext): Promise<string>;
30
- /**
31
- * Read an agent context file by UUID
32
- */
33
- export declare function readAgentContextById(directory: string, id: string): Promise<AgentContext | null>;
34
- /**
35
- * Update agent status in context file
36
- */
37
- export declare function updateAgentStatus(directory: string, id: string, status: AgentContext['status']): Promise<boolean>;
38
- /**
39
- * List all active agents
40
- */
41
- export declare function listActiveAgents(directory: string, sessionId?: string, agentType?: string): Promise<AgentContext[]>;
42
- /**
43
- * Find agent files by various criteria
44
- */
45
- export declare function findAgentFiles(directory: string, agentType?: string, sessionId?: string): Promise<string[]>;
46
- /**
47
- * Find agent file by UUID
48
- */
49
- export declare function findAgentFilesById(directory: string, id: string): Promise<string[]>;
50
- /**
51
- * Find all agent files
52
- */
53
- export declare function findAllAgentFiles(directory: string): Promise<string[]>;
54
- /**
55
- * Delete agent files
56
- */
57
- export declare function deleteAgentFiles(directory: string, files: string[]): Promise<number>;
@@ -1,282 +0,0 @@
1
- import { isValidUUID } from './uuid.js';
2
- import { writeFile, readFile, readdir, stat, unlink } from 'fs/promises';
3
- /**
4
- * Generate the content for an agent context file
5
- */
6
- function generateContextFileContent(context) {
7
- const frontmatter = `---
8
- id: "${context.id}"
9
- agent: ${context.agent}
10
- title: "${context.title}"
11
- description: "${context.description}"
12
- folder: "${context.folder}"
13
- status: ${context.status}
14
- started: "${context.started}"
15
- session: "${context.session}"
16
- ${context.parent ? `parent: "${context.parent}"` : 'parent: null'}
17
- ${context.delegated_to && context.delegated_to.length > 0 ? `delegated_to:\n${context.delegated_to.map((id) => ` - "${id}"`).join('\n')}` : 'delegated_to: []'}
18
- ---`;
19
- const body = `
20
-
21
- ## Task Context
22
-
23
- ${context.notes || 'No additional notes.'}
24
-
25
- ## Progress
26
-
27
- - [ ] Task started
28
-
29
- ## Delegated Work
30
-
31
- ${context.delegated_to && context.delegated_to.length > 0 ? context.delegated_to.map((id) => `- Agent ${id} (pending)`).join('\n') : 'No delegated work.'}
32
- `;
33
- return frontmatter + body;
34
- }
35
- /**
36
- * Write an agent context file
37
- * File naming: {agent}-{uuid}.md
38
- */
39
- export async function writeAgentContext(directory, context) {
40
- const fileName = `${context.agent}-${context.id}.md`;
41
- const filePath = `${directory}/.feature-factory/agents/${fileName}`;
42
- const content = generateContextFileContent(context);
43
- try {
44
- await writeFile(filePath, content, 'utf-8');
45
- return filePath;
46
- }
47
- catch (error) {
48
- throw new Error(`Failed to write agent context file: ${error}`);
49
- }
50
- }
51
- /**
52
- * Read an agent context file by UUID
53
- */
54
- export async function readAgentContextById(directory, id) {
55
- if (!isValidUUID(id)) {
56
- return null;
57
- }
58
- try {
59
- // Read directory and find file with this UUID
60
- const agentsDir = `${directory}/.feature-factory/agents`;
61
- const entries = await readdir(agentsDir, { withFileTypes: true });
62
- const fileName = entries
63
- .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
64
- .map((entry) => entry.name)
65
- .find((name) => name.includes(`-${id}.md`));
66
- if (!fileName) {
67
- return null;
68
- }
69
- const filePath = `${agentsDir}/${fileName}`;
70
- const content = await readFile(filePath, 'utf-8');
71
- return parseAgentContext(content);
72
- }
73
- catch {
74
- return null;
75
- }
76
- }
77
- /**
78
- * Parse agent context from markdown content
79
- */
80
- function parseAgentContext(content) {
81
- try {
82
- // Extract frontmatter
83
- const frontmatterMatch = content.match(/---\n([\s\S]*?)\n---/);
84
- if (!frontmatterMatch) {
85
- return null;
86
- }
87
- const frontmatter = frontmatterMatch[1];
88
- const lines = frontmatter.split('\n');
89
- const context = {};
90
- for (const line of lines) {
91
- const match = line.match(/^([a-z_]+):\s*(.*)$/);
92
- if (match) {
93
- const [, key, value] = match;
94
- const cleanValue = value.replace(/^["']|["']$/g, ''); // Remove quotes
95
- if (key === 'delegated_to') {
96
- // Handle array - this is simplified, real YAML parsing would be better
97
- continue;
98
- }
99
- else if (key === 'parent' && cleanValue === 'null') {
100
- context[key] = undefined;
101
- }
102
- else {
103
- context[key] = cleanValue;
104
- }
105
- }
106
- }
107
- // Parse delegated_to array manually from content
108
- const delegatedMatch = content.match(/delegated_to:\n((?: {2}- ".*"\n?)*)/);
109
- if (delegatedMatch) {
110
- const delegatedLines = delegatedMatch[1].trim().split('\n');
111
- context.delegated_to = delegatedLines
112
- .map((line) => line.match(/- "([^"]+)"/)?.[1])
113
- .filter((id) => !!id);
114
- }
115
- return context;
116
- }
117
- catch {
118
- return null;
119
- }
120
- }
121
- /**
122
- * Update agent status in context file
123
- */
124
- export async function updateAgentStatus(directory, id, status) {
125
- try {
126
- const agentsDir = `${directory}/.feature-factory/agents`;
127
- const entries = await readdir(agentsDir, { withFileTypes: true });
128
- const fileName = entries
129
- .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
130
- .map((entry) => entry.name)
131
- .find((name) => name.includes(`-${id}.md`));
132
- if (!fileName) {
133
- return false;
134
- }
135
- const filePath = `${agentsDir}/${fileName}`;
136
- // Read current content
137
- const content = await readFile(filePath, 'utf-8');
138
- let text = content;
139
- // Replace status line
140
- text = text.replace(/status: \w+/, `status: ${status}`);
141
- // Write back
142
- await writeFile(filePath, text, 'utf-8');
143
- return true;
144
- }
145
- catch {
146
- return false;
147
- }
148
- }
149
- /**
150
- * List all active agents
151
- */
152
- export async function listActiveAgents(directory, sessionId, agentType) {
153
- const agentsDir = `${directory}/.feature-factory/agents`;
154
- try {
155
- // Check if directory exists
156
- await stat(agentsDir);
157
- }
158
- catch {
159
- return [];
160
- }
161
- try {
162
- const entries = await readdir(agentsDir, { withFileTypes: true });
163
- const files = entries
164
- .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
165
- .map((entry) => `${agentsDir}/${entry.name}`);
166
- const agents = [];
167
- for (const filePath of files) {
168
- try {
169
- const content = await readFile(filePath, 'utf-8');
170
- const context = parseAgentContext(content);
171
- if (context) {
172
- // Apply filters
173
- if (sessionId && context.session !== sessionId) {
174
- continue;
175
- }
176
- if (agentType && context.agent !== agentType) {
177
- continue;
178
- }
179
- agents.push(context);
180
- }
181
- }
182
- catch {
183
- // Skip files that can't be read
184
- continue;
185
- }
186
- }
187
- return agents;
188
- }
189
- catch {
190
- return [];
191
- }
192
- }
193
- /**
194
- * Find agent files by various criteria
195
- */
196
- export async function findAgentFiles(directory, agentType, sessionId) {
197
- const agentsDir = `${directory}/.feature-factory/agents`;
198
- try {
199
- await stat(agentsDir);
200
- }
201
- catch {
202
- return [];
203
- }
204
- try {
205
- const entries = await readdir(agentsDir, { withFileTypes: true });
206
- let files = entries
207
- .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
208
- .map((entry) => `${agentsDir}/${entry.name}`);
209
- if (agentType) {
210
- files = files.filter((file) => file.includes(`${agentType}-`));
211
- }
212
- if (sessionId) {
213
- // Filter by session ID (need to read files)
214
- const filteredFiles = [];
215
- for (const file of files) {
216
- try {
217
- const content = await readFile(file, 'utf-8');
218
- if (content.includes(`session: "${sessionId}"`)) {
219
- filteredFiles.push(file);
220
- }
221
- }
222
- catch {
223
- continue;
224
- }
225
- }
226
- return filteredFiles;
227
- }
228
- return files;
229
- }
230
- catch {
231
- return [];
232
- }
233
- }
234
- /**
235
- * Find agent file by UUID
236
- */
237
- export async function findAgentFilesById(directory, id) {
238
- if (!isValidUUID(id)) {
239
- return [];
240
- }
241
- try {
242
- const agentsDir = `${directory}/.feature-factory/agents`;
243
- const entries = await readdir(agentsDir, { withFileTypes: true });
244
- return entries
245
- .filter((entry) => entry.isFile() && entry.name.endsWith('.md') && entry.name.includes(`-${id}.md`))
246
- .map((entry) => `${agentsDir}/${entry.name}`);
247
- }
248
- catch {
249
- return [];
250
- }
251
- }
252
- /**
253
- * Find all agent files
254
- */
255
- export async function findAllAgentFiles(directory) {
256
- const agentsDir = `${directory}/.feature-factory/agents`;
257
- try {
258
- const entries = await readdir(agentsDir, { withFileTypes: true });
259
- return entries
260
- .filter((entry) => entry.isFile() && entry.name.endsWith('.md'))
261
- .map((entry) => `${agentsDir}/${entry.name}`);
262
- }
263
- catch {
264
- return [];
265
- }
266
- }
267
- /**
268
- * Delete agent files
269
- */
270
- export async function deleteAgentFiles(directory, files) {
271
- let deletedCount = 0;
272
- for (const file of files) {
273
- try {
274
- await unlink(file);
275
- deletedCount++;
276
- }
277
- catch {
278
- // Continue even if one file fails
279
- }
280
- }
281
- return deletedCount;
282
- }
@@ -1,2 +0,0 @@
1
- import { tool } from '@opencode-ai/plugin/tool';
2
- export declare function createFFAgentContextCreateTool(): ReturnType<typeof tool>;
@@ -1,82 +0,0 @@
1
- import { tool } from '@opencode-ai/plugin/tool';
2
- import { writeFile, mkdir } from 'fs/promises';
3
- import { dirname } from 'path';
4
- export function createFFAgentContextCreateTool() {
5
- return tool({
6
- description: 'Create a new agent context file in .feature-factory/agents/. Use this to document agent tasks, track progress, and maintain delegation chains.',
7
- args: {
8
- id: tool.schema.string().describe('Unique UUID for this agent instance'),
9
- agent: tool.schema
10
- .string()
11
- .describe('Agent type (e.g., planning, building, reviewing, ff-research)'),
12
- title: tool.schema.string().describe('Task title'),
13
- description: tool.schema.string().describe('Detailed task description'),
14
- status: tool.schema
15
- .enum(['in-progress', 'completed', 'delegated', 'failed'])
16
- .default('in-progress')
17
- .describe('Current status'),
18
- parent: tool.schema.string().optional().describe('Parent agent UUID if this was delegated'),
19
- delegatedTo: tool.schema
20
- .array(tool.schema.string())
21
- .optional()
22
- .describe('Array of child agent UUIDs'),
23
- notes: tool.schema.string().optional().describe('Additional notes or context'),
24
- },
25
- async execute(args, toolCtx) {
26
- try {
27
- const timestamp = new Date().toISOString();
28
- const filePath = `${toolCtx.directory}/.feature-factory/agents/${args.agent}-${args.id}.md`;
29
- // Generate frontmatter
30
- const frontmatter = `---
31
-
32
- id: "${args.id}"
33
- agent: ${args.agent}
34
- title: "${args.title}"
35
- description: "${args.description}"
36
- folder: "${toolCtx.directory}"
37
- status: ${args.status}
38
- started: "${timestamp}"
39
- session: "${args.agent}-${args.id}"
40
- ${args.parent ? `parent: "${args.parent}"` : 'parent: null'}
41
- ${args.delegatedTo && args.delegatedTo.length > 0 ? `delegated_to:\n${args.delegatedTo.map((id) => ` - "${id}"`).join('\n')}` : 'delegated_to: []'}
42
-
43
- ---`;
44
- const body = `
45
-
46
- ## Task Context
47
-
48
- ${args.description}
49
-
50
- ## Progress
51
-
52
- - [x] Task started
53
- - [ ] Analysis complete
54
- - [ ] Implementation pending
55
-
56
- ## Delegated Work
57
-
58
- No delegated work yet.
59
-
60
- ${args.notes ? `## Notes\n\n${args.notes}` : ''}
61
- `;
62
- const fullContent = `${frontmatter}${body}`;
63
- // Ensure directory exists
64
- await mkdir(dirname(filePath), { recursive: true });
65
- // Write file
66
- await writeFile(filePath, fullContent, 'utf-8');
67
- return JSON.stringify({
68
- success: true,
69
- agentId: args.id,
70
- filePath: `.feature-factory/agents/${args.agent}-${args.id}.md`,
71
- message: `Agent context created successfully at .feature-factory/agents/${args.agent}-${args.id}.md`,
72
- }, null, 2);
73
- }
74
- catch (error) {
75
- return JSON.stringify({
76
- success: false,
77
- error: `Failed to create agent context: ${error}`,
78
- }, null, 2);
79
- }
80
- },
81
- });
82
- }
@@ -1,2 +0,0 @@
1
- import { tool } from '@opencode-ai/plugin/tool';
2
- export declare function createFFAgentContextUpdateTool(): ReturnType<typeof tool>;
@@ -1,78 +0,0 @@
1
- import { tool } from '@opencode-ai/plugin/tool';
2
- import { readFile, writeFile } from 'fs/promises';
3
- export function createFFAgentContextUpdateTool() {
4
- return tool({
5
- description: 'Update an existing agent context file in .feature-factory/agents/. Use this to update status, add delegated agents, or append notes.',
6
- args: {
7
- agentId: tool.schema.string().describe('Agent UUID to update'),
8
- agent: tool.schema.string().describe('Agent type'),
9
- status: tool.schema
10
- .enum(['in-progress', 'completed', 'delegated', 'failed'])
11
- .optional()
12
- .describe('New status'),
13
- addDelegatedTo: tool.schema
14
- .string()
15
- .optional()
16
- .describe('Add a child agent UUID to delegated_to list'),
17
- notes: tool.schema.string().optional().describe('Notes to append to the file'),
18
- progressUpdate: tool.schema
19
- .string()
20
- .optional()
21
- .describe('Progress update to add (e.g., "- [x] Step completed")'),
22
- },
23
- async execute(args, toolCtx) {
24
- try {
25
- const filePath = `${toolCtx.directory}/.feature-factory/agents/${args.agent}-${args.agentId}.md`;
26
- // Read existing file
27
- let content;
28
- try {
29
- content = await readFile(filePath, 'utf-8');
30
- }
31
- catch {
32
- return JSON.stringify({
33
- success: false,
34
- error: `Agent context file not found: ${filePath}`,
35
- }, null, 2);
36
- }
37
- // Update status if provided
38
- if (args.status) {
39
- content = content.replace(/status: (in-progress|completed|delegated|failed)/, `status: ${args.status}`);
40
- }
41
- // Add delegated agent if provided
42
- if (args.addDelegatedTo) {
43
- if (content.includes('delegated_to: []')) {
44
- content = content.replace('delegated_to: []', `delegated_to:\n - "${args.addDelegatedTo}"`);
45
- }
46
- else if (content.includes('delegated_to:')) {
47
- content = content.replace(/(delegated_to:\n(?: {2}- ".*"\n)*)/, `$1 - "${args.addDelegatedTo}"\n`);
48
- }
49
- }
50
- // Append notes if provided
51
- if (args.notes) {
52
- const timestamp = new Date().toISOString();
53
- content += `\n\n## Update - ${timestamp}\n\n${args.notes}\n`;
54
- }
55
- // Add progress update if provided
56
- if (args.progressUpdate) {
57
- if (content.includes('## Progress')) {
58
- content = content.replace(/(## Progress\n\n)/, `$1${args.progressUpdate}\n`);
59
- }
60
- }
61
- // Write updated file
62
- await writeFile(filePath, content, 'utf-8');
63
- return JSON.stringify({
64
- success: true,
65
- agentId: args.agentId,
66
- filePath: `.feature-factory/agents/${args.agent}-${args.agentId}.md`,
67
- message: `Agent context updated successfully`,
68
- }, null, 2);
69
- }
70
- catch (error) {
71
- return JSON.stringify({
72
- success: false,
73
- error: `Failed to update agent context: ${error}`,
74
- }, null, 2);
75
- }
76
- },
77
- });
78
- }