swarm-control 0.1.0
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/LICENSE +21 -0
- package/README.md +229 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +24 -0
- package/dist/cli.js.map +1 -0
- package/dist/installer.d.ts +4 -0
- package/dist/installer.d.ts.map +1 -0
- package/dist/installer.js +87 -0
- package/dist/installer.js.map +1 -0
- package/dist/plugin/config.d.ts +5 -0
- package/dist/plugin/config.d.ts.map +1 -0
- package/dist/plugin/config.js +50 -0
- package/dist/plugin/config.js.map +1 -0
- package/dist/plugin/coordinator.d.ts +9 -0
- package/dist/plugin/coordinator.d.ts.map +1 -0
- package/dist/plugin/coordinator.js +153 -0
- package/dist/plugin/coordinator.js.map +1 -0
- package/dist/plugin/decomposer.d.ts +11 -0
- package/dist/plugin/decomposer.d.ts.map +1 -0
- package/dist/plugin/decomposer.js +77 -0
- package/dist/plugin/decomposer.js.map +1 -0
- package/dist/plugin/file-lock.d.ts +14 -0
- package/dist/plugin/file-lock.d.ts.map +1 -0
- package/dist/plugin/file-lock.js +55 -0
- package/dist/plugin/file-lock.js.map +1 -0
- package/dist/plugin/index.d.ts +3 -0
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +138 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/plugin/state.d.ts +12 -0
- package/dist/plugin/state.d.ts.map +1 -0
- package/dist/plugin/state.js +75 -0
- package/dist/plugin/state.js.map +1 -0
- package/dist/plugin/types.d.ts +45 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin/types.js +5 -0
- package/dist/plugin/types.js.map +1 -0
- package/dist/plugin/worker.d.ts +3 -0
- package/dist/plugin/worker.d.ts.map +1 -0
- package/dist/plugin/worker.js +40 -0
- package/dist/plugin/worker.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const DecompositionResponseSchema = z.object({
|
|
3
|
+
analysis: z.string(),
|
|
4
|
+
numWorkers: z.number().min(1).max(4),
|
|
5
|
+
subtasks: z.array(z.object({
|
|
6
|
+
id: z.string(),
|
|
7
|
+
description: z.string(),
|
|
8
|
+
files: z.array(z.string()),
|
|
9
|
+
dependsOn: z.array(z.string()).optional()
|
|
10
|
+
}))
|
|
11
|
+
});
|
|
12
|
+
export async function decomposeTask(client, model, task, context) {
|
|
13
|
+
// Get file list from project
|
|
14
|
+
const filesResult = await client.find.files({
|
|
15
|
+
query: { type: 'file', limit: 200 }
|
|
16
|
+
});
|
|
17
|
+
const files = filesResult.data || [];
|
|
18
|
+
const fileList = files.length > 0 ? files.join('\n') : 'No files found';
|
|
19
|
+
const prompt = `You are a task decomposition system. Analyze this programming task:
|
|
20
|
+
|
|
21
|
+
TASK: ${task}
|
|
22
|
+
|
|
23
|
+
PROJECT FILES:
|
|
24
|
+
${fileList}
|
|
25
|
+
|
|
26
|
+
Your goal:
|
|
27
|
+
1. Identify which files need to be modified
|
|
28
|
+
2. Group related files into logical subtasks (maximum 4 workers)
|
|
29
|
+
3. Determine if subtasks can be executed in parallel
|
|
30
|
+
4. Identify dependencies between subtasks
|
|
31
|
+
|
|
32
|
+
RESPONSE FORMAT (JSON only):
|
|
33
|
+
{
|
|
34
|
+
"analysis": "Brief explanation of approach",
|
|
35
|
+
"numWorkers": number (1-4),
|
|
36
|
+
"subtasks": [
|
|
37
|
+
{
|
|
38
|
+
"id": "unique_id",
|
|
39
|
+
"description": "Clear description",
|
|
40
|
+
"files": ["path/to/file1.ts"],
|
|
41
|
+
"dependsOn": ["id_of_dependency"]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
IMPORTANT:
|
|
47
|
+
- Use the exact file paths from the PROJECT FILES list above
|
|
48
|
+
- Maximum 4 workers total
|
|
49
|
+
- Only include files that actually need to be modified
|
|
50
|
+
- Provide unique IDs for each subtask`;
|
|
51
|
+
try {
|
|
52
|
+
const result = await client.session.prompt({
|
|
53
|
+
path: { id: context.sessionID },
|
|
54
|
+
body: {
|
|
55
|
+
model: {
|
|
56
|
+
providerID: model.split('/')[0],
|
|
57
|
+
modelID: model.split('/')[1]
|
|
58
|
+
},
|
|
59
|
+
parts: [{ type: 'text', text: prompt }]
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
const responseText = result.parts?.find((p) => p.type === 'text')?.text || '{}';
|
|
63
|
+
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
|
|
64
|
+
const jsonStr = jsonMatch ? jsonMatch[0] : responseText;
|
|
65
|
+
return DecompositionResponseSchema.parse(JSON.parse(jsonStr));
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
await client.app.log({
|
|
69
|
+
service: 'swarm-control',
|
|
70
|
+
level: 'error',
|
|
71
|
+
message: 'Decomposition failed',
|
|
72
|
+
extra: { error: error instanceof Error ? error.message : 'Unknown error', task }
|
|
73
|
+
});
|
|
74
|
+
throw new Error(`Failed to decompose task: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=decomposer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decomposer.js","sourceRoot":"","sources":["../../src/plugin/decomposer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { FileLock } from './types.js';
|
|
2
|
+
declare class FileLockManager {
|
|
3
|
+
private locks;
|
|
4
|
+
private waitQueue;
|
|
5
|
+
acquireLock(filePath: string, workerId: string): Promise<boolean>;
|
|
6
|
+
releaseLock(filePath: string): void;
|
|
7
|
+
isLocked(filePath: string): boolean;
|
|
8
|
+
getLock(filePath: string): FileLock | undefined;
|
|
9
|
+
releaseAllLocksForWorker(workerId: string): void;
|
|
10
|
+
clearAll(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare const lockManager: FileLockManager;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=file-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.d.ts","sourceRoot":"","sources":["../../src/plugin/file-lock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE1C,cAAM,eAAe;IACnB,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,SAAS,CAA6D;IAExE,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBvE,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAmBnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAInC,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI/C,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQhD,QAAQ,IAAI,IAAI;CAIjB;AAED,eAAO,MAAM,WAAW,iBAAwB,CAAA"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
class FileLockManager {
|
|
2
|
+
locks = new Map();
|
|
3
|
+
waitQueue = new Map();
|
|
4
|
+
async acquireLock(filePath, workerId) {
|
|
5
|
+
if (!this.locks.has(filePath)) {
|
|
6
|
+
this.locks.set(filePath, {
|
|
7
|
+
filePath,
|
|
8
|
+
lockedBy: workerId,
|
|
9
|
+
lockedAt: Date.now()
|
|
10
|
+
});
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
if (!this.waitQueue.has(filePath)) {
|
|
15
|
+
this.waitQueue.set(filePath, []);
|
|
16
|
+
}
|
|
17
|
+
this.waitQueue.get(filePath).push(resolve);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
releaseLock(filePath) {
|
|
21
|
+
this.locks.delete(filePath);
|
|
22
|
+
const queue = this.waitQueue.get(filePath);
|
|
23
|
+
if (queue && queue.length > 0) {
|
|
24
|
+
const next = queue.shift();
|
|
25
|
+
this.locks.set(filePath, {
|
|
26
|
+
filePath,
|
|
27
|
+
lockedBy: 'pending',
|
|
28
|
+
lockedAt: Date.now()
|
|
29
|
+
});
|
|
30
|
+
next(true);
|
|
31
|
+
}
|
|
32
|
+
if (queue && queue.length === 0) {
|
|
33
|
+
this.waitQueue.delete(filePath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
isLocked(filePath) {
|
|
37
|
+
return this.locks.has(filePath);
|
|
38
|
+
}
|
|
39
|
+
getLock(filePath) {
|
|
40
|
+
return this.locks.get(filePath);
|
|
41
|
+
}
|
|
42
|
+
releaseAllLocksForWorker(workerId) {
|
|
43
|
+
for (const [filePath, lock] of this.locks.entries()) {
|
|
44
|
+
if (lock.lockedBy === workerId) {
|
|
45
|
+
this.releaseLock(filePath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
clearAll() {
|
|
50
|
+
this.locks.clear();
|
|
51
|
+
this.waitQueue.clear();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export const lockManager = new FileLockManager();
|
|
55
|
+
//# sourceMappingURL=file-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.js","sourceRoot":"","sources":["../../src/plugin/file-lock.ts"],"names":[],"mappings":"AAEA,MAAM,eAAe;IACX,KAAK,GAA0B,IAAI,GAAG,EAAE,CAAA;IACxC,SAAS,GAAoD,IAAI,GAAG,EAAE,CAAA;IAE9E,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,QAAgB;QAClD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACvB,QAAQ;gBACR,QAAQ,EAAE,QAAQ;gBAClB,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;aACrB,CAAC,CAAA;YACF,OAAO,IAAI,CAAA;QACb,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;YAClC,CAAC;YACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,WAAW,CAAC,QAAgB;QAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QAE3B,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAC1C,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAG,CAAA;YAC3B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACvB,QAAQ;gBACR,QAAQ,EAAE,SAAS;gBACnB,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;aACrB,CAAC,CAAA;YACF,IAAI,CAAC,IAAI,CAAC,CAAA;QACZ,CAAC;QAED,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACjC,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,QAAgB;QACvB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAED,OAAO,CAAC,QAAgB;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACjC,CAAC;IAED,wBAAwB,CAAC,QAAgB;QACvC,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YACpD,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC/B,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAED,QAAQ;QACN,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;QAClB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AASjD,eAAO,MAAM,kBAAkB,EAAE,MAkKhC,CAAA"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { tool } from '@opencode-ai/plugin/tool';
|
|
2
|
+
import { getConfig, setConfig } from './config.js';
|
|
3
|
+
import { decomposeTask } from './decomposer.js';
|
|
4
|
+
import { createSwarmCoordinator } from './coordinator.js';
|
|
5
|
+
import { StateManager } from './state.js';
|
|
6
|
+
import { lockManager } from './file-lock.js';
|
|
7
|
+
export const SwarmControlPlugin = async ({ client, directory }) => {
|
|
8
|
+
const state = new StateManager();
|
|
9
|
+
return {
|
|
10
|
+
tool: {
|
|
11
|
+
swarm_model: tool({
|
|
12
|
+
description: 'Configure model to use for swarm task decomposition (required before using swarm_spawn)',
|
|
13
|
+
args: {
|
|
14
|
+
model: tool.schema.string().describe('Model identifier (e.g., anthropic/claude-3-5-sonnet-20241022)')
|
|
15
|
+
},
|
|
16
|
+
async execute({ model }) {
|
|
17
|
+
await setConfig({ model });
|
|
18
|
+
return `Swarm model set to: ${model}`;
|
|
19
|
+
}
|
|
20
|
+
}),
|
|
21
|
+
swarm_spawn: tool({
|
|
22
|
+
description: 'Spawn a swarm of subagents to tackle a complex programming task',
|
|
23
|
+
args: {
|
|
24
|
+
task: tool.schema.string().describe('The task description to decompose and execute'),
|
|
25
|
+
maxWorkers: tool.schema.number().min(1).max(4).optional().describe('Maximum number of workers (default: 4)')
|
|
26
|
+
},
|
|
27
|
+
async execute({ task, maxWorkers = 4 }, context) {
|
|
28
|
+
// Check if model is configured
|
|
29
|
+
const config = await getConfig();
|
|
30
|
+
if (!config) {
|
|
31
|
+
throw new Error('Swarm model not configured. Please run /swarm_model <model> first to set the model for task decomposition.');
|
|
32
|
+
}
|
|
33
|
+
// Check if there's already a running task
|
|
34
|
+
const currentTask = await state.getCurrentTask();
|
|
35
|
+
if (currentTask && currentTask.status === 'in_progress') {
|
|
36
|
+
throw new Error(`A swarm task is already in progress. Task ID: ${currentTask.id}. Use /swarm_status to check progress or wait for it to complete.`);
|
|
37
|
+
}
|
|
38
|
+
// Clear any stale locks
|
|
39
|
+
lockManager.clearAll();
|
|
40
|
+
let decompositionResult;
|
|
41
|
+
try {
|
|
42
|
+
// Decompose task
|
|
43
|
+
decompositionResult = await decomposeTask(client, config.model, task, context);
|
|
44
|
+
// Validate numWorkers doesn't exceed maxWorkers
|
|
45
|
+
const numWorkers = Math.min(decompositionResult.numWorkers, maxWorkers);
|
|
46
|
+
// Create and run coordinator
|
|
47
|
+
const coordinator = createSwarmCoordinator(client, directory, config);
|
|
48
|
+
const result = await coordinator.execute(task, {
|
|
49
|
+
...decompositionResult,
|
|
50
|
+
numWorkers
|
|
51
|
+
}, numWorkers);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
// Clean up on error
|
|
56
|
+
lockManager.clearAll();
|
|
57
|
+
await state.clearTask();
|
|
58
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
59
|
+
throw new Error(`Swarm execution failed: ${errorMsg}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}),
|
|
63
|
+
swarm_status: tool({
|
|
64
|
+
description: 'Show status of current or recent swarm tasks',
|
|
65
|
+
args: {
|
|
66
|
+
taskId: tool.schema.string().optional().describe('Specific task ID to check (if omitted, shows current task)')
|
|
67
|
+
},
|
|
68
|
+
async execute({ taskId }) {
|
|
69
|
+
if (taskId) {
|
|
70
|
+
// For specific task ID, we'd need to implement task history
|
|
71
|
+
return `Task history not yet implemented. Use without arguments to check current task status.`;
|
|
72
|
+
}
|
|
73
|
+
const currentTask = await state.getCurrentTask();
|
|
74
|
+
if (!currentTask) {
|
|
75
|
+
return 'No active swarm task. Use /swarm_spawn to start a new task.';
|
|
76
|
+
}
|
|
77
|
+
let status = `## Swarm Task Status\n\n`;
|
|
78
|
+
status += `**Task ID:** ${currentTask.id}\n`;
|
|
79
|
+
status += `**Description:** ${currentTask.description}\n`;
|
|
80
|
+
status += `**Status:** ${currentTask.status.toUpperCase()}\n`;
|
|
81
|
+
if (currentTask.completedAt) {
|
|
82
|
+
const duration = Math.round((currentTask.completedAt - currentTask.createdAt) / 1000);
|
|
83
|
+
status += `**Duration:** ${duration}s\n`;
|
|
84
|
+
}
|
|
85
|
+
status += `\n**Subtasks:**\n\n`;
|
|
86
|
+
const completed = currentTask.subtasks.filter((s) => s.status === 'completed').length;
|
|
87
|
+
const failed = currentTask.subtasks.filter((s) => s.status === 'failed').length;
|
|
88
|
+
const inProgress = currentTask.subtasks.filter((s) => s.status === 'in_progress').length;
|
|
89
|
+
status += `- Total: ${currentTask.subtasks.length}\n`;
|
|
90
|
+
status += `- ✅ Completed: ${completed}\n`;
|
|
91
|
+
if (inProgress > 0) {
|
|
92
|
+
status += `- ⏳ In Progress: ${inProgress}\n`;
|
|
93
|
+
}
|
|
94
|
+
if (failed > 0) {
|
|
95
|
+
status += `- ❌ Failed: ${failed}\n`;
|
|
96
|
+
}
|
|
97
|
+
status += `\n**Details:**\n\n`;
|
|
98
|
+
for (const subtask of currentTask.subtasks) {
|
|
99
|
+
const statusEmoji = subtask.status === 'completed' ? '✅' :
|
|
100
|
+
subtask.status === 'failed' ? '❌' :
|
|
101
|
+
subtask.status === 'in_progress' ? '⏳' : '⏸️';
|
|
102
|
+
status += `${statusEmoji} **${subtask.description}**\n`;
|
|
103
|
+
if (subtask.files && subtask.files.length > 0) {
|
|
104
|
+
status += ` Files: ${subtask.files.join(', ')}\n`;
|
|
105
|
+
}
|
|
106
|
+
if (subtask.workerId) {
|
|
107
|
+
status += ` Worker: ${subtask.workerId}\n`;
|
|
108
|
+
}
|
|
109
|
+
if (subtask.result) {
|
|
110
|
+
status += ` Result: ${subtask.result}\n`;
|
|
111
|
+
}
|
|
112
|
+
if (subtask.error) {
|
|
113
|
+
status += ` Error: ${subtask.error}\n`;
|
|
114
|
+
}
|
|
115
|
+
status += '\n';
|
|
116
|
+
}
|
|
117
|
+
// Show worker status
|
|
118
|
+
const workers = await state.getWorkers();
|
|
119
|
+
if (workers.length > 0) {
|
|
120
|
+
status += `**Workers:**\n\n`;
|
|
121
|
+
for (const worker of workers) {
|
|
122
|
+
const statusEmoji = worker.status === 'idle' ? '💤' :
|
|
123
|
+
worker.status === 'working' ? '🔨' :
|
|
124
|
+
worker.status === 'waiting_for_lock' ? '⏳' : '❌';
|
|
125
|
+
status += `${statusEmoji} **${worker.id}** (${worker.status})`;
|
|
126
|
+
if (worker.currentSubtaskId) {
|
|
127
|
+
status += ` - Working on: ${worker.currentSubtaskId}`;
|
|
128
|
+
}
|
|
129
|
+
status += '\n';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return status.trim();
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SwarmState, SwarmTask, WorkerInfo } from './types.js';
|
|
2
|
+
export declare class StateManager {
|
|
3
|
+
getState(): Promise<SwarmState>;
|
|
4
|
+
setState(state: SwarmState): Promise<void>;
|
|
5
|
+
getCurrentTask(): Promise<SwarmTask | null>;
|
|
6
|
+
setCurrentTask(task: SwarmTask | null): Promise<void>;
|
|
7
|
+
updateSubtaskStatus(taskId: string, subtaskId: string, status: 'pending' | 'in_progress' | 'completed' | 'failed', result?: string, error?: string): Promise<void>;
|
|
8
|
+
getWorkers(): Promise<WorkerInfo[]>;
|
|
9
|
+
updateWorker(worker: WorkerInfo): Promise<void>;
|
|
10
|
+
clearTask(): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/plugin/state.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAKnE,qBAAa,YAAY;IACjB,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC;IAkB/B,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1C,cAAc,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAK3C,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrD,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAalK,UAAU,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAKnC,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/C,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAMjC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
const STATE_DIR = path.join(process.env.HOME, '.config/swarm-control');
|
|
4
|
+
const STATE_FILE = path.join(STATE_DIR, 'state.json');
|
|
5
|
+
export class StateManager {
|
|
6
|
+
async getState() {
|
|
7
|
+
try {
|
|
8
|
+
const data = await fs.readFile(STATE_FILE, 'utf-8');
|
|
9
|
+
const parsed = JSON.parse(data);
|
|
10
|
+
return {
|
|
11
|
+
currentTask: parsed.currentTask,
|
|
12
|
+
workers: parsed.workers || [],
|
|
13
|
+
fileLocks: parsed.fileLocks || []
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return {
|
|
18
|
+
currentTask: null,
|
|
19
|
+
workers: [],
|
|
20
|
+
fileLocks: []
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async setState(state) {
|
|
25
|
+
await fs.ensureDir(STATE_DIR);
|
|
26
|
+
const tempFile = `${STATE_FILE}.tmp`;
|
|
27
|
+
await fs.writeJSON(tempFile, state, { spaces: 2 });
|
|
28
|
+
await fs.move(tempFile, STATE_FILE, { overwrite: true });
|
|
29
|
+
}
|
|
30
|
+
async getCurrentTask() {
|
|
31
|
+
const state = await this.getState();
|
|
32
|
+
return state.currentTask;
|
|
33
|
+
}
|
|
34
|
+
async setCurrentTask(task) {
|
|
35
|
+
const state = await this.getState();
|
|
36
|
+
state.currentTask = task;
|
|
37
|
+
await this.setState(state);
|
|
38
|
+
}
|
|
39
|
+
async updateSubtaskStatus(taskId, subtaskId, status, result, error) {
|
|
40
|
+
const state = await this.getState();
|
|
41
|
+
if (!state.currentTask || state.currentTask.id !== taskId)
|
|
42
|
+
return;
|
|
43
|
+
const subtask = state.currentTask.subtasks.find(s => s.id === subtaskId);
|
|
44
|
+
if (subtask) {
|
|
45
|
+
subtask.status = status;
|
|
46
|
+
if (result)
|
|
47
|
+
subtask.result = result;
|
|
48
|
+
if (error)
|
|
49
|
+
subtask.error = error;
|
|
50
|
+
await this.setState(state);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async getWorkers() {
|
|
54
|
+
const state = await this.getState();
|
|
55
|
+
return state.workers;
|
|
56
|
+
}
|
|
57
|
+
async updateWorker(worker) {
|
|
58
|
+
const state = await this.getState();
|
|
59
|
+
const index = state.workers.findIndex((w) => w.id === worker.id);
|
|
60
|
+
if (index >= 0) {
|
|
61
|
+
state.workers[index] = worker;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
state.workers.push(worker);
|
|
65
|
+
}
|
|
66
|
+
await this.setState(state);
|
|
67
|
+
}
|
|
68
|
+
async clearTask() {
|
|
69
|
+
const state = await this.getState();
|
|
70
|
+
state.currentTask = null;
|
|
71
|
+
state.workers = [];
|
|
72
|
+
await this.setState(state);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/plugin/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const SwarmConfigSchema: z.ZodObject<{
|
|
3
|
+
model: z.ZodString;
|
|
4
|
+
}, "strip", z.ZodTypeAny, {
|
|
5
|
+
model: string;
|
|
6
|
+
}, {
|
|
7
|
+
model: string;
|
|
8
|
+
}>;
|
|
9
|
+
export type SwarmConfig = z.infer<typeof SwarmConfigSchema>;
|
|
10
|
+
export interface SwarmTask {
|
|
11
|
+
id: string;
|
|
12
|
+
description: string;
|
|
13
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
14
|
+
subtasks: Subtask[];
|
|
15
|
+
createdAt: number;
|
|
16
|
+
completedAt?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface Subtask {
|
|
19
|
+
id: string;
|
|
20
|
+
description: string;
|
|
21
|
+
files: string[];
|
|
22
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
23
|
+
workerId?: string;
|
|
24
|
+
sessionId?: string;
|
|
25
|
+
dependsOn?: string[];
|
|
26
|
+
result?: string;
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface FileLock {
|
|
30
|
+
filePath: string;
|
|
31
|
+
lockedBy: string;
|
|
32
|
+
lockedAt: number;
|
|
33
|
+
}
|
|
34
|
+
export interface SwarmState {
|
|
35
|
+
currentTask: SwarmTask | null;
|
|
36
|
+
workers: WorkerInfo[];
|
|
37
|
+
fileLocks: FileLock[];
|
|
38
|
+
}
|
|
39
|
+
export interface WorkerInfo {
|
|
40
|
+
id: string;
|
|
41
|
+
sessionId: string;
|
|
42
|
+
status: 'idle' | 'working' | 'waiting_for_lock' | 'error';
|
|
43
|
+
currentSubtaskId?: string;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,iBAAiB;;;;;;EAE5B,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA;AAE3D,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAA;IAC1D,QAAQ,EAAE,OAAO,EAAE,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAA;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,SAAS,GAAG,IAAI,CAAA;IAC7B,OAAO,EAAE,UAAU,EAAE,CAAA;IACrB,SAAS,EAAE,QAAQ,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,kBAAkB,GAAG,OAAO,CAAA;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugin/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;CAC7D,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/plugin/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAErD,wBAAsB,cAAc,CAClC,MAAM,EAAE,GAAG,EACX,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CA0CjB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export async function executeSubtask(client, worker, subtask, model) {
|
|
2
|
+
const prompt = `You are a specialized worker agent. Execute this specific task:
|
|
3
|
+
|
|
4
|
+
${subtask.description}
|
|
5
|
+
|
|
6
|
+
Files to modify:
|
|
7
|
+
${subtask.files.map((f) => `- ${f}`).join('\n')}
|
|
8
|
+
|
|
9
|
+
Instructions:
|
|
10
|
+
1. Work on the specified files
|
|
11
|
+
2. Complete the task described above
|
|
12
|
+
3. Return a summary of changes made
|
|
13
|
+
4. If you encounter any errors, describe them clearly
|
|
14
|
+
|
|
15
|
+
IMPORTANT:
|
|
16
|
+
- Only modify the files listed above
|
|
17
|
+
- Be specific about what changes you made
|
|
18
|
+
- If a file doesn't exist, mention it in your response`;
|
|
19
|
+
try {
|
|
20
|
+
const result = await client.session.prompt({
|
|
21
|
+
path: { id: worker.sessionId },
|
|
22
|
+
body: {
|
|
23
|
+
model: {
|
|
24
|
+
providerID: model.split('/')[0],
|
|
25
|
+
modelID: model.split('/')[1]
|
|
26
|
+
},
|
|
27
|
+
parts: [{ type: 'text', text: prompt }]
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const responseText = result.parts?.find((p) => p.type === 'text')?.text || '';
|
|
31
|
+
// Extract a concise summary
|
|
32
|
+
const lines = responseText.split('\n').filter((l) => l.trim());
|
|
33
|
+
const summary = lines.slice(0, 5).join(' ');
|
|
34
|
+
return summary || 'Task completed';
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw new Error(`Worker execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/plugin/worker.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAW,EACX,MAAkB,EAClB,OAAgB,EAChB,KAAa;IAEX,MAAM,MAAM,GAAG;;EAEjB,OAAO,CAAC,WAAW;;;EAGnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;uDAWA,CAAA;IAErD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YACzC,IAAI,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,SAAS,EAAE;YAC9B,IAAI,EAAE;gBACJ,KAAK,EAAE;oBACL,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC/B,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;iBAC7B;gBACD,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;aACxC;SACF,CAAC,CAAA;QAEF,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,EAAE,IAAI,IAAI,EAAE,CAAA;QAElF,4BAA4B;QAC5B,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QACtE,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAE3C,OAAO,OAAO,IAAI,gBAAgB,CAAA;IAEpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAA;IACzG,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "swarm-control",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "OpenCode plugin for multi-agent swarm coordination",
|
|
6
|
+
"main": "dist/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"swarm-control": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/",
|
|
12
|
+
"templates/",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"prepare": "npm run build",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"publish": "./publish.sh"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@opencode-ai/plugin": "^1.1.7",
|
|
25
|
+
"@opencode-ai/sdk": "^1.1.7",
|
|
26
|
+
"commander": "^11.0.0",
|
|
27
|
+
"chalk": "^5.3.0",
|
|
28
|
+
"ora": "^7.0.0",
|
|
29
|
+
"fs-extra": "^11.0.0",
|
|
30
|
+
"zod": "^3.22.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/fs-extra": "^11.0.0",
|
|
34
|
+
"@types/node": "^20.0.0",
|
|
35
|
+
"typescript": "^5.0.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"opencode-ai": ">=1.1.7"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"opencode",
|
|
45
|
+
"plugin",
|
|
46
|
+
"swarm",
|
|
47
|
+
"multi-agent",
|
|
48
|
+
"ai"
|
|
49
|
+
],
|
|
50
|
+
"author": "",
|
|
51
|
+
"license": "ISC",
|
|
52
|
+
"packageManager": "pnpm@10.24.0"
|
|
53
|
+
}
|