@syntesseraai/opencode-feature-factory 0.2.35 → 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.
- package/dist/agent-context.d.ts +11 -8
- package/dist/agent-context.js +69 -60
- package/dist/index.js +23 -23
- package/dist/learning/memory-get.d.ts +1 -2
- package/dist/learning/memory-get.js +4 -4
- package/dist/learning/memory-search.d.ts +1 -2
- package/dist/learning/memory-search.js +3 -3
- package/dist/learning/memory-store.d.ts +1 -2
- package/dist/learning/memory-store.js +2 -2
- package/dist/plugins/ff-agent-context-create-plugin.d.ts +1 -2
- package/dist/plugins/ff-agent-context-create-plugin.js +4 -4
- package/dist/plugins/ff-agent-context-update-plugin.d.ts +1 -2
- package/dist/plugins/ff-agent-context-update-plugin.js +3 -3
- package/dist/plugins/ff-agents-clear-plugin.d.ts +1 -2
- package/dist/plugins/ff-agents-clear-plugin.js +10 -18
- package/dist/plugins/ff-agents-current-plugin.d.ts +1 -2
- package/dist/plugins/ff-agents-current-plugin.js +3 -3
- package/dist/plugins/ff-agents-delete-plugin.d.ts +1 -2
- package/dist/plugins/ff-agents-delete-plugin.js +8 -12
- package/dist/plugins/ff-agents-get-plugin.d.ts +1 -2
- package/dist/plugins/ff-agents-get-plugin.js +9 -13
- package/dist/plugins/ff-agents-list-plugin.d.ts +1 -2
- package/dist/plugins/ff-agents-list-plugin.js +16 -27
- package/dist/plugins/ff-agents-show-plugin.d.ts +1 -2
- package/dist/plugins/ff-agents-show-plugin.js +3 -3
- package/dist/plugins/ff-agents-update-plugin.d.ts +1 -2
- package/dist/plugins/ff-agents-update-plugin.js +7 -7
- package/dist/plugins/ff-learning-get-plugin.d.ts +1 -2
- package/dist/plugins/ff-learning-get-plugin.js +3 -3
- package/dist/plugins/ff-learning-search-plugin.d.ts +1 -2
- package/dist/plugins/ff-learning-search-plugin.js +3 -3
- package/dist/plugins/ff-learning-store-plugin.d.ts +1 -2
- package/dist/plugins/ff-learning-store-plugin.js +3 -3
- package/dist/plugins/ff-plan-create-plugin.d.ts +1 -2
- package/dist/plugins/ff-plan-create-plugin.js +3 -3
- package/dist/plugins/ff-plan-update-plugin.d.ts +1 -2
- package/dist/plugins/ff-plan-update-plugin.js +4 -4
- package/dist/plugins/ff-plans-delete-plugin.d.ts +1 -2
- package/dist/plugins/ff-plans-delete-plugin.js +8 -12
- package/dist/plugins/ff-plans-get-plugin.d.ts +1 -2
- package/dist/plugins/ff-plans-get-plugin.js +9 -13
- package/dist/plugins/ff-plans-list-plugin.d.ts +1 -2
- package/dist/plugins/ff-plans-list-plugin.js +16 -27
- package/dist/plugins/ff-plans-update-plugin.d.ts +1 -2
- package/dist/plugins/ff-plans-update-plugin.js +7 -7
- package/dist/plugins/ff-review-create-plugin.d.ts +1 -2
- package/dist/plugins/ff-review-create-plugin.js +3 -3
- package/dist/plugins/ff-reviews-delete-plugin.d.ts +1 -2
- package/dist/plugins/ff-reviews-delete-plugin.js +8 -12
- package/dist/plugins/ff-reviews-get-plugin.d.ts +1 -2
- package/dist/plugins/ff-reviews-get-plugin.js +9 -13
- package/dist/plugins/ff-reviews-list-plugin.d.ts +1 -2
- package/dist/plugins/ff-reviews-list-plugin.js +16 -27
- package/dist/plugins/ff-reviews-update-plugin.d.ts +1 -2
- package/dist/plugins/ff-reviews-update-plugin.js +7 -7
- package/dist/utils/file-utils.d.ts +1 -3
- package/dist/utils/file-utils.js +4 -5
- package/package.json +1 -1
package/dist/agent-context.d.ts
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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>;
|
package/dist/agent-context.js
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
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(
|
|
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
|
-
//
|
|
62
|
-
const
|
|
63
|
-
const
|
|
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 = `${
|
|
68
|
-
const content = await
|
|
69
|
-
return parseAgentContext(content
|
|
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(
|
|
123
|
-
const { directory, $ } = input;
|
|
124
|
+
export async function updateAgentStatus(directory, id, status) {
|
|
124
125
|
try {
|
|
125
|
-
const
|
|
126
|
-
const
|
|
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 = `${
|
|
135
|
+
const filePath = `${agentsDir}/${fileName}`;
|
|
131
136
|
// Read current content
|
|
132
|
-
const content = await
|
|
133
|
-
let text = content
|
|
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
|
|
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(
|
|
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
|
|
156
|
+
await stat(agentsDir);
|
|
153
157
|
}
|
|
154
158
|
catch {
|
|
155
159
|
return [];
|
|
156
160
|
}
|
|
157
161
|
try {
|
|
158
|
-
const
|
|
159
|
-
const files =
|
|
160
|
-
.
|
|
161
|
-
.
|
|
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
|
|
168
|
-
const context = parseAgentContext(content
|
|
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(
|
|
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
|
|
199
|
+
await stat(agentsDir);
|
|
199
200
|
}
|
|
200
201
|
catch {
|
|
201
202
|
return [];
|
|
202
203
|
}
|
|
203
204
|
try {
|
|
204
|
-
|
|
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
|
-
|
|
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
|
|
220
|
-
if (content.
|
|
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(
|
|
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
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
.
|
|
249
|
-
.
|
|
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(
|
|
260
|
-
const { directory, $ } = input;
|
|
255
|
+
export async function findAllAgentFiles(directory) {
|
|
261
256
|
const agentsDir = `${directory}/.feature-factory/agents`;
|
|
262
257
|
try {
|
|
263
|
-
const
|
|
264
|
-
return
|
|
265
|
-
.
|
|
266
|
-
.
|
|
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(
|
|
46
|
-
'ff-agents-show': createFFAgentsShowTool(
|
|
47
|
-
'ff-agents-clear': createFFAgentsClearTool(
|
|
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(
|
|
50
|
-
'ff-learning-search': createFFLearningSearchTool(
|
|
51
|
-
'ff-learning-get': createFFLearningGetTool(
|
|
49
|
+
'ff-learning-store': createFFLearningStoreTool(),
|
|
50
|
+
'ff-learning-search': createFFLearningSearchTool(),
|
|
51
|
+
'ff-learning-get': createFFLearningGetTool(),
|
|
52
52
|
// Plan tools
|
|
53
|
-
'ff-plan-create': createFFPlanCreateTool(
|
|
54
|
-
'ff-plan-update': createFFPlanUpdateTool(
|
|
53
|
+
'ff-plan-create': createFFPlanCreateTool(),
|
|
54
|
+
'ff-plan-update': createFFPlanUpdateTool(),
|
|
55
55
|
// Agent context tools
|
|
56
|
-
'ff-agent-context-create': createFFAgentContextCreateTool(
|
|
57
|
-
'ff-agent-context-update': createFFAgentContextUpdateTool(
|
|
56
|
+
'ff-agent-context-create': createFFAgentContextCreateTool(),
|
|
57
|
+
'ff-agent-context-update': createFFAgentContextUpdateTool(),
|
|
58
58
|
// Review tools
|
|
59
|
-
'ff-review-create': createFFReviewCreateTool(
|
|
59
|
+
'ff-review-create': createFFReviewCreateTool(),
|
|
60
60
|
// File management - agents
|
|
61
|
-
'ff-agents-get': createFFAgentsGetTool(
|
|
62
|
-
'ff-agents-update': createFFAgentsUpdateTool(
|
|
63
|
-
'ff-agents-delete': createFFAgentsDeleteTool(
|
|
64
|
-
'ff-agents-list': createFFAgentsListTool(
|
|
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(
|
|
67
|
-
'ff-plans-update': createFFPlansUpdateTool(
|
|
68
|
-
'ff-plans-delete': createFFPlansDeleteTool(
|
|
69
|
-
'ff-plans-list': createFFPlansListTool(
|
|
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(
|
|
72
|
-
'ff-reviews-update': createFFReviewsUpdateTool(
|
|
73
|
-
'ff-reviews-delete': createFFReviewsDeleteTool(
|
|
74
|
-
'ff-reviews-list': createFFReviewsListTool(
|
|
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(
|
|
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(
|
|
2
|
+
export async function getMemory(directory, criteria) {
|
|
3
3
|
try {
|
|
4
4
|
let filePath = null;
|
|
5
5
|
if (criteria.filePath) {
|
|
6
|
-
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(
|
|
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(`${
|
|
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(
|
|
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(
|
|
4
|
-
const memoriesDir = `${
|
|
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(
|
|
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(
|
|
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(
|
|
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 = `${
|
|
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
|
-
|
|
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(
|
|
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 = `${
|
|
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: "${
|
|
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
|
-
|
|
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(
|
|
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 = `${
|
|
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
|
-
|
|
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(
|
|
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(
|
|
15
|
+
files = await findAgentFilesById(toolCtx.directory, args.id);
|
|
17
16
|
}
|
|
18
17
|
else if (args.agent && args.sessionID) {
|
|
19
|
-
files = await findAgentFiles(
|
|
18
|
+
files = await findAgentFiles(toolCtx.directory, args.agent, args.sessionID);
|
|
20
19
|
}
|
|
21
20
|
else if (args.sessionID) {
|
|
22
|
-
files = await findAgentFiles(
|
|
21
|
+
files = await findAgentFiles(toolCtx.directory, undefined, args.sessionID);
|
|
23
22
|
}
|
|
24
23
|
else if (args.agent) {
|
|
25
|
-
files = await findAgentFiles(
|
|
24
|
+
files = await findAgentFiles(toolCtx.directory, args.agent);
|
|
26
25
|
}
|
|
27
26
|
else {
|
|
28
|
-
files = await findAllAgentFiles(
|
|
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
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
4
|
-
|
|
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
|
|
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
|
-
|
|
3
|
-
export declare function createFFAgentsGetTool(input: PluginInput): ReturnType<typeof tool>;
|
|
2
|
+
export declare function createFFAgentsGetTool(): ReturnType<typeof tool>;
|