@locusai/sdk 0.4.6 → 0.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/agent/worker.js +1271 -239
  2. package/dist/index-node.js +1601 -20
  3. package/dist/index.js +429 -121
  4. package/dist/orchestrator.d.ts.map +1 -1
  5. package/package.json +7 -19
  6. package/dist/agent/artifact-syncer.js +0 -77
  7. package/dist/agent/codebase-indexer-service.js +0 -55
  8. package/dist/agent/index.js +0 -5
  9. package/dist/agent/sprint-planner.js +0 -68
  10. package/dist/agent/task-executor.js +0 -60
  11. package/dist/ai/anthropic-client.js +0 -70
  12. package/dist/ai/claude-runner.js +0 -71
  13. package/dist/ai/index.js +0 -2
  14. package/dist/core/config.js +0 -15
  15. package/dist/core/index.js +0 -3
  16. package/dist/core/indexer.js +0 -113
  17. package/dist/core/prompt-builder.js +0 -83
  18. package/dist/events.js +0 -15
  19. package/dist/modules/auth.js +0 -23
  20. package/dist/modules/base.js +0 -8
  21. package/dist/modules/ci.js +0 -7
  22. package/dist/modules/docs.js +0 -38
  23. package/dist/modules/invitations.js +0 -22
  24. package/dist/modules/organizations.js +0 -39
  25. package/dist/modules/sprints.js +0 -34
  26. package/dist/modules/tasks.js +0 -56
  27. package/dist/modules/workspaces.js +0 -49
  28. package/dist/orchestrator.js +0 -356
  29. package/dist/utils/colors.js +0 -54
  30. package/dist/utils/retry.js +0 -37
  31. package/src/agent/artifact-syncer.ts +0 -111
  32. package/src/agent/codebase-indexer-service.ts +0 -71
  33. package/src/agent/index.ts +0 -5
  34. package/src/agent/sprint-planner.ts +0 -86
  35. package/src/agent/task-executor.ts +0 -85
  36. package/src/agent/worker.ts +0 -322
  37. package/src/ai/anthropic-client.ts +0 -93
  38. package/src/ai/claude-runner.ts +0 -86
  39. package/src/ai/index.ts +0 -2
  40. package/src/core/config.ts +0 -21
  41. package/src/core/index.ts +0 -3
  42. package/src/core/indexer.ts +0 -131
  43. package/src/core/prompt-builder.ts +0 -91
  44. package/src/events.ts +0 -35
  45. package/src/index-node.ts +0 -23
  46. package/src/index.ts +0 -159
  47. package/src/modules/auth.ts +0 -48
  48. package/src/modules/base.ts +0 -9
  49. package/src/modules/ci.ts +0 -12
  50. package/src/modules/docs.ts +0 -84
  51. package/src/modules/invitations.ts +0 -45
  52. package/src/modules/organizations.ts +0 -90
  53. package/src/modules/sprints.ts +0 -69
  54. package/src/modules/tasks.ts +0 -110
  55. package/src/modules/workspaces.ts +0 -94
  56. package/src/orchestrator.ts +0 -473
  57. package/src/utils/colors.ts +0 -63
  58. package/src/utils/retry.ts +0 -56
@@ -1,8 +0,0 @@
1
- export class BaseModule {
2
- api;
3
- emitter;
4
- constructor(api, emitter) {
5
- this.api = api;
6
- this.emitter = emitter;
7
- }
8
- }
@@ -1,7 +0,0 @@
1
- import { BaseModule } from "./base.js";
2
- export class CiModule extends BaseModule {
3
- async report(body) {
4
- const { data } = await this.api.post("/ci/report", body);
5
- return data;
6
- }
7
- }
@@ -1,38 +0,0 @@
1
- import { BaseModule } from "./base.js";
2
- export class DocsModule extends BaseModule {
3
- async create(workspaceId, body) {
4
- const { data } = await this.api.post(`/workspaces/${workspaceId}/docs`, body);
5
- return data.doc;
6
- }
7
- async list(workspaceId) {
8
- const { data } = await this.api.get(`/workspaces/${workspaceId}/docs`);
9
- return data.docs;
10
- }
11
- async getById(id, workspaceId) {
12
- const { data } = await this.api.get(`/workspaces/${workspaceId}/docs/${id}`);
13
- return data.doc;
14
- }
15
- async update(id, workspaceId, body) {
16
- const { data } = await this.api.put(`/workspaces/${workspaceId}/docs/${id}`, body);
17
- return data.doc;
18
- }
19
- async delete(id, workspaceId) {
20
- await this.api.delete(`/workspaces/${workspaceId}/docs/${id}`);
21
- }
22
- // Group Management
23
- async listGroups(workspaceId) {
24
- const { data } = await this.api.get(`/workspaces/${workspaceId}/doc-groups`);
25
- return data.groups;
26
- }
27
- async createGroup(workspaceId, body) {
28
- const { data } = await this.api.post(`/workspaces/${workspaceId}/doc-groups`, body);
29
- return data.group;
30
- }
31
- async updateGroup(id, workspaceId, body) {
32
- const { data } = await this.api.patch(`/workspaces/${workspaceId}/doc-groups/${id}`, body);
33
- return data.group;
34
- }
35
- async deleteGroup(id, workspaceId) {
36
- await this.api.delete(`/workspaces/${workspaceId}/doc-groups/${id}`);
37
- }
38
- }
@@ -1,22 +0,0 @@
1
- import { BaseModule } from "./base.js";
2
- export class InvitationsModule extends BaseModule {
3
- async create(orgId, body) {
4
- const { data } = await this.api.post(`/org/${orgId}/invitations`, body);
5
- return data.invitation;
6
- }
7
- async list(orgId) {
8
- const { data } = await this.api.get(`/org/${orgId}/invitations`);
9
- return data.invitations;
10
- }
11
- async verify(token) {
12
- const { data } = await this.api.get(`/invitations/verify/${token}`);
13
- return data;
14
- }
15
- async accept(body) {
16
- const { data } = await this.api.post("/invitations/accept", body);
17
- return data;
18
- }
19
- async revoke(orgId, id) {
20
- await this.api.delete(`/org/${orgId}/invitations/${id}`);
21
- }
22
- }
@@ -1,39 +0,0 @@
1
- import { BaseModule } from "./base.js";
2
- export class OrganizationsModule extends BaseModule {
3
- async list() {
4
- const { data } = await this.api.get("/organizations");
5
- return data.organizations;
6
- }
7
- async getById(id) {
8
- const { data } = await this.api.get(`/organizations/${id}`);
9
- return data.organization;
10
- }
11
- async listMembers(id) {
12
- const { data } = await this.api.get(`/organizations/${id}/members`);
13
- return data.members;
14
- }
15
- async addMember(id, body) {
16
- const { data } = await this.api.post(`/organizations/${id}/members`, body);
17
- return data.membership;
18
- }
19
- async removeMember(orgId, userId) {
20
- await this.api.delete(`/organizations/${orgId}/members/${userId}`);
21
- }
22
- async delete(orgId) {
23
- await this.api.delete(`/organizations/${orgId}`);
24
- }
25
- // ============================================================================
26
- // API Key Management
27
- // ============================================================================
28
- async listApiKeys(orgId) {
29
- const { data } = await this.api.get(`/organizations/${orgId}/api-keys`);
30
- return data.apiKeys;
31
- }
32
- async createApiKey(orgId, name) {
33
- const { data } = await this.api.post(`/organizations/${orgId}/api-keys`, { name });
34
- return data.apiKey;
35
- }
36
- async deleteApiKey(orgId, keyId) {
37
- await this.api.delete(`/organizations/${orgId}/api-keys/${keyId}`);
38
- }
39
- }
@@ -1,34 +0,0 @@
1
- import { BaseModule } from "./base.js";
2
- export class SprintsModule extends BaseModule {
3
- async list(workspaceId) {
4
- const { data } = await this.api.get(`/workspaces/${workspaceId}/sprints`);
5
- return data.sprints;
6
- }
7
- async getActive(workspaceId) {
8
- const { data } = await this.api.get(`/workspaces/${workspaceId}/sprints/active`);
9
- return data.sprint;
10
- }
11
- async getById(id, workspaceId) {
12
- const { data } = await this.api.get(`/workspaces/${workspaceId}/sprints/${id}`);
13
- return data.sprint;
14
- }
15
- async create(workspaceId, body) {
16
- const { data } = await this.api.post(`/workspaces/${workspaceId}/sprints`, body);
17
- return data.sprint;
18
- }
19
- async update(id, workspaceId, body) {
20
- const { data } = await this.api.patch(`/workspaces/${workspaceId}/sprints/${id}`, body);
21
- return data.sprint;
22
- }
23
- async delete(id, workspaceId) {
24
- await this.api.delete(`/workspaces/${workspaceId}/sprints/${id}`);
25
- }
26
- async start(id, workspaceId) {
27
- const { data } = await this.api.post(`/workspaces/${workspaceId}/sprints/${id}/start`);
28
- return data.sprint;
29
- }
30
- async complete(id, workspaceId) {
31
- const { data } = await this.api.post(`/workspaces/${workspaceId}/sprints/${id}/complete`);
32
- return data.sprint;
33
- }
34
- }
@@ -1,56 +0,0 @@
1
- import { TaskStatus, } from "@locusai/shared";
2
- import { BaseModule } from "./base.js";
3
- export class TasksModule extends BaseModule {
4
- /**
5
- * List all tasks in a workspace, optionally filtered
6
- */
7
- async list(workspaceId, options) {
8
- const { data } = await this.api.get(`/workspaces/${workspaceId}/tasks`);
9
- let tasks = data.tasks;
10
- // Client-side filtering (API doesn't support query params yet)
11
- if (options?.sprintId) {
12
- tasks = tasks.filter((t) => t.sprintId === options.sprintId);
13
- }
14
- if (options?.status) {
15
- const statuses = Array.isArray(options.status)
16
- ? options.status
17
- : [options.status];
18
- tasks = tasks.filter((t) => statuses.includes(t.status));
19
- }
20
- return tasks;
21
- }
22
- /**
23
- * Get available tasks for an agent to work on.
24
- * Returns tasks in BACKLOG or IN_PROGRESS (unassigned) status.
25
- */
26
- async getAvailable(workspaceId, sprintId) {
27
- const tasks = await this.list(workspaceId, {
28
- sprintId,
29
- });
30
- return tasks.filter((t) => t.status === TaskStatus.BACKLOG ||
31
- (t.status === TaskStatus.IN_PROGRESS && !t.assignedTo));
32
- }
33
- async getById(id, workspaceId) {
34
- const { data } = await this.api.get(`/workspaces/${workspaceId}/tasks/${id}`);
35
- return data.task;
36
- }
37
- async create(workspaceId, body) {
38
- const { data } = await this.api.post(`/workspaces/${workspaceId}/tasks`, body);
39
- return data.task;
40
- }
41
- async update(id, workspaceId, body) {
42
- const { data } = await this.api.patch(`/workspaces/${workspaceId}/tasks/${id}`, body);
43
- return data.task;
44
- }
45
- async delete(id, workspaceId) {
46
- await this.api.delete(`/workspaces/${workspaceId}/tasks/${id}`);
47
- }
48
- async getBacklog(workspaceId) {
49
- const { data } = await this.api.get(`/workspaces/${workspaceId}/tasks/backlog`);
50
- return data.tasks;
51
- }
52
- async addComment(id, workspaceId, body) {
53
- const { data } = await this.api.post(`/workspaces/${workspaceId}/tasks/${id}/comment`, body);
54
- return data.comment;
55
- }
56
- }
@@ -1,49 +0,0 @@
1
- import { BaseModule } from "./base.js";
2
- export class WorkspacesModule extends BaseModule {
3
- async listAll() {
4
- const { data } = await this.api.get("/workspaces");
5
- return data.workspaces;
6
- }
7
- async listByOrg(orgId) {
8
- const { data } = await this.api.get(`/workspaces/org/${orgId}`);
9
- return data.workspaces;
10
- }
11
- async create(body) {
12
- const { orgId, ...bodyWithoutOrgId } = body;
13
- const { data } = await this.api.post(`/workspaces/org/${orgId}`, bodyWithoutOrgId);
14
- return data.workspace;
15
- }
16
- async createWithAutoOrg(body) {
17
- const { data } = await this.api.post("/workspaces", body);
18
- return data.workspace;
19
- }
20
- async getById(id) {
21
- const { data } = await this.api.get(`/workspaces/${id}`);
22
- return data.workspace;
23
- }
24
- async update(id, body) {
25
- const { data } = await this.api.put(`/workspaces/${id}`, body);
26
- return data.workspace;
27
- }
28
- async delete(id) {
29
- await this.api.delete(`/workspaces/${id}`);
30
- }
31
- async getStats(id) {
32
- const { data } = await this.api.get(`/workspaces/${id}/stats`);
33
- return data;
34
- }
35
- async getActivity(id, limit) {
36
- const { data } = await this.api.get(`/workspaces/${id}/activity`, {
37
- params: { limit },
38
- });
39
- return data.activity;
40
- }
41
- /**
42
- * Dispatch a task from the workspace backlog to an agent.
43
- * Atomically moves a task from BACKLOG to IN_PROGRESS and assigns it.
44
- */
45
- async dispatch(id, workerId, sprintId) {
46
- const { data } = await this.api.post(`/workspaces/${id}/dispatch`, { workerId, sprintId });
47
- return data.task;
48
- }
49
- }
@@ -1,356 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { TaskPriority, TaskStatus } from "@locusai/shared";
5
- import { EventEmitter } from "events";
6
- import { LocusClient } from "./index.js";
7
- import { c } from "./utils/colors.js";
8
- export class AgentOrchestrator extends EventEmitter {
9
- client;
10
- config;
11
- agents = new Map();
12
- isRunning = false;
13
- processedTasks = new Set();
14
- resolvedSprintId = null;
15
- constructor(config) {
16
- super();
17
- this.config = config;
18
- this.client = new LocusClient({
19
- baseUrl: config.apiBase,
20
- token: config.apiKey,
21
- });
22
- }
23
- /**
24
- * Resolve the sprint ID - use provided or find active sprint
25
- */
26
- async resolveSprintId() {
27
- if (this.config.sprintId) {
28
- return this.config.sprintId;
29
- }
30
- // Try to find active sprint in workspace
31
- try {
32
- const sprint = await this.client.sprints.getActive(this.config.workspaceId);
33
- if (sprint?.id) {
34
- console.log(c.info(`📋 Using active sprint: ${sprint.name}`));
35
- return sprint.id;
36
- }
37
- }
38
- catch {
39
- // No active sprint found, will work with all tasks
40
- }
41
- console.log(c.dim("ℹ No sprint specified, working with all workspace tasks"));
42
- return "";
43
- }
44
- /**
45
- * Start the orchestrator with N agents
46
- */
47
- async start() {
48
- if (this.isRunning) {
49
- throw new Error("Orchestrator is already running");
50
- }
51
- this.isRunning = true;
52
- this.processedTasks.clear();
53
- try {
54
- await this.orchestrationLoop();
55
- }
56
- catch (error) {
57
- this.emit("error", error);
58
- throw error;
59
- }
60
- finally {
61
- await this.cleanup();
62
- }
63
- }
64
- /**
65
- * Main orchestration loop - runs 1 agent continuously
66
- */
67
- async orchestrationLoop() {
68
- // Resolve sprint ID first
69
- this.resolvedSprintId = await this.resolveSprintId();
70
- this.emit("started", {
71
- timestamp: new Date(),
72
- config: this.config,
73
- sprintId: this.resolvedSprintId,
74
- });
75
- console.log(`\n${c.primary("🤖 Locus Agent Orchestrator")}`);
76
- console.log(c.dim("----------------------------------------------"));
77
- console.log(`${c.bold("Workspace:")} ${this.config.workspaceId}`);
78
- if (this.resolvedSprintId) {
79
- console.log(`${c.bold("Sprint:")} ${this.resolvedSprintId}`);
80
- }
81
- console.log(`${c.bold("API Base:")} ${this.config.apiBase}`);
82
- console.log(c.dim("----------------------------------------------\n"));
83
- // Check if there are tasks to work on before spawning
84
- const tasks = await this.getAvailableTasks();
85
- if (tasks.length === 0) {
86
- console.log(c.dim("ℹ No available tasks found in the backlog."));
87
- return;
88
- }
89
- // Spawn single agent
90
- await this.spawnAgent();
91
- // Wait for agent to complete
92
- while (this.agents.size > 0 && this.isRunning) {
93
- await this.reapAgents();
94
- if (this.agents.size === 0) {
95
- break;
96
- }
97
- await this.sleep(2000);
98
- }
99
- console.log(`\n${c.success("✅ Orchestrator finished")}`);
100
- }
101
- /**
102
- * Find the package root by looking for package.json
103
- */
104
- findPackageRoot(startPath) {
105
- let currentDir = startPath;
106
- while (currentDir !== "/") {
107
- if (existsSync(join(currentDir, "package.json"))) {
108
- return currentDir;
109
- }
110
- currentDir = dirname(currentDir);
111
- }
112
- // Fallback to startPath if not found
113
- return startPath;
114
- }
115
- /**
116
- * Spawn a single agent process
117
- */
118
- async spawnAgent() {
119
- const agentId = `agent-${Date.now()}-${Math.random()
120
- .toString(36)
121
- .slice(2, 9)}`;
122
- const agentState = {
123
- id: agentId,
124
- status: "IDLE",
125
- currentTaskId: null,
126
- tasksCompleted: 0,
127
- tasksFailed: 0,
128
- lastHeartbeat: new Date(),
129
- };
130
- this.agents.set(agentId, agentState);
131
- console.log(`${c.primary("🚀 Agent started:")} ${c.bold(agentId)}\n`);
132
- // Build arguments for agent worker
133
- // Try multiple resolution strategies
134
- const potentialPaths = [];
135
- // Strategy 1: Use import.meta.resolve to find the installed SDK package
136
- try {
137
- // Resolve the SDK's index to find the package location
138
- const sdkIndexPath = import.meta.resolve("@locusai/sdk");
139
- const sdkDir = dirname(sdkIndexPath.replace("file://", ""));
140
- // In production, files are in dist/; sdkDir points to dist/ or src/
141
- const sdkRoot = this.findPackageRoot(sdkDir);
142
- potentialPaths.push(join(sdkRoot, "dist", "agent", "worker.js"), join(sdkRoot, "src", "agent", "worker.ts"));
143
- }
144
- catch {
145
- // import.meta.resolve failed, continue with fallback strategies
146
- }
147
- // Strategy 2: Find package root from __dirname (works in dev/local)
148
- const packageRoot = this.findPackageRoot(__dirname);
149
- potentialPaths.push(join(packageRoot, "dist", "agent", "worker.js"), join(packageRoot, "src", "agent", "worker.ts"), join(__dirname, "agent", "worker.ts"), join(__dirname, "agent", "worker.js"));
150
- const workerPath = potentialPaths.find((p) => existsSync(p));
151
- // Verify worker file exists
152
- if (!workerPath) {
153
- throw new Error(`Worker file not found. Checked: ${potentialPaths.join(", ")}. ` +
154
- `Make sure the SDK is properly built and installed.`);
155
- }
156
- const workerArgs = [
157
- "--agent-id",
158
- agentId,
159
- "--workspace-id",
160
- this.config.workspaceId,
161
- "--api-base",
162
- this.config.apiBase,
163
- "--api-key",
164
- this.config.apiKey,
165
- "--project-path",
166
- this.config.projectPath,
167
- ];
168
- // Add anthropic API key if provided
169
- if (this.config.anthropicApiKey) {
170
- workerArgs.push("--anthropic-api-key", this.config.anthropicApiKey);
171
- }
172
- // Add model if specified
173
- if (this.config.model) {
174
- workerArgs.push("--model", this.config.model);
175
- }
176
- // Add sprint ID if resolved
177
- if (this.resolvedSprintId) {
178
- workerArgs.push("--sprint-id", this.resolvedSprintId);
179
- }
180
- // Use node to run the worker script
181
- const agentProcess = spawn(process.execPath, [workerPath, ...workerArgs]);
182
- agentState.process = agentProcess;
183
- agentProcess.on("message", (msg) => {
184
- if (msg.type === "stats") {
185
- agentState.tasksCompleted = msg.tasksCompleted || 0;
186
- agentState.tasksFailed = msg.tasksFailed || 0;
187
- }
188
- });
189
- agentProcess.stdout?.on("data", (data) => {
190
- process.stdout.write(data.toString());
191
- });
192
- agentProcess.stderr?.on("data", (data) => {
193
- process.stderr.write(`[${agentId}] ERR: ${data.toString()}`);
194
- });
195
- agentProcess.on("exit", (code) => {
196
- console.log(`\n${agentId} finished (exit code: ${code})`);
197
- const agent = this.agents.get(agentId);
198
- if (agent) {
199
- agent.status = code === 0 ? "COMPLETED" : "FAILED";
200
- // Ensure CLI gets the absolute latest stats
201
- this.emit("agent:completed", {
202
- agentId,
203
- status: agent.status,
204
- tasksCompleted: agent.tasksCompleted,
205
- tasksFailed: agent.tasksFailed,
206
- });
207
- // Remove from active tracking after emitting
208
- this.agents.delete(agentId);
209
- }
210
- });
211
- this.emit("agent:spawned", { agentId });
212
- }
213
- /**
214
- * Reap completed agents
215
- */
216
- async reapAgents() {
217
- // No-op: agents now remove themselves in the 'exit' listener
218
- // to ensure events are emitted with correct stats before deletion.
219
- }
220
- /**
221
- * Get available tasks in sprint
222
- */
223
- async getAvailableTasks() {
224
- try {
225
- const tasks = await this.client.tasks.getAvailable(this.config.workspaceId, this.resolvedSprintId || undefined);
226
- return tasks.filter((task) => !this.processedTasks.has(task.id));
227
- }
228
- catch (error) {
229
- this.emit("error", error);
230
- return [];
231
- }
232
- }
233
- /**
234
- * Assign task to agent
235
- */
236
- async assignTaskToAgent(agentId) {
237
- const agent = this.agents.get(agentId);
238
- if (!agent)
239
- return null;
240
- try {
241
- const tasks = await this.getAvailableTasks();
242
- const priorityOrder = [
243
- TaskPriority.CRITICAL,
244
- TaskPriority.HIGH,
245
- TaskPriority.MEDIUM,
246
- TaskPriority.LOW,
247
- ];
248
- // Find task with highest priority
249
- let task = tasks.sort((a, b) => priorityOrder.indexOf(a.priority) - priorityOrder.indexOf(b.priority))[0];
250
- // Fallback: any available task
251
- if (!task && tasks.length > 0) {
252
- task = tasks[0];
253
- }
254
- if (!task)
255
- return null;
256
- agent.currentTaskId = task.id;
257
- agent.status = "WORKING";
258
- this.emit("task:assigned", {
259
- agentId,
260
- taskId: task.id,
261
- title: task.title,
262
- });
263
- return task;
264
- }
265
- catch (error) {
266
- this.emit("error", error);
267
- return null;
268
- }
269
- }
270
- /**
271
- * Mark task as completed by agent
272
- */
273
- async completeTask(taskId, agentId, summary) {
274
- try {
275
- await this.client.tasks.update(taskId, this.config.workspaceId, {
276
- status: TaskStatus.VERIFICATION,
277
- });
278
- if (summary) {
279
- await this.client.tasks.addComment(taskId, this.config.workspaceId, {
280
- author: agentId,
281
- text: `✅ Task completed\n\n${summary}`,
282
- });
283
- }
284
- this.processedTasks.add(taskId);
285
- const agent = this.agents.get(agentId);
286
- if (agent) {
287
- agent.tasksCompleted += 1;
288
- agent.currentTaskId = null;
289
- agent.status = "IDLE";
290
- }
291
- this.emit("task:completed", { agentId, taskId });
292
- }
293
- catch (error) {
294
- this.emit("error", error);
295
- }
296
- }
297
- /**
298
- * Mark task as failed
299
- */
300
- async failTask(taskId, agentId, error) {
301
- try {
302
- await this.client.tasks.update(taskId, this.config.workspaceId, {
303
- status: TaskStatus.BACKLOG,
304
- assignedTo: null,
305
- });
306
- await this.client.tasks.addComment(taskId, this.config.workspaceId, {
307
- author: agentId,
308
- text: `❌ Agent failed: ${error}`,
309
- });
310
- const agent = this.agents.get(agentId);
311
- if (agent) {
312
- agent.tasksFailed += 1;
313
- agent.currentTaskId = null;
314
- agent.status = "IDLE";
315
- }
316
- this.emit("task:failed", { agentId, taskId, error });
317
- }
318
- catch (error) {
319
- this.emit("error", error);
320
- }
321
- }
322
- /**
323
- * Stop orchestrator
324
- */
325
- async stop() {
326
- this.isRunning = false;
327
- await this.cleanup();
328
- this.emit("stopped", { timestamp: new Date() });
329
- }
330
- /**
331
- * Cleanup - kill all agent processes
332
- */
333
- async cleanup() {
334
- for (const [agentId, agent] of this.agents.entries()) {
335
- if (agent.process && !agent.process.killed) {
336
- console.log(`Killing agent: ${agentId}`);
337
- agent.process.kill();
338
- }
339
- }
340
- this.agents.clear();
341
- }
342
- /**
343
- * Get orchestrator stats
344
- */
345
- getStats() {
346
- return {
347
- activeAgents: this.agents.size,
348
- processedTasks: this.processedTasks.size,
349
- totalTasksCompleted: Array.from(this.agents.values()).reduce((sum, agent) => sum + agent.tasksCompleted, 0),
350
- totalTasksFailed: Array.from(this.agents.values()).reduce((sum, agent) => sum + agent.tasksFailed, 0),
351
- };
352
- }
353
- sleep(ms) {
354
- return new Promise((resolve) => setTimeout(resolve, ms));
355
- }
356
- }
@@ -1,54 +0,0 @@
1
- /**
2
- * Simple ANSI color utility for terminal output
3
- * Dependency-free and works in Node.js/Bun environments
4
- */
5
- const ESC = "\u001b[";
6
- const RESET = `${ESC}0m`;
7
- const colors = {
8
- reset: RESET,
9
- bold: `${ESC}1m`,
10
- dim: `${ESC}2m`,
11
- italic: `${ESC}3m`,
12
- underline: `${ESC}4m`,
13
- // Foreground colors
14
- black: `${ESC}30m`,
15
- red: `${ESC}31m`,
16
- green: `${ESC}32m`,
17
- yellow: `${ESC}33m`,
18
- blue: `${ESC}34m`,
19
- magenta: `${ESC}35m`,
20
- cyan: `${ESC}36m`,
21
- white: `${ESC}37m`,
22
- gray: `${ESC}90m`,
23
- // Foreground bright colors
24
- brightRed: `${ESC}91m`,
25
- brightGreen: `${ESC}92m`,
26
- brightYellow: `${ESC}93m`,
27
- brightBlue: `${ESC}94m`,
28
- brightMagenta: `${ESC}95m`,
29
- brightCyan: `${ESC}96m`,
30
- brightWhite: `${ESC}97m`,
31
- };
32
- export const c = {
33
- text: (text, ...colorNames) => {
34
- const codes = colorNames.map((name) => colors[name]).join("");
35
- return `${codes}${text}${RESET}`;
36
- },
37
- // Shortcuts
38
- bold: (t) => c.text(t, "bold"),
39
- dim: (t) => c.text(t, "dim"),
40
- red: (t) => c.text(t, "red"),
41
- green: (t) => c.text(t, "green"),
42
- yellow: (t) => c.text(t, "yellow"),
43
- blue: (t) => c.text(t, "blue"),
44
- magenta: (t) => c.text(t, "magenta"),
45
- cyan: (t) => c.text(t, "cyan"),
46
- gray: (t) => c.text(t, "gray"),
47
- // Combinations
48
- success: (t) => c.text(t, "green", "bold"),
49
- error: (t) => c.text(t, "red", "bold"),
50
- warning: (t) => c.text(t, "yellow", "bold"),
51
- info: (t) => c.text(t, "cyan", "bold"),
52
- primary: (t) => c.text(t, "blue", "bold"),
53
- underline: (t) => c.text(t, "underline"),
54
- };