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.
Files changed (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +229 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +24 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/installer.d.ts +4 -0
  8. package/dist/installer.d.ts.map +1 -0
  9. package/dist/installer.js +87 -0
  10. package/dist/installer.js.map +1 -0
  11. package/dist/plugin/config.d.ts +5 -0
  12. package/dist/plugin/config.d.ts.map +1 -0
  13. package/dist/plugin/config.js +50 -0
  14. package/dist/plugin/config.js.map +1 -0
  15. package/dist/plugin/coordinator.d.ts +9 -0
  16. package/dist/plugin/coordinator.d.ts.map +1 -0
  17. package/dist/plugin/coordinator.js +153 -0
  18. package/dist/plugin/coordinator.js.map +1 -0
  19. package/dist/plugin/decomposer.d.ts +11 -0
  20. package/dist/plugin/decomposer.d.ts.map +1 -0
  21. package/dist/plugin/decomposer.js +77 -0
  22. package/dist/plugin/decomposer.js.map +1 -0
  23. package/dist/plugin/file-lock.d.ts +14 -0
  24. package/dist/plugin/file-lock.d.ts.map +1 -0
  25. package/dist/plugin/file-lock.js +55 -0
  26. package/dist/plugin/file-lock.js.map +1 -0
  27. package/dist/plugin/index.d.ts +3 -0
  28. package/dist/plugin/index.d.ts.map +1 -0
  29. package/dist/plugin/index.js +138 -0
  30. package/dist/plugin/index.js.map +1 -0
  31. package/dist/plugin/state.d.ts +12 -0
  32. package/dist/plugin/state.d.ts.map +1 -0
  33. package/dist/plugin/state.js +75 -0
  34. package/dist/plugin/state.js.map +1 -0
  35. package/dist/plugin/types.d.ts +45 -0
  36. package/dist/plugin/types.d.ts.map +1 -0
  37. package/dist/plugin/types.js +5 -0
  38. package/dist/plugin/types.js.map +1 -0
  39. package/dist/plugin/worker.d.ts +3 -0
  40. package/dist/plugin/worker.d.ts.map +1 -0
  41. package/dist/plugin/worker.js +40 -0
  42. package/dist/plugin/worker.js.map +1 -0
  43. 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,3 @@
1
+ import type { Plugin } from '@opencode-ai/plugin';
2
+ export declare const SwarmControlPlugin: Plugin;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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,5 @@
1
+ import { z } from 'zod';
2
+ export const SwarmConfigSchema = z.object({
3
+ model: z.string().describe('Model to use for decomposition'),
4
+ });
5
+ //# sourceMappingURL=types.js.map
@@ -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,3 @@
1
+ import type { WorkerInfo, Subtask } from './types.js';
2
+ export declare function executeSubtask(client: any, worker: WorkerInfo, subtask: Subtask, model: string): Promise<string>;
3
+ //# sourceMappingURL=worker.d.ts.map
@@ -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
+ }