@stan-chen/simple-cli 0.2.1

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 (87) hide show
  1. package/README.md +287 -0
  2. package/dist/cli.d.ts +6 -0
  3. package/dist/cli.js +259 -0
  4. package/dist/commands/add.d.ts +9 -0
  5. package/dist/commands/add.js +50 -0
  6. package/dist/commands/git/commit.d.ts +12 -0
  7. package/dist/commands/git/commit.js +97 -0
  8. package/dist/commands/git/status.d.ts +6 -0
  9. package/dist/commands/git/status.js +42 -0
  10. package/dist/commands/index.d.ts +16 -0
  11. package/dist/commands/index.js +376 -0
  12. package/dist/commands/mcp/status.d.ts +6 -0
  13. package/dist/commands/mcp/status.js +31 -0
  14. package/dist/commands/swarm.d.ts +36 -0
  15. package/dist/commands/swarm.js +236 -0
  16. package/dist/commands.d.ts +32 -0
  17. package/dist/commands.js +427 -0
  18. package/dist/context.d.ts +116 -0
  19. package/dist/context.js +327 -0
  20. package/dist/index.d.ts +6 -0
  21. package/dist/index.js +109 -0
  22. package/dist/lib/agent.d.ts +98 -0
  23. package/dist/lib/agent.js +281 -0
  24. package/dist/lib/editor.d.ts +74 -0
  25. package/dist/lib/editor.js +441 -0
  26. package/dist/lib/git.d.ts +164 -0
  27. package/dist/lib/git.js +351 -0
  28. package/dist/lib/ui.d.ts +159 -0
  29. package/dist/lib/ui.js +252 -0
  30. package/dist/mcp/client.d.ts +22 -0
  31. package/dist/mcp/client.js +81 -0
  32. package/dist/mcp/manager.d.ts +186 -0
  33. package/dist/mcp/manager.js +442 -0
  34. package/dist/prompts/provider.d.ts +22 -0
  35. package/dist/prompts/provider.js +78 -0
  36. package/dist/providers/index.d.ts +15 -0
  37. package/dist/providers/index.js +82 -0
  38. package/dist/providers/multi.d.ts +11 -0
  39. package/dist/providers/multi.js +28 -0
  40. package/dist/registry.d.ts +24 -0
  41. package/dist/registry.js +379 -0
  42. package/dist/repoMap.d.ts +5 -0
  43. package/dist/repoMap.js +79 -0
  44. package/dist/router.d.ts +41 -0
  45. package/dist/router.js +108 -0
  46. package/dist/skills.d.ts +25 -0
  47. package/dist/skills.js +288 -0
  48. package/dist/swarm/coordinator.d.ts +86 -0
  49. package/dist/swarm/coordinator.js +257 -0
  50. package/dist/swarm/index.d.ts +28 -0
  51. package/dist/swarm/index.js +29 -0
  52. package/dist/swarm/task.d.ts +104 -0
  53. package/dist/swarm/task.js +221 -0
  54. package/dist/swarm/types.d.ts +132 -0
  55. package/dist/swarm/types.js +37 -0
  56. package/dist/swarm/worker.d.ts +107 -0
  57. package/dist/swarm/worker.js +299 -0
  58. package/dist/tools/analyzeFile.d.ts +16 -0
  59. package/dist/tools/analyzeFile.js +43 -0
  60. package/dist/tools/git.d.ts +40 -0
  61. package/dist/tools/git.js +236 -0
  62. package/dist/tools/glob.d.ts +34 -0
  63. package/dist/tools/glob.js +165 -0
  64. package/dist/tools/grep.d.ts +53 -0
  65. package/dist/tools/grep.js +296 -0
  66. package/dist/tools/linter.d.ts +35 -0
  67. package/dist/tools/linter.js +349 -0
  68. package/dist/tools/listDir.d.ts +29 -0
  69. package/dist/tools/listDir.js +50 -0
  70. package/dist/tools/memory.d.ts +34 -0
  71. package/dist/tools/memory.js +215 -0
  72. package/dist/tools/readFiles.d.ts +25 -0
  73. package/dist/tools/readFiles.js +31 -0
  74. package/dist/tools/reloadTools.d.ts +11 -0
  75. package/dist/tools/reloadTools.js +22 -0
  76. package/dist/tools/runCommand.d.ts +32 -0
  77. package/dist/tools/runCommand.js +79 -0
  78. package/dist/tools/scraper.d.ts +31 -0
  79. package/dist/tools/scraper.js +211 -0
  80. package/dist/tools/writeFiles.d.ts +63 -0
  81. package/dist/tools/writeFiles.js +87 -0
  82. package/dist/ui/server.d.ts +5 -0
  83. package/dist/ui/server.js +74 -0
  84. package/dist/watcher.d.ts +35 -0
  85. package/dist/watcher.js +164 -0
  86. package/docs/assets/logo.jpeg +0 -0
  87. package/package.json +78 -0
package/dist/skills.js ADDED
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Skills/Presets System
3
+ * Based on OpenHands skills and Aider prompts
4
+ * Provides specialized behavior presets for different tasks
5
+ */
6
+ import { readFile, writeFile, readdir } from 'fs/promises';
7
+ import { existsSync } from 'fs';
8
+ import { join } from 'path';
9
+ // Built-in skills
10
+ export const builtinSkills = {
11
+ // Code editing skill (default)
12
+ code: {
13
+ name: 'code',
14
+ description: 'General coding assistant with file editing and custom skill creation capabilities',
15
+ systemPrompt: `You are a coding assistant. You help users write, modify, and debug code.
16
+
17
+ ## Custom Skills (Self-Evolution)
18
+ You can create your own specialized tools in \`skills/\`, \`scripts/\`, or \`tools/\`:
19
+ 1. **TypeScript/JS**: Standard native exports.
20
+ 2. **Scripts & Binaries**:
21
+ - Write any script (Python, Bash, PowerShell, etc.) or binary.
22
+ - **Documentation**: Provide a matching \`.md\` or \`.txt\` file (e.g., \`tool.py\` + \`tool.md\`).
23
+ - **Internal Documentation**: Alternatively, put Markdown in a comment block at the very top of your script.
24
+
25
+ 3. **AI Attribution**: All self-created tools MUST include a marker as the first line:
26
+ - **Scripts**: A comment e.g. \`# [Simple-CLI AI-Created]\` or \`// [Simple-CLI AI-Created]\`.
27
+ - **Documentation**: A hidden comment e.g. \`<!-- [Simple-CLI AI-Created] -->\`.
28
+
29
+ **Markdown Specification Example**:
30
+ \`\`\`markdown
31
+ <!-- [Simple-CLI AI-Created] -->
32
+ # toolName
33
+ Brief description.
34
+
35
+ ## Command
36
+ python scripts/tool.py
37
+ \`\`\`
38
+ Inputs are passed via **stdin** (JSON) and the \`TOOL_INPUT\` env var.
39
+ After creating/modifying, call \`reloadTools\`.
40
+
41
+ 4. **Self-Orchestration**: If a project lacks clear success criteria (missing \`.agent/\` or \`.simple/\` directories), you should take the initiative to create them. Use these folders to store implementation plans, SPEC/PRDs, and validation tests.
42
+
43
+ When making changes to files:
44
+ 1. Read the file first to understand the context
45
+ 2. Make precise, targeted changes using search/replace
46
+ 3. Verify changes don't break existing functionality
47
+ 4. Follow the existing code style`,
48
+ tools: ['readFiles', 'writeFiles', 'runCommand', 'glob', 'grep', 'lint', 'reloadTools'],
49
+ },
50
+ // Architect skill for planning
51
+ architect: {
52
+ name: 'architect',
53
+ description: 'Design and planning mode - focuses on architecture decisions',
54
+ systemPrompt: `You are a software architect assistant. Your role is to:
55
+
56
+ 1. Help design system architecture
57
+ 2. Make technology decisions
58
+ 3. Plan implementation strategies
59
+ 4. Review and improve existing designs
60
+
61
+ When working on architecture:
62
+ - Ask clarifying questions about requirements
63
+ - Consider scalability, maintainability, and security
64
+ - Provide multiple options when appropriate
65
+ - Document decisions and trade-offs
66
+
67
+ Focus on high-level design rather than implementation details.
68
+ Generate diagrams and documentation when helpful.`,
69
+ tools: ['readFiles', 'glob', 'grep', 'memory'],
70
+ modelPreference: 'orchestrator',
71
+ },
72
+ // Ask skill for questions only
73
+ ask: {
74
+ name: 'ask',
75
+ description: 'Question-answering mode - no file modifications',
76
+ systemPrompt: `You are a helpful coding assistant in read-only mode.
77
+
78
+ You can:
79
+ - Answer questions about the codebase
80
+ - Explain how code works
81
+ - Suggest improvements
82
+ - Help with debugging
83
+
84
+ You should NOT:
85
+ - Modify any files
86
+ - Run commands that change state
87
+ - Create new files
88
+
89
+ Always read files before answering questions about them.`,
90
+ tools: ['readFiles', 'glob', 'grep'],
91
+ },
92
+ // Help/docs skill
93
+ help: {
94
+ name: 'help',
95
+ description: 'Help and documentation assistant',
96
+ systemPrompt: `You are a documentation assistant. Help users understand:
97
+
98
+ - How to use this CLI tool
99
+ - Programming concepts and patterns
100
+ - Best practices and conventions
101
+ - Error messages and debugging
102
+
103
+ Be concise and provide examples when helpful.
104
+ Reference official documentation when available.`,
105
+ tools: ['readFiles', 'scrapeUrl'],
106
+ },
107
+ // Test skill
108
+ test: {
109
+ name: 'test',
110
+ description: 'Test writing and debugging assistant',
111
+ systemPrompt: `You are a test engineering assistant. Your focus is:
112
+
113
+ 1. Writing comprehensive tests
114
+ 2. Debugging failing tests
115
+ 3. Improving test coverage
116
+ 4. Setting up test infrastructure
117
+
118
+ Test guidelines:
119
+ - Follow the project's existing test patterns
120
+ - Cover edge cases and error conditions
121
+ - Write clear test descriptions
122
+ - Use appropriate mocking when needed
123
+
124
+ After writing tests, run them to verify they pass.`,
125
+ tools: ['readFiles', 'writeFiles', 'runCommand', 'glob', 'grep', 'lint'],
126
+ },
127
+ // Debug skill
128
+ debug: {
129
+ name: 'debug',
130
+ description: 'Debugging assistant for troubleshooting issues',
131
+ systemPrompt: `You are a debugging assistant. Your process:
132
+
133
+ 1. Understand the error or unexpected behavior
134
+ 2. Reproduce the issue if possible
135
+ 3. Analyze logs, stack traces, and code
136
+ 4. Form hypotheses about the cause
137
+ 5. Test fixes incrementally
138
+
139
+ Debugging tips:
140
+ - Add logging to understand program flow
141
+ - Check recent changes that might have caused the issue
142
+ - Look for common patterns (null checks, async issues, etc.)
143
+ - Use the linter to catch syntax errors`,
144
+ tools: ['readFiles', 'writeFiles', 'runCommand', 'grep', 'lint', 'git'],
145
+ },
146
+ // Refactor skill
147
+ refactor: {
148
+ name: 'refactor',
149
+ description: 'Code refactoring with safety focus',
150
+ systemPrompt: `You are a refactoring assistant. Your approach:
151
+
152
+ 1. Understand the current implementation
153
+ 2. Identify areas for improvement
154
+ 3. Make incremental, safe changes
155
+ 4. Verify behavior is preserved
156
+
157
+ Refactoring principles:
158
+ - Small, focused changes
159
+ - Maintain existing tests
160
+ - Improve readability and maintainability
161
+ - Reduce duplication
162
+ - Follow SOLID principles
163
+
164
+ Always run tests after refactoring to ensure nothing broke.`,
165
+ tools: ['readFiles', 'writeFiles', 'runCommand', 'glob', 'grep', 'lint', 'git'],
166
+ },
167
+ // Review skill
168
+ review: {
169
+ name: 'review',
170
+ description: 'Code review assistant',
171
+ systemPrompt: `You are a code reviewer. Review code for:
172
+
173
+ 1. Correctness - Does it work as intended?
174
+ 2. Security - Are there vulnerabilities?
175
+ 3. Performance - Are there inefficiencies?
176
+ 4. Style - Does it follow conventions?
177
+ 5. Maintainability - Is it easy to understand?
178
+
179
+ Provide constructive feedback with specific suggestions.
180
+ Prioritize critical issues over minor style concerns.`,
181
+ tools: ['readFiles', 'glob', 'grep', 'git', 'lint'],
182
+ },
183
+ // Shell skill
184
+ shell: {
185
+ name: 'shell',
186
+ description: 'Shell/command-line assistant',
187
+ systemPrompt: `You are a shell/command-line assistant. Help with:
188
+
189
+ - Writing shell scripts
190
+ - Running and debugging commands
191
+ - System administration tasks
192
+ - Build and deployment scripts
193
+
194
+ Safety guidelines:
195
+ - Explain what commands do before running
196
+ - Use safe defaults (no force flags unless needed)
197
+ - Be careful with destructive operations
198
+ - Test commands before applying to production`,
199
+ tools: ['runCommand', 'readFiles', 'writeFiles', 'glob'],
200
+ },
201
+ // Git skill
202
+ git: {
203
+ name: 'git',
204
+ description: 'Git version control assistant',
205
+ systemPrompt: `You are a Git assistant. Help with:
206
+
207
+ - Understanding git history and changes
208
+ - Creating meaningful commits
209
+ - Managing branches
210
+ - Resolving merge conflicts
211
+ - Best practices for version control
212
+
213
+ Git guidelines:
214
+ - Write clear, descriptive commit messages
215
+ - Make small, focused commits
216
+ - Keep branches up to date
217
+ - Review changes before committing`,
218
+ tools: ['git', 'readFiles', 'glob', 'grep'],
219
+ },
220
+ };
221
+ // Get active skill from environment or default
222
+ export function getActiveSkill() {
223
+ const skillName = process.env.SIMPLE_CLI_SKILL || 'code';
224
+ return builtinSkills[skillName] || builtinSkills.code;
225
+ }
226
+ // Set active skill
227
+ export function setActiveSkill(name) {
228
+ if (builtinSkills[name]) {
229
+ process.env.SIMPLE_CLI_SKILL = name;
230
+ return builtinSkills[name];
231
+ }
232
+ return undefined;
233
+ }
234
+ // List available skills
235
+ export function listSkills() {
236
+ return Object.values(builtinSkills);
237
+ }
238
+ // Load custom skill from file
239
+ export async function loadSkillFromFile(path) {
240
+ try {
241
+ const content = await readFile(path, 'utf-8');
242
+ const skill = JSON.parse(content);
243
+ if (!skill.name || !skill.systemPrompt) {
244
+ return null;
245
+ }
246
+ return skill;
247
+ }
248
+ catch {
249
+ return null;
250
+ }
251
+ }
252
+ // Save custom skill to file
253
+ export async function saveSkillToFile(skill, path) {
254
+ await writeFile(path, JSON.stringify(skill, null, 2));
255
+ }
256
+ // Load all custom skills from a directory
257
+ export async function loadCustomSkills(dir) {
258
+ const skills = {};
259
+ if (!existsSync(dir)) {
260
+ return skills;
261
+ }
262
+ try {
263
+ const files = await readdir(dir);
264
+ for (const file of files) {
265
+ if (file.endsWith('.json')) {
266
+ const skill = await loadSkillFromFile(join(dir, file));
267
+ if (skill) {
268
+ skills[skill.name] = skill;
269
+ }
270
+ }
271
+ }
272
+ }
273
+ catch {
274
+ // Ignore errors
275
+ }
276
+ return skills;
277
+ }
278
+ // Get skill system prompt with context
279
+ export function buildSkillPrompt(skill, context) {
280
+ let prompt = skill.systemPrompt;
281
+ if (context?.files?.length) {
282
+ prompt += `\n\n## Active Files\nYou are working with these files:\n${context.files.join('\n')}`;
283
+ }
284
+ if (context?.repoMap) {
285
+ prompt += `\n\n## Repository Structure\n${context.repoMap}`;
286
+ }
287
+ return prompt;
288
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Swarm Coordinator - Orchestrates multiple workers executing tasks
3
+ */
4
+ import { EventEmitter } from 'events';
5
+ import type { SwarmTask, CoordinatorOptions, SwarmResult, SwarmEventMap } from './types.js';
6
+ export declare class SwarmCoordinator extends EventEmitter {
7
+ private options;
8
+ private taskQueue;
9
+ private workerPool;
10
+ private retryPolicy;
11
+ private running;
12
+ private startTime;
13
+ private aborted;
14
+ constructor(options?: CoordinatorOptions);
15
+ /**
16
+ * Add a single task
17
+ */
18
+ addTask(task: SwarmTask): void;
19
+ /**
20
+ * Add multiple tasks
21
+ */
22
+ addTasks(tasks: SwarmTask[]): void;
23
+ /**
24
+ * Get next task from queue
25
+ */
26
+ getTask(): SwarmTask | null;
27
+ /**
28
+ * Peek at next task
29
+ */
30
+ peekTask(): SwarmTask | null;
31
+ /**
32
+ * Get all workers status
33
+ */
34
+ getAllWorkers(): import("./types.js").WorkerStatus[];
35
+ /**
36
+ * Get worker status by ID
37
+ */
38
+ getWorkerStatus(id: string): import("./types.js").WorkerStatus | undefined;
39
+ /**
40
+ * Stop the swarm gracefully
41
+ */
42
+ stop(): void;
43
+ /**
44
+ * Abort immediately
45
+ */
46
+ abort(): void;
47
+ /**
48
+ * Run the swarm
49
+ */
50
+ run(concurrency?: number): Promise<SwarmResult>;
51
+ /**
52
+ * Main processing loop
53
+ */
54
+ private processLoop;
55
+ /**
56
+ * Execute a single task on a worker
57
+ */
58
+ private executeTask;
59
+ /**
60
+ * Sleep helper
61
+ */
62
+ private sleep;
63
+ /**
64
+ * Get queue statistics
65
+ */
66
+ getStats(): {
67
+ total: number;
68
+ pending: number;
69
+ running: number;
70
+ completed: number;
71
+ failed: number;
72
+ };
73
+ /**
74
+ * Check if swarm is running
75
+ */
76
+ isRunning(): boolean;
77
+ /**
78
+ * Type-safe event emitter methods
79
+ */
80
+ on<K extends keyof SwarmEventMap>(event: K, listener: SwarmEventMap[K]): this;
81
+ emit<K extends keyof SwarmEventMap>(event: K, ...args: Parameters<SwarmEventMap[K]>): boolean;
82
+ }
83
+ /**
84
+ * Create a swarm coordinator
85
+ */
86
+ export declare function createSwarmCoordinator(options?: CoordinatorOptions): SwarmCoordinator;
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Swarm Coordinator - Orchestrates multiple workers executing tasks
3
+ */
4
+ import { EventEmitter } from 'events';
5
+ import { DEFAULT_COORDINATOR_OPTIONS, DEFAULT_RETRY_POLICY } from './types.js';
6
+ import { TaskQueue } from './task.js';
7
+ import { WorkerPool } from './worker.js';
8
+ export class SwarmCoordinator extends EventEmitter {
9
+ options;
10
+ taskQueue;
11
+ workerPool;
12
+ retryPolicy;
13
+ running = false;
14
+ startTime = 0;
15
+ aborted = false;
16
+ constructor(options = {}) {
17
+ super();
18
+ this.options = {
19
+ ...DEFAULT_COORDINATOR_OPTIONS,
20
+ ...options,
21
+ retryPolicy: {
22
+ ...DEFAULT_RETRY_POLICY,
23
+ ...options.retryPolicy,
24
+ },
25
+ };
26
+ this.retryPolicy = this.options.retryPolicy;
27
+ this.taskQueue = new TaskQueue();
28
+ this.workerPool = new WorkerPool(this.options.concurrency, {
29
+ cwd: this.options.cwd,
30
+ yolo: this.options.yolo,
31
+ timeout: this.options.timeout,
32
+ });
33
+ }
34
+ /**
35
+ * Add a single task
36
+ */
37
+ addTask(task) {
38
+ this.taskQueue.addTask(task);
39
+ }
40
+ /**
41
+ * Add multiple tasks
42
+ */
43
+ addTasks(tasks) {
44
+ this.taskQueue.addTasks(tasks);
45
+ }
46
+ /**
47
+ * Get next task from queue
48
+ */
49
+ getTask() {
50
+ return this.taskQueue.getNextTask();
51
+ }
52
+ /**
53
+ * Peek at next task
54
+ */
55
+ peekTask() {
56
+ return this.taskQueue.peekNextTask();
57
+ }
58
+ /**
59
+ * Get all workers status
60
+ */
61
+ getAllWorkers() {
62
+ return this.workerPool.getAllWorkers().map(w => w.getStatus());
63
+ }
64
+ /**
65
+ * Get worker status by ID
66
+ */
67
+ getWorkerStatus(id) {
68
+ return this.workerPool.getWorkerById(id)?.getStatus();
69
+ }
70
+ /**
71
+ * Stop the swarm gracefully
72
+ */
73
+ stop() {
74
+ this.running = false;
75
+ }
76
+ /**
77
+ * Abort immediately
78
+ */
79
+ abort() {
80
+ this.aborted = true;
81
+ this.running = false;
82
+ this.workerPool.killAll();
83
+ }
84
+ /**
85
+ * Run the swarm
86
+ */
87
+ async run(concurrency) {
88
+ if (concurrency !== undefined) {
89
+ this.options.concurrency = concurrency;
90
+ this.workerPool = new WorkerPool(concurrency, {
91
+ cwd: this.options.cwd,
92
+ yolo: this.options.yolo,
93
+ timeout: this.options.timeout,
94
+ });
95
+ }
96
+ this.running = true;
97
+ this.aborted = false;
98
+ this.startTime = Date.now();
99
+ // Skip tasks blocked by failed dependencies
100
+ const skipped = this.taskQueue.skipBlockedTasks();
101
+ for (const taskId of skipped) {
102
+ const task = this.taskQueue.getTask(taskId);
103
+ if (task) {
104
+ this.emit('task:fail', task, new Error('Blocked by failed dependency'));
105
+ }
106
+ }
107
+ // Process tasks
108
+ await this.processLoop();
109
+ // Mark as no longer running
110
+ this.running = false;
111
+ // Build result
112
+ const stats = this.taskQueue.getStats();
113
+ const results = this.taskQueue.getResults();
114
+ const failures = this.taskQueue.getFailures();
115
+ const duration = Date.now() - this.startTime;
116
+ const result = {
117
+ total: stats.total,
118
+ completed: stats.completed,
119
+ failed: stats.failed,
120
+ skipped: skipped.length,
121
+ duration,
122
+ successRate: stats.total > 0 ? stats.completed / stats.total : 0,
123
+ results,
124
+ failedTasks: failures,
125
+ };
126
+ this.emit('swarm:complete', result);
127
+ return result;
128
+ }
129
+ /**
130
+ * Main processing loop
131
+ */
132
+ async processLoop() {
133
+ const activePromises = new Map();
134
+ while (this.running && !this.aborted) {
135
+ // Check if done
136
+ if (this.taskQueue.isDone() && activePromises.size === 0) {
137
+ break;
138
+ }
139
+ // Skip blocked tasks
140
+ const skipped = this.taskQueue.skipBlockedTasks();
141
+ for (const taskId of skipped) {
142
+ const task = this.taskQueue.getTask(taskId);
143
+ if (task) {
144
+ this.emit('task:fail', task, new Error('Blocked by failed dependency'));
145
+ }
146
+ }
147
+ // Try to start new tasks
148
+ while (this.workerPool.getAvailableCount() > 0) {
149
+ const task = this.taskQueue.getNextTask();
150
+ if (!task)
151
+ break;
152
+ const worker = this.workerPool.getWorker();
153
+ if (!worker) {
154
+ // No worker available, put task back
155
+ this.taskQueue.addTask(task);
156
+ break;
157
+ }
158
+ // Start task execution
159
+ const promise = this.executeTask(worker, task);
160
+ activePromises.set(task.id, promise);
161
+ promise.finally(() => {
162
+ activePromises.delete(task.id);
163
+ });
164
+ }
165
+ // Wait a bit before checking again
166
+ if (activePromises.size > 0) {
167
+ await Promise.race([
168
+ ...activePromises.values(),
169
+ this.sleep(100),
170
+ ]);
171
+ }
172
+ else if (this.taskQueue.hasWork()) {
173
+ // Have work but no available workers, wait
174
+ await this.sleep(100);
175
+ }
176
+ else {
177
+ break;
178
+ }
179
+ }
180
+ // Wait for remaining tasks to complete
181
+ if (activePromises.size > 0) {
182
+ await Promise.all(activePromises.values());
183
+ }
184
+ }
185
+ /**
186
+ * Execute a single task on a worker
187
+ */
188
+ async executeTask(worker, task) {
189
+ const attempt = this.taskQueue.getAttempts(task.id) + 1;
190
+ this.emit('task:start', task, worker.id);
191
+ if (attempt > 1) {
192
+ this.emit('task:retry', task, attempt);
193
+ }
194
+ try {
195
+ const result = await worker.execute(task);
196
+ if (result.success) {
197
+ const taskResult = {
198
+ task,
199
+ workerId: worker.id,
200
+ result,
201
+ };
202
+ this.taskQueue.completeTask(task.id, taskResult);
203
+ this.emit('task:complete', task, result);
204
+ }
205
+ else {
206
+ const willRetry = this.taskQueue.failTask(task.id, result.error || 'Unknown error', this.retryPolicy.maxRetries);
207
+ if (!willRetry) {
208
+ this.emit('task:fail', task, new Error(result.error || 'Max retries exceeded'));
209
+ }
210
+ }
211
+ }
212
+ catch (error) {
213
+ const errorMsg = error instanceof Error ? error.message : String(error);
214
+ const willRetry = this.taskQueue.failTask(task.id, errorMsg, this.retryPolicy.maxRetries);
215
+ if (!willRetry) {
216
+ this.emit('task:fail', task, error instanceof Error ? error : new Error(errorMsg));
217
+ }
218
+ }
219
+ finally {
220
+ // Release worker back to pool
221
+ this.workerPool.releaseWorker(worker);
222
+ }
223
+ }
224
+ /**
225
+ * Sleep helper
226
+ */
227
+ sleep(ms) {
228
+ return new Promise(resolve => setTimeout(resolve, ms));
229
+ }
230
+ /**
231
+ * Get queue statistics
232
+ */
233
+ getStats() {
234
+ return this.taskQueue.getStats();
235
+ }
236
+ /**
237
+ * Check if swarm is running
238
+ */
239
+ isRunning() {
240
+ return this.running;
241
+ }
242
+ /**
243
+ * Type-safe event emitter methods
244
+ */
245
+ on(event, listener) {
246
+ return super.on(event, listener);
247
+ }
248
+ emit(event, ...args) {
249
+ return super.emit(event, ...args);
250
+ }
251
+ }
252
+ /**
253
+ * Create a swarm coordinator
254
+ */
255
+ export function createSwarmCoordinator(options) {
256
+ return new SwarmCoordinator(options);
257
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Swarm Module - Coordinate multiple Simple-CLI agents
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { SwarmCoordinator } from 'simplecli/swarm';
7
+ *
8
+ * const coordinator = new SwarmCoordinator({
9
+ * cwd: '/path/to/repo',
10
+ * concurrency: 4,
11
+ * yolo: true,
12
+ * });
13
+ *
14
+ * coordinator.addTasks([
15
+ * { id: 'task1', type: 'implement', description: '...', scope: {}, priority: 1, timeout: 300000, retries: 2 },
16
+ * { id: 'task2', type: 'test', description: '...', scope: {}, priority: 2, timeout: 180000, retries: 1 },
17
+ * ]);
18
+ *
19
+ * const result = await coordinator.run();
20
+ * console.log(`Completed: ${result.completed}/${result.total}`);
21
+ * ```
22
+ */
23
+ export type { SwarmTask, TaskScope, TaskType, Priority, WorkerStatus, WorkerState, WorkerResult, TaskResult, FailedTask, SwarmResult, CoordinatorOptions, RetryPolicy, SwarmEventMap, } from './types.js';
24
+ export { swarmTaskSchema, taskScopeSchema, DEFAULT_RETRY_POLICY, DEFAULT_COORDINATOR_OPTIONS, } from './types.js';
25
+ export { TaskQueue } from './task.js';
26
+ export { Worker, WorkerPool } from './worker.js';
27
+ export type { WorkerOptions } from './worker.js';
28
+ export { SwarmCoordinator, createSwarmCoordinator } from './coordinator.js';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Swarm Module - Coordinate multiple Simple-CLI agents
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { SwarmCoordinator } from 'simplecli/swarm';
7
+ *
8
+ * const coordinator = new SwarmCoordinator({
9
+ * cwd: '/path/to/repo',
10
+ * concurrency: 4,
11
+ * yolo: true,
12
+ * });
13
+ *
14
+ * coordinator.addTasks([
15
+ * { id: 'task1', type: 'implement', description: '...', scope: {}, priority: 1, timeout: 300000, retries: 2 },
16
+ * { id: 'task2', type: 'test', description: '...', scope: {}, priority: 2, timeout: 180000, retries: 1 },
17
+ * ]);
18
+ *
19
+ * const result = await coordinator.run();
20
+ * console.log(`Completed: ${result.completed}/${result.total}`);
21
+ * ```
22
+ */
23
+ export { swarmTaskSchema, taskScopeSchema, DEFAULT_RETRY_POLICY, DEFAULT_COORDINATOR_OPTIONS, } from './types.js';
24
+ // Task Queue
25
+ export { TaskQueue } from './task.js';
26
+ // Worker
27
+ export { Worker, WorkerPool } from './worker.js';
28
+ // Coordinator
29
+ export { SwarmCoordinator, createSwarmCoordinator } from './coordinator.js';