@syntesseraai/opencode-feature-factory 0.2.34 → 0.2.36

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 (58) hide show
  1. package/dist/agent-context.d.ts +11 -8
  2. package/dist/agent-context.js +69 -60
  3. package/dist/index.js +23 -23
  4. package/dist/learning/memory-get.d.ts +1 -2
  5. package/dist/learning/memory-get.js +4 -4
  6. package/dist/learning/memory-search.d.ts +1 -2
  7. package/dist/learning/memory-search.js +3 -3
  8. package/dist/learning/memory-store.d.ts +1 -2
  9. package/dist/learning/memory-store.js +2 -2
  10. package/dist/plugins/ff-agent-context-create-plugin.d.ts +1 -2
  11. package/dist/plugins/ff-agent-context-create-plugin.js +4 -4
  12. package/dist/plugins/ff-agent-context-update-plugin.d.ts +1 -2
  13. package/dist/plugins/ff-agent-context-update-plugin.js +3 -3
  14. package/dist/plugins/ff-agents-clear-plugin.d.ts +1 -2
  15. package/dist/plugins/ff-agents-clear-plugin.js +10 -18
  16. package/dist/plugins/ff-agents-current-plugin.d.ts +1 -2
  17. package/dist/plugins/ff-agents-current-plugin.js +3 -3
  18. package/dist/plugins/ff-agents-delete-plugin.d.ts +1 -2
  19. package/dist/plugins/ff-agents-delete-plugin.js +8 -12
  20. package/dist/plugins/ff-agents-get-plugin.d.ts +1 -2
  21. package/dist/plugins/ff-agents-get-plugin.js +9 -13
  22. package/dist/plugins/ff-agents-list-plugin.d.ts +1 -2
  23. package/dist/plugins/ff-agents-list-plugin.js +16 -27
  24. package/dist/plugins/ff-agents-show-plugin.d.ts +1 -2
  25. package/dist/plugins/ff-agents-show-plugin.js +3 -3
  26. package/dist/plugins/ff-agents-update-plugin.d.ts +1 -2
  27. package/dist/plugins/ff-agents-update-plugin.js +7 -7
  28. package/dist/plugins/ff-learning-get-plugin.d.ts +1 -2
  29. package/dist/plugins/ff-learning-get-plugin.js +3 -3
  30. package/dist/plugins/ff-learning-search-plugin.d.ts +1 -2
  31. package/dist/plugins/ff-learning-search-plugin.js +3 -3
  32. package/dist/plugins/ff-learning-store-plugin.d.ts +1 -2
  33. package/dist/plugins/ff-learning-store-plugin.js +3 -3
  34. package/dist/plugins/ff-plan-create-plugin.d.ts +1 -2
  35. package/dist/plugins/ff-plan-create-plugin.js +3 -3
  36. package/dist/plugins/ff-plan-update-plugin.d.ts +1 -2
  37. package/dist/plugins/ff-plan-update-plugin.js +4 -4
  38. package/dist/plugins/ff-plans-delete-plugin.d.ts +1 -2
  39. package/dist/plugins/ff-plans-delete-plugin.js +8 -12
  40. package/dist/plugins/ff-plans-get-plugin.d.ts +1 -2
  41. package/dist/plugins/ff-plans-get-plugin.js +9 -13
  42. package/dist/plugins/ff-plans-list-plugin.d.ts +1 -2
  43. package/dist/plugins/ff-plans-list-plugin.js +16 -27
  44. package/dist/plugins/ff-plans-update-plugin.d.ts +1 -2
  45. package/dist/plugins/ff-plans-update-plugin.js +7 -7
  46. package/dist/plugins/ff-review-create-plugin.d.ts +1 -2
  47. package/dist/plugins/ff-review-create-plugin.js +3 -3
  48. package/dist/plugins/ff-reviews-delete-plugin.d.ts +1 -2
  49. package/dist/plugins/ff-reviews-delete-plugin.js +8 -12
  50. package/dist/plugins/ff-reviews-get-plugin.d.ts +1 -2
  51. package/dist/plugins/ff-reviews-get-plugin.js +9 -13
  52. package/dist/plugins/ff-reviews-list-plugin.d.ts +1 -2
  53. package/dist/plugins/ff-reviews-list-plugin.js +16 -27
  54. package/dist/plugins/ff-reviews-update-plugin.d.ts +1 -2
  55. package/dist/plugins/ff-reviews-update-plugin.js +7 -7
  56. package/dist/utils/file-utils.d.ts +1 -3
  57. package/dist/utils/file-utils.js +4 -5
  58. package/package.json +1 -1
@@ -1,4 +1,3 @@
1
- import type { PluginInput } from '@opencode-ai/plugin';
2
1
  export interface AgentContext {
3
2
  /** Unique UUID for this agent instance */
4
3
  id: string;
@@ -27,28 +26,32 @@ export interface AgentContext {
27
26
  * Write an agent context file
28
27
  * File naming: {agent}-{uuid}.md
29
28
  */
30
- export declare function writeAgentContext(input: PluginInput, context: AgentContext): Promise<string>;
29
+ export declare function writeAgentContext(directory: string, context: AgentContext): Promise<string>;
31
30
  /**
32
31
  * Read an agent context file by UUID
33
32
  */
34
- export declare function readAgentContextById(input: PluginInput, id: string): Promise<AgentContext | null>;
33
+ export declare function readAgentContextById(directory: string, id: string): Promise<AgentContext | null>;
35
34
  /**
36
35
  * Update agent status in context file
37
36
  */
38
- export declare function updateAgentStatus(input: PluginInput, id: string, status: AgentContext['status']): Promise<boolean>;
37
+ export declare function updateAgentStatus(directory: string, id: string, status: AgentContext['status']): Promise<boolean>;
39
38
  /**
40
39
  * List all active agents
41
40
  */
42
- export declare function listActiveAgents(input: PluginInput, sessionId?: string, agentType?: string): Promise<AgentContext[]>;
41
+ export declare function listActiveAgents(directory: string, sessionId?: string, agentType?: string): Promise<AgentContext[]>;
43
42
  /**
44
43
  * Find agent files by various criteria
45
44
  */
46
- export declare function findAgentFiles(input: PluginInput, agentType?: string, sessionId?: string): Promise<string[]>;
45
+ export declare function findAgentFiles(directory: string, agentType?: string, sessionId?: string): Promise<string[]>;
47
46
  /**
48
47
  * Find agent file by UUID
49
48
  */
50
- export declare function findAgentFilesById(input: PluginInput, id: string): Promise<string[]>;
49
+ export declare function findAgentFilesById(directory: string, id: string): Promise<string[]>;
51
50
  /**
52
51
  * Find all agent files
53
52
  */
54
- export declare function findAllAgentFiles(input: PluginInput): Promise<string[]>;
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,4 +1,5 @@
1
1
  import { isValidUUID } from './uuid.js';
2
+ import { writeFile, readFile, readdir, stat, unlink } from 'fs/promises';
2
3
  /**
3
4
  * Generate the content for an agent context file
4
5
  */
@@ -35,14 +36,12 @@ ${context.delegated_to && context.delegated_to.length > 0 ? context.delegated_to
35
36
  * Write an agent context file
36
37
  * File naming: {agent}-{uuid}.md
37
38
  */
38
- export async function writeAgentContext(input, context) {
39
- const { directory, $ } = input;
39
+ export async function writeAgentContext(directory, context) {
40
40
  const fileName = `${context.agent}-${context.id}.md`;
41
41
  const filePath = `${directory}/.feature-factory/agents/${fileName}`;
42
42
  const content = generateContextFileContent(context);
43
43
  try {
44
- // Use echo to write file (Bun shell)
45
- await $ `echo ${content} > ${filePath}`.quiet();
44
+ await writeFile(filePath, content, 'utf-8');
46
45
  return filePath;
47
46
  }
48
47
  catch (error) {
@@ -52,21 +51,24 @@ export async function writeAgentContext(input, context) {
52
51
  /**
53
52
  * Read an agent context file by UUID
54
53
  */
55
- export async function readAgentContextById(input, id) {
56
- const { directory, $ } = input;
54
+ export async function readAgentContextById(directory, id) {
57
55
  if (!isValidUUID(id)) {
58
56
  return null;
59
57
  }
60
58
  try {
61
- // Find file with this UUID
62
- const result = await $ `ls ${directory}/.feature-factory/agents/ | grep "-${id}.md"`.quiet();
63
- const fileName = result.text().trim();
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`));
64
66
  if (!fileName) {
65
67
  return null;
66
68
  }
67
- const filePath = `${directory}/.feature-factory/agents/${fileName}`;
68
- const content = await $ `cat ${filePath}`.quiet();
69
- return parseAgentContext(content.text());
69
+ const filePath = `${agentsDir}/${fileName}`;
70
+ const content = await readFile(filePath, 'utf-8');
71
+ return parseAgentContext(content);
70
72
  }
71
73
  catch {
72
74
  return null;
@@ -119,22 +121,25 @@ function parseAgentContext(content) {
119
121
  /**
120
122
  * Update agent status in context file
121
123
  */
122
- export async function updateAgentStatus(input, id, status) {
123
- const { directory, $ } = input;
124
+ export async function updateAgentStatus(directory, id, status) {
124
125
  try {
125
- const result = await $ `ls ${directory}/.feature-factory/agents/ | grep "-${id}.md"`.quiet();
126
- const fileName = result.text().trim();
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`));
127
132
  if (!fileName) {
128
133
  return false;
129
134
  }
130
- const filePath = `${directory}/.feature-factory/agents/${fileName}`;
135
+ const filePath = `${agentsDir}/${fileName}`;
131
136
  // Read current content
132
- const content = await $ `cat ${filePath}`.quiet();
133
- let text = content.text();
137
+ const content = await readFile(filePath, 'utf-8');
138
+ let text = content;
134
139
  // Replace status line
135
140
  text = text.replace(/status: \w+/, `status: ${status}`);
136
141
  // Write back
137
- await $ `echo ${text} > ${filePath}`.quiet();
142
+ await writeFile(filePath, text, 'utf-8');
138
143
  return true;
139
144
  }
140
145
  catch {
@@ -144,28 +149,25 @@ export async function updateAgentStatus(input, id, status) {
144
149
  /**
145
150
  * List all active agents
146
151
  */
147
- export async function listActiveAgents(input, sessionId, agentType) {
148
- const { directory, $ } = input;
152
+ export async function listActiveAgents(directory, sessionId, agentType) {
149
153
  const agentsDir = `${directory}/.feature-factory/agents`;
150
154
  try {
151
155
  // Check if directory exists
152
- await $ `test -d ${agentsDir}`.quiet();
156
+ await stat(agentsDir);
153
157
  }
154
158
  catch {
155
159
  return [];
156
160
  }
157
161
  try {
158
- const result = await $ `ls ${agentsDir}/*.md 2>/dev/null || echo ""`.quiet();
159
- const files = result
160
- .text()
161
- .trim()
162
- .split('\n')
163
- .filter((f) => f.endsWith('.md'));
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}`);
164
166
  const agents = [];
165
167
  for (const filePath of files) {
166
168
  try {
167
- const content = await $ `cat ${filePath}`.quiet();
168
- const context = parseAgentContext(content.text());
169
+ const content = await readFile(filePath, 'utf-8');
170
+ const context = parseAgentContext(content);
169
171
  if (context) {
170
172
  // Apply filters
171
173
  if (sessionId && context.session !== sessionId) {
@@ -191,33 +193,29 @@ export async function listActiveAgents(input, sessionId, agentType) {
191
193
  /**
192
194
  * Find agent files by various criteria
193
195
  */
194
- export async function findAgentFiles(input, agentType, sessionId) {
195
- const { directory, $ } = input;
196
+ export async function findAgentFiles(directory, agentType, sessionId) {
196
197
  const agentsDir = `${directory}/.feature-factory/agents`;
197
198
  try {
198
- await $ `test -d ${agentsDir}`.quiet();
199
+ await stat(agentsDir);
199
200
  }
200
201
  catch {
201
202
  return [];
202
203
  }
203
204
  try {
204
- let pattern = '*.md';
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}`);
205
209
  if (agentType) {
206
- pattern = `${agentType}-*.md`;
210
+ files = files.filter((file) => file.includes(`${agentType}-`));
207
211
  }
208
- const result = await $ `ls ${agentsDir}/${pattern} 2>/dev/null || echo ""`.quiet();
209
- const files = result
210
- .text()
211
- .trim()
212
- .split('\n')
213
- .filter((f) => f && f.endsWith('.md'));
214
212
  if (sessionId) {
215
213
  // Filter by session ID (need to read files)
216
214
  const filteredFiles = [];
217
215
  for (const file of files) {
218
216
  try {
219
- const content = await $ `cat ${file}`.quiet();
220
- if (content.text().includes(`session: "${sessionId}"`)) {
217
+ const content = await readFile(file, 'utf-8');
218
+ if (content.includes(`session: "${sessionId}"`)) {
221
219
  filteredFiles.push(file);
222
220
  }
223
221
  }
@@ -236,18 +234,16 @@ export async function findAgentFiles(input, agentType, sessionId) {
236
234
  /**
237
235
  * Find agent file by UUID
238
236
  */
239
- export async function findAgentFilesById(input, id) {
240
- const { directory, $ } = input;
237
+ export async function findAgentFilesById(directory, id) {
241
238
  if (!isValidUUID(id)) {
242
239
  return [];
243
240
  }
244
241
  try {
245
- const result = await $ `ls ${directory}/.feature-factory/agents/*-${id}.md 2>/dev/null || echo ""`.quiet();
246
- return result
247
- .text()
248
- .trim()
249
- .split('\n')
250
- .filter((f) => f && f.endsWith('.md'));
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}`);
251
247
  }
252
248
  catch {
253
249
  return [];
@@ -256,18 +252,31 @@ export async function findAgentFilesById(input, id) {
256
252
  /**
257
253
  * Find all agent files
258
254
  */
259
- export async function findAllAgentFiles(input) {
260
- const { directory, $ } = input;
255
+ export async function findAllAgentFiles(directory) {
261
256
  const agentsDir = `${directory}/.feature-factory/agents`;
262
257
  try {
263
- const result = await $ `ls ${agentsDir}/*.md 2>/dev/null || echo ""`.quiet();
264
- return result
265
- .text()
266
- .trim()
267
- .split('\n')
268
- .filter((f) => f && f.endsWith('.md'));
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}`);
269
262
  }
270
263
  catch {
271
264
  return [];
272
265
  }
273
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
+ }
package/dist/index.js CHANGED
@@ -42,36 +42,36 @@ export const FeatureFactoryPlugin = async (input) => {
42
42
  // Create all tools
43
43
  const tools = {
44
44
  // Agent management tools
45
- 'ff-agents-current': createFFAgentsCurrentTool(input),
46
- 'ff-agents-show': createFFAgentsShowTool(input),
47
- 'ff-agents-clear': createFFAgentsClearTool(input),
45
+ 'ff-agents-current': createFFAgentsCurrentTool(),
46
+ 'ff-agents-show': createFFAgentsShowTool(),
47
+ 'ff-agents-clear': createFFAgentsClearTool(),
48
48
  // Learning/memory tools
49
- 'ff-learning-store': createFFLearningStoreTool(input),
50
- 'ff-learning-search': createFFLearningSearchTool(input),
51
- 'ff-learning-get': createFFLearningGetTool(input),
49
+ 'ff-learning-store': createFFLearningStoreTool(),
50
+ 'ff-learning-search': createFFLearningSearchTool(),
51
+ 'ff-learning-get': createFFLearningGetTool(),
52
52
  // Plan tools
53
- 'ff-plan-create': createFFPlanCreateTool(input),
54
- 'ff-plan-update': createFFPlanUpdateTool(input),
53
+ 'ff-plan-create': createFFPlanCreateTool(),
54
+ 'ff-plan-update': createFFPlanUpdateTool(),
55
55
  // Agent context tools
56
- 'ff-agent-context-create': createFFAgentContextCreateTool(input),
57
- 'ff-agent-context-update': createFFAgentContextUpdateTool(input),
56
+ 'ff-agent-context-create': createFFAgentContextCreateTool(),
57
+ 'ff-agent-context-update': createFFAgentContextUpdateTool(),
58
58
  // Review tools
59
- 'ff-review-create': createFFReviewCreateTool(input),
59
+ 'ff-review-create': createFFReviewCreateTool(),
60
60
  // File management - agents
61
- 'ff-agents-get': createFFAgentsGetTool(input),
62
- 'ff-agents-update': createFFAgentsUpdateTool(input),
63
- 'ff-agents-delete': createFFAgentsDeleteTool(input),
64
- 'ff-agents-list': createFFAgentsListTool(input),
61
+ 'ff-agents-get': createFFAgentsGetTool(),
62
+ 'ff-agents-update': createFFAgentsUpdateTool(),
63
+ 'ff-agents-delete': createFFAgentsDeleteTool(),
64
+ 'ff-agents-list': createFFAgentsListTool(),
65
65
  // File management - plans
66
- 'ff-plans-get': createFFPlansGetTool(input),
67
- 'ff-plans-update': createFFPlansUpdateTool(input),
68
- 'ff-plans-delete': createFFPlansDeleteTool(input),
69
- 'ff-plans-list': createFFPlansListTool(input),
66
+ 'ff-plans-get': createFFPlansGetTool(),
67
+ 'ff-plans-update': createFFPlansUpdateTool(),
68
+ 'ff-plans-delete': createFFPlansDeleteTool(),
69
+ 'ff-plans-list': createFFPlansListTool(),
70
70
  // File management - reviews
71
- 'ff-reviews-get': createFFReviewsGetTool(input),
72
- 'ff-reviews-update': createFFReviewsUpdateTool(input),
73
- 'ff-reviews-delete': createFFReviewsDeleteTool(input),
74
- 'ff-reviews-list': createFFReviewsListTool(input),
71
+ 'ff-reviews-get': createFFReviewsGetTool(),
72
+ 'ff-reviews-update': createFFReviewsUpdateTool(),
73
+ 'ff-reviews-delete': createFFReviewsDeleteTool(),
74
+ 'ff-reviews-list': createFFReviewsListTool(),
75
75
  };
76
76
  // Return combined hooks and tools
77
77
  return {
@@ -1,4 +1,3 @@
1
- import type { PluginInput } from '@opencode-ai/plugin';
2
1
  export interface GetCriteria {
3
2
  memoryId?: string;
4
3
  filePath?: string;
@@ -22,4 +21,4 @@ export interface MemoryData {
22
21
  content: string;
23
22
  filePath: string;
24
23
  }
25
- export declare function getMemory(input: PluginInput, criteria: GetCriteria): Promise<MemoryData | null>;
24
+ export declare function getMemory(directory: string, criteria: GetCriteria): Promise<MemoryData | null>;
@@ -1,13 +1,13 @@
1
1
  import { readFile } from 'fs/promises';
2
- export async function getMemory(input, criteria) {
2
+ export async function getMemory(directory, criteria) {
3
3
  try {
4
4
  let filePath = null;
5
5
  if (criteria.filePath) {
6
- filePath = `${input.directory}/${criteria.filePath}`;
6
+ filePath = `${directory}/${criteria.filePath}`;
7
7
  }
8
8
  else if (criteria.memoryId) {
9
9
  // Search for file by ID
10
- filePath = await findFileById(input.directory, criteria.memoryId);
10
+ filePath = await findFileById(directory, criteria.memoryId);
11
11
  if (!filePath) {
12
12
  return null;
13
13
  }
@@ -36,7 +36,7 @@ export async function getMemory(input, criteria) {
36
36
  relatedMemories: metadata.related_memories,
37
37
  context: metadata.context,
38
38
  content: bodyContent,
39
- filePath: criteria.filePath || (filePath ? filePath.replace(`${input.directory}/`, '') : ''),
39
+ filePath: criteria.filePath || (filePath ? filePath.replace(`${directory}/`, '') : ''),
40
40
  };
41
41
  }
42
42
  catch {
@@ -1,4 +1,3 @@
1
- import type { PluginInput } from '@opencode-ai/plugin';
2
1
  export interface SearchCriteria {
3
2
  query: string;
4
3
  tags?: string[];
@@ -18,4 +17,4 @@ export interface MemoryMetadata {
18
17
  tags: string[];
19
18
  filePath: string;
20
19
  }
21
- export declare function searchMemories(input: PluginInput, criteria: SearchCriteria): Promise<MemoryMetadata[]>;
20
+ export declare function searchMemories(directory: string, criteria: SearchCriteria): Promise<MemoryMetadata[]>;
@@ -1,7 +1,7 @@
1
1
  import { readFile, readdir } from 'fs/promises';
2
2
  import { join, relative } from 'path';
3
- export async function searchMemories(input, criteria) {
4
- const memoriesDir = `${input.directory}/.feature-factory/memories`;
3
+ export async function searchMemories(directory, criteria) {
4
+ const memoriesDir = `${directory}/.feature-factory/memories`;
5
5
  const results = [];
6
6
  try {
7
7
  // Find all memory files
@@ -58,7 +58,7 @@ export async function searchMemories(input, criteria) {
58
58
  agentId: metadata.agent_id,
59
59
  importance: metadata.importance,
60
60
  tags: tags,
61
- filePath: relative(input.directory, filePath),
61
+ filePath: relative(directory, filePath),
62
62
  relevance,
63
63
  });
64
64
  }
@@ -1,4 +1,3 @@
1
- import type { PluginInput } from '@opencode-ai/plugin';
2
1
  export interface MemoryInput {
3
2
  title: string;
4
3
  description: string;
@@ -18,4 +17,4 @@ export interface MemoryResult {
18
17
  id: string;
19
18
  filePath: string;
20
19
  }
21
- export declare function storeMemory(input: PluginInput, memoryInput: MemoryInput): Promise<MemoryResult>;
20
+ export declare function storeMemory(directory: string, memoryInput: MemoryInput): Promise<MemoryResult>;
@@ -1,12 +1,12 @@
1
1
  import { v4 as uuidv4 } from 'uuid';
2
2
  import { writeFile, mkdir } from 'fs/promises';
3
3
  import { dirname } from 'path';
4
- export async function storeMemory(input, memoryInput) {
4
+ export async function storeMemory(directory, memoryInput) {
5
5
  const id = uuidv4();
6
6
  const date = new Date().toISOString();
7
7
  // Determine file path based on memory type
8
8
  const filePath = generateMemoryFilePath(memoryInput.memoryType, id, date);
9
- const fullPath = `${input.directory}/${filePath}`;
9
+ const fullPath = `${directory}/${filePath}`;
10
10
  // Generate frontmatter
11
11
  const frontmatter = generateFrontmatter(id, date, memoryInput);
12
12
  // Generate full content
@@ -1,3 +1,2 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import type { PluginInput } from '@opencode-ai/plugin';
3
- export declare function createFFAgentContextCreateTool(input: PluginInput): ReturnType<typeof tool>;
2
+ export declare function createFFAgentContextCreateTool(): ReturnType<typeof tool>;
@@ -1,7 +1,7 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
2
  import { writeFile, mkdir } from 'fs/promises';
3
3
  import { dirname } from 'path';
4
- export function createFFAgentContextCreateTool(input) {
4
+ export function createFFAgentContextCreateTool() {
5
5
  return tool({
6
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
7
  args: {
@@ -22,10 +22,10 @@ export function createFFAgentContextCreateTool(input) {
22
22
  .describe('Array of child agent UUIDs'),
23
23
  notes: tool.schema.string().optional().describe('Additional notes or context'),
24
24
  },
25
- async execute(args) {
25
+ async execute(args, toolCtx) {
26
26
  try {
27
27
  const timestamp = new Date().toISOString();
28
- const filePath = `${input.directory}/.feature-factory/agents/${args.agent}-${args.id}.md`;
28
+ const filePath = `${toolCtx.directory}/.feature-factory/agents/${args.agent}-${args.id}.md`;
29
29
  // Generate frontmatter
30
30
  const frontmatter = `---
31
31
 
@@ -33,7 +33,7 @@ id: "${args.id}"
33
33
  agent: ${args.agent}
34
34
  title: "${args.title}"
35
35
  description: "${args.description}"
36
- folder: "${input.directory}"
36
+ folder: "${toolCtx.directory}"
37
37
  status: ${args.status}
38
38
  started: "${timestamp}"
39
39
  session: "${args.agent}-${args.id}"
@@ -1,3 +1,2 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import type { PluginInput } from '@opencode-ai/plugin';
3
- export declare function createFFAgentContextUpdateTool(input: PluginInput): ReturnType<typeof tool>;
2
+ export declare function createFFAgentContextUpdateTool(): ReturnType<typeof tool>;
@@ -1,6 +1,6 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
2
  import { readFile, writeFile } from 'fs/promises';
3
- export function createFFAgentContextUpdateTool(input) {
3
+ export function createFFAgentContextUpdateTool() {
4
4
  return tool({
5
5
  description: 'Update an existing agent context file in .feature-factory/agents/. Use this to update status, add delegated agents, or append notes.',
6
6
  args: {
@@ -20,9 +20,9 @@ export function createFFAgentContextUpdateTool(input) {
20
20
  .optional()
21
21
  .describe('Progress update to add (e.g., "- [x] Step completed")'),
22
22
  },
23
- async execute(args) {
23
+ async execute(args, toolCtx) {
24
24
  try {
25
- const filePath = `${input.directory}/.feature-factory/agents/${args.agent}-${args.agentId}.md`;
25
+ const filePath = `${toolCtx.directory}/.feature-factory/agents/${args.agent}-${args.agentId}.md`;
26
26
  // Read existing file
27
27
  let content;
28
28
  try {
@@ -1,3 +1,2 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import type { PluginInput } from '@opencode-ai/plugin';
3
- export declare function createFFAgentsClearTool(input: PluginInput): ReturnType<typeof tool>;
2
+ export declare function createFFAgentsClearTool(): ReturnType<typeof tool>;
@@ -1,7 +1,6 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import { findAgentFiles, findAgentFilesById, findAllAgentFiles } from '../agent-context.js';
3
- export function createFFAgentsClearTool(input) {
4
- const { $ } = input;
2
+ import { findAgentFiles, findAgentFilesById, findAllAgentFiles, deleteAgentFiles, } from '../agent-context.js';
3
+ export function createFFAgentsClearTool() {
5
4
  return tool({
6
5
  description: 'Clear agent context files. Can clear all, or filter by session, agent type, or specific UUID',
7
6
  args: {
@@ -9,36 +8,29 @@ export function createFFAgentsClearTool(input) {
9
8
  agent: tool.schema.string().optional().describe('Clear only specific agent type'),
10
9
  id: tool.schema.string().optional().describe('Clear specific agent by UUID'),
11
10
  },
12
- async execute(args) {
11
+ async execute(args, toolCtx) {
13
12
  try {
14
13
  let files = [];
15
14
  if (args.id) {
16
- files = await findAgentFilesById(input, args.id);
15
+ files = await findAgentFilesById(toolCtx.directory, args.id);
17
16
  }
18
17
  else if (args.agent && args.sessionID) {
19
- files = await findAgentFiles(input, args.agent, args.sessionID);
18
+ files = await findAgentFiles(toolCtx.directory, args.agent, args.sessionID);
20
19
  }
21
20
  else if (args.sessionID) {
22
- files = await findAgentFiles(input, undefined, args.sessionID);
21
+ files = await findAgentFiles(toolCtx.directory, undefined, args.sessionID);
23
22
  }
24
23
  else if (args.agent) {
25
- files = await findAgentFiles(input, args.agent);
24
+ files = await findAgentFiles(toolCtx.directory, args.agent);
26
25
  }
27
26
  else {
28
- files = await findAllAgentFiles(input);
27
+ files = await findAllAgentFiles(toolCtx.directory);
29
28
  }
30
29
  if (files.length === 0) {
31
30
  return 'No agent context files found to clear.';
32
31
  }
33
- for (const file of files) {
34
- try {
35
- await $ `rm ${file}`.quiet();
36
- }
37
- catch {
38
- // Continue even if one file fails
39
- }
40
- }
41
- return `Cleared ${files.length} agent context file(s)`;
32
+ const deletedCount = await deleteAgentFiles(toolCtx.directory, files);
33
+ return `Cleared ${deletedCount} agent context file(s)`;
42
34
  }
43
35
  catch (error) {
44
36
  return `Error clearing agents: ${error}`;
@@ -1,3 +1,2 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import type { PluginInput } from '@opencode-ai/plugin';
3
- export declare function createFFAgentsCurrentTool(input: PluginInput): ReturnType<typeof tool>;
2
+ export declare function createFFAgentsCurrentTool(): ReturnType<typeof tool>;
@@ -1,6 +1,6 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
2
  import { listActiveAgents } from '../agent-context.js';
3
- export function createFFAgentsCurrentTool(input) {
3
+ export function createFFAgentsCurrentTool() {
4
4
  return tool({
5
5
  description: 'List all currently active Feature Factory agents with their UUIDs and status',
6
6
  args: {
@@ -10,9 +10,9 @@ export function createFFAgentsCurrentTool(input) {
10
10
  .optional()
11
11
  .describe('Filter by agent type (e.g., planning, research)'),
12
12
  },
13
- async execute(args) {
13
+ async execute(args, toolCtx) {
14
14
  try {
15
- const agents = await listActiveAgents(input, args.sessionID, args.agent);
15
+ const agents = await listActiveAgents(toolCtx.directory, args.sessionID, args.agent);
16
16
  if (agents.length === 0) {
17
17
  return JSON.stringify({
18
18
  count: 0,
@@ -1,3 +1,2 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import type { PluginInput } from '@opencode-ai/plugin';
3
- export declare function createFFAgentsDeleteTool(input: PluginInput): ReturnType<typeof tool>;
2
+ export declare function createFFAgentsDeleteTool(): ReturnType<typeof tool>;
@@ -1,8 +1,7 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
2
  import { validateSafePath, resolveSafePath, getFeatureFactoryDir } from '../utils/file-utils.js';
3
- export function createFFAgentsDeleteTool(input) {
4
- const { directory, $ } = input;
5
- const agentsDir = getFeatureFactoryDir(directory, 'agents');
3
+ import { unlink } from 'fs/promises';
4
+ export function createFFAgentsDeleteTool() {
6
5
  return tool({
7
6
  description: 'Delete an agent context file from .feature-factory/agents',
8
7
  args: {
@@ -10,25 +9,22 @@ export function createFFAgentsDeleteTool(input) {
10
9
  .string()
11
10
  .describe('Name of the agent file to delete (e.g., "planning-abc123.md")'),
12
11
  },
13
- async execute(args) {
12
+ async execute(args, toolCtx) {
14
13
  try {
14
+ const agentsDir = getFeatureFactoryDir(toolCtx.directory, 'agents');
15
15
  // Validate the file path
16
16
  if (!validateSafePath(agentsDir, args.fileName)) {
17
17
  return `Error: Invalid or unsafe file name "${args.fileName}". Only .md files with alphanumeric names are allowed.`;
18
18
  }
19
19
  const filePath = resolveSafePath(agentsDir, args.fileName);
20
- // Check if file exists
21
- try {
22
- await $ `test -f ${filePath}`.quiet();
23
- }
24
- catch {
25
- return `Error: File "${args.fileName}" not found in .feature-factory/agents`;
26
- }
27
20
  // Delete the file
28
- await $ `rm ${filePath}`.quiet();
21
+ await unlink(filePath);
29
22
  return `Successfully deleted agent file: ${args.fileName}`;
30
23
  }
31
24
  catch (error) {
25
+ if (error.code === 'ENOENT') {
26
+ return `Error: File "${args.fileName}" not found in .feature-factory/agents`;
27
+ }
32
28
  return `Error deleting agent file: ${error}`;
33
29
  }
34
30
  },
@@ -1,3 +1,2 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import type { PluginInput } from '@opencode-ai/plugin';
3
- export declare function createFFAgentsGetTool(input: PluginInput): ReturnType<typeof tool>;
2
+ export declare function createFFAgentsGetTool(): ReturnType<typeof tool>;