copilot-liku-cli 0.0.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 (71) hide show
  1. package/ARCHITECTURE.md +411 -0
  2. package/CONFIGURATION.md +302 -0
  3. package/CONTRIBUTING.md +225 -0
  4. package/ELECTRON_README.md +121 -0
  5. package/INSTALLATION.md +350 -0
  6. package/LICENSE.md +1 -0
  7. package/PROJECT_STATUS.md +229 -0
  8. package/QUICKSTART.md +255 -0
  9. package/README.md +167 -0
  10. package/TESTING.md +274 -0
  11. package/package.json +61 -0
  12. package/scripts/start.js +30 -0
  13. package/src/assets/tray-icon.png +0 -0
  14. package/src/cli/commands/agent.js +327 -0
  15. package/src/cli/commands/click.js +108 -0
  16. package/src/cli/commands/drag.js +85 -0
  17. package/src/cli/commands/find.js +109 -0
  18. package/src/cli/commands/keys.js +132 -0
  19. package/src/cli/commands/mouse.js +79 -0
  20. package/src/cli/commands/repl.js +290 -0
  21. package/src/cli/commands/screenshot.js +72 -0
  22. package/src/cli/commands/scroll.js +74 -0
  23. package/src/cli/commands/start.js +67 -0
  24. package/src/cli/commands/type.js +57 -0
  25. package/src/cli/commands/wait.js +84 -0
  26. package/src/cli/commands/window.js +104 -0
  27. package/src/cli/liku.js +249 -0
  28. package/src/cli/util/output.js +174 -0
  29. package/src/main/agents/base-agent.js +410 -0
  30. package/src/main/agents/builder.js +484 -0
  31. package/src/main/agents/index.js +62 -0
  32. package/src/main/agents/orchestrator.js +362 -0
  33. package/src/main/agents/researcher.js +511 -0
  34. package/src/main/agents/state-manager.js +344 -0
  35. package/src/main/agents/supervisor.js +365 -0
  36. package/src/main/agents/verifier.js +452 -0
  37. package/src/main/ai-service.js +1633 -0
  38. package/src/main/index.js +2208 -0
  39. package/src/main/inspect-service.js +467 -0
  40. package/src/main/system-automation.js +1186 -0
  41. package/src/main/ui-automation/config.js +76 -0
  42. package/src/main/ui-automation/core/helpers.js +41 -0
  43. package/src/main/ui-automation/core/index.js +15 -0
  44. package/src/main/ui-automation/core/powershell.js +82 -0
  45. package/src/main/ui-automation/elements/finder.js +274 -0
  46. package/src/main/ui-automation/elements/index.js +14 -0
  47. package/src/main/ui-automation/elements/wait.js +66 -0
  48. package/src/main/ui-automation/index.js +164 -0
  49. package/src/main/ui-automation/interactions/element-click.js +211 -0
  50. package/src/main/ui-automation/interactions/high-level.js +230 -0
  51. package/src/main/ui-automation/interactions/index.js +47 -0
  52. package/src/main/ui-automation/keyboard/index.js +15 -0
  53. package/src/main/ui-automation/keyboard/input.js +179 -0
  54. package/src/main/ui-automation/mouse/click.js +186 -0
  55. package/src/main/ui-automation/mouse/drag.js +88 -0
  56. package/src/main/ui-automation/mouse/index.js +30 -0
  57. package/src/main/ui-automation/mouse/movement.js +51 -0
  58. package/src/main/ui-automation/mouse/scroll.js +116 -0
  59. package/src/main/ui-automation/screenshot.js +183 -0
  60. package/src/main/ui-automation/window/index.js +23 -0
  61. package/src/main/ui-automation/window/manager.js +305 -0
  62. package/src/main/utils/time.js +62 -0
  63. package/src/main/visual-awareness.js +597 -0
  64. package/src/renderer/chat/chat.js +671 -0
  65. package/src/renderer/chat/index.html +725 -0
  66. package/src/renderer/chat/preload.js +112 -0
  67. package/src/renderer/overlay/index.html +648 -0
  68. package/src/renderer/overlay/overlay.js +782 -0
  69. package/src/renderer/overlay/preload.js +90 -0
  70. package/src/shared/grid-math.js +82 -0
  71. package/src/shared/inspect-types.js +230 -0
@@ -0,0 +1,344 @@
1
+ /**
2
+ * Agent State Manager
3
+ *
4
+ * Manages persistent state across agent sessions.
5
+ * State is stored in .github/agent_state.json for visibility and debugging.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const os = require('os');
11
+ const { nowIso, nowFilenameSafe } = require('../utils/time');
12
+
13
+ class AgentStateManager {
14
+ constructor(statePath = null) {
15
+ this.statePath = statePath || path.join(process.cwd(), '.github', 'agent_state.json');
16
+ this.state = this._loadState();
17
+ }
18
+
19
+ _loadState() {
20
+ try {
21
+ if (fs.existsSync(this.statePath)) {
22
+ const content = fs.readFileSync(this.statePath, 'utf-8');
23
+ const state = JSON.parse(content);
24
+ return this._migrateState(state);
25
+ }
26
+ } catch (error) {
27
+ console.warn(`[StateManager] Failed to load state: ${error.message}`);
28
+ }
29
+
30
+ return {
31
+ version: '1.1.0',
32
+ schemaVersion: 2,
33
+ created: nowIso(),
34
+ queue: [],
35
+ inProgress: [],
36
+ completed: [],
37
+ failed: [],
38
+ agents: {},
39
+ sessions: [],
40
+ modelMetadata: {
41
+ modelId: 'unknown',
42
+ provider: 'unknown',
43
+ modelVersion: null,
44
+ capabilities: []
45
+ },
46
+ sessionContext: {
47
+ initiatedBy: null,
48
+ purpose: null,
49
+ parentSessionId: null
50
+ },
51
+ checkpoints: []
52
+ };
53
+ }
54
+
55
+ _migrateState(state) {
56
+ if (!state.schemaVersion || state.schemaVersion < 2) {
57
+ state.modelMetadata = state.modelMetadata || {
58
+ modelId: 'unknown',
59
+ provider: 'unknown',
60
+ modelVersion: null,
61
+ capabilities: []
62
+ };
63
+ state.sessionContext = state.sessionContext || {
64
+ initiatedBy: null,
65
+ purpose: null,
66
+ parentSessionId: null
67
+ };
68
+ state.checkpoints = state.checkpoints || [];
69
+ state.schemaVersion = 2;
70
+ state.version = '1.1.0';
71
+ }
72
+ return state;
73
+ }
74
+
75
+ _getStateFilePath(sessionId = null, modelId = null) {
76
+ const timestamp = nowFilenameSafe();
77
+ const modelSuffix = modelId ? `-${modelId}` : '';
78
+ const sessionSuffix = sessionId ? `-${sessionId.slice(-8)}` : '';
79
+ return path.join(
80
+ path.dirname(this.statePath),
81
+ `state-${timestamp}${modelSuffix}${sessionSuffix}.json`
82
+ );
83
+ }
84
+
85
+ _saveState() {
86
+ try {
87
+ const dir = path.dirname(this.statePath);
88
+ if (!fs.existsSync(dir)) {
89
+ fs.mkdirSync(dir, { recursive: true });
90
+ }
91
+
92
+ this.state.lastModified = nowIso();
93
+ fs.writeFileSync(this.statePath, JSON.stringify(this.state, null, 2));
94
+ } catch (error) {
95
+ console.error(`[StateManager] Failed to save state: ${error.message}`);
96
+ }
97
+ }
98
+
99
+ // ===== Queue Management =====
100
+
101
+ enqueue(task) {
102
+ const taskEntry = {
103
+ id: `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
104
+ ...task,
105
+ status: 'queued',
106
+ createdAt: nowIso(),
107
+ attempts: 0
108
+ };
109
+
110
+ this.state.queue.push(taskEntry);
111
+ this._saveState();
112
+ return taskEntry.id;
113
+ }
114
+
115
+ dequeue() {
116
+ const task = this.state.queue.shift();
117
+ if (task) {
118
+ task.status = 'in-progress';
119
+ task.startedAt = nowIso();
120
+ this.state.inProgress.push(task);
121
+ this._saveState();
122
+ }
123
+ return task;
124
+ }
125
+
126
+ // ===== Task Lifecycle =====
127
+
128
+ startTask(taskId, agentId) {
129
+ const task = this._findTask(taskId, 'queue');
130
+ if (task) {
131
+ this._moveTask(taskId, 'queue', 'inProgress');
132
+ task.status = 'in-progress';
133
+ task.agentId = agentId;
134
+ task.startedAt = nowIso();
135
+ this._saveState();
136
+ }
137
+ return task;
138
+ }
139
+
140
+ completeTask(taskId, result) {
141
+ const task = this._findTask(taskId, 'inProgress');
142
+ if (task) {
143
+ this._moveTask(taskId, 'inProgress', 'completed');
144
+ task.status = 'completed';
145
+ task.completedAt = nowIso();
146
+ task.result = result;
147
+ this._saveState();
148
+ }
149
+ return task;
150
+ }
151
+
152
+ failTask(taskId, error) {
153
+ const task = this._findTask(taskId, 'inProgress');
154
+ if (task) {
155
+ task.attempts++;
156
+
157
+ if (task.attempts >= 3) {
158
+ this._moveTask(taskId, 'inProgress', 'failed');
159
+ task.status = 'failed';
160
+ task.error = error;
161
+ task.failedAt = nowIso();
162
+ } else {
163
+ // Return to queue for retry
164
+ this._moveTask(taskId, 'inProgress', 'queue');
165
+ task.status = 'queued';
166
+ task.lastError = error;
167
+ }
168
+ this._saveState();
169
+ }
170
+ return task;
171
+ }
172
+
173
+ // ===== Agent Registration =====
174
+
175
+ registerAgent(agentId, agentType, capabilities) {
176
+ this.state.agents[agentId] = {
177
+ type: agentType,
178
+ capabilities,
179
+ registeredAt: nowIso(),
180
+ lastActive: nowIso(),
181
+ tasksCompleted: 0,
182
+ tasksFailed: 0
183
+ };
184
+ this._saveState();
185
+ }
186
+
187
+ updateAgentActivity(agentId) {
188
+ if (this.state.agents[agentId]) {
189
+ this.state.agents[agentId].lastActive = nowIso();
190
+ this._saveState();
191
+ }
192
+ }
193
+
194
+ setModelMetadata(metadata) {
195
+ this.state.modelMetadata = {
196
+ ...this.state.modelMetadata,
197
+ ...metadata,
198
+ lastUpdated: nowIso()
199
+ };
200
+ this._saveState();
201
+ }
202
+
203
+ // ===== Session Management =====
204
+
205
+ startSession(sessionId, metadata = {}) {
206
+ const session = {
207
+ id: sessionId || `session-${Date.now()}`,
208
+ startedAt: nowIso(),
209
+ status: 'active',
210
+ metadata,
211
+ handoffs: [],
212
+ tasks: []
213
+ };
214
+
215
+ this.state.sessions.push(session);
216
+ this._saveState();
217
+ return session;
218
+ }
219
+
220
+ recordHandoff(sessionId, fromAgent, toAgent, context) {
221
+ const session = this.state.sessions.find(s => s.id === sessionId);
222
+ if (session) {
223
+ session.handoffs.push({
224
+ from: fromAgent,
225
+ to: toAgent,
226
+ context,
227
+ timestamp: nowIso()
228
+ });
229
+ this._saveState();
230
+ }
231
+ }
232
+
233
+ endSession(sessionId, summary) {
234
+ const session = this.state.sessions.find(s => s.id === sessionId);
235
+ if (session) {
236
+ session.status = 'completed';
237
+ session.endedAt = nowIso();
238
+ session.summary = summary;
239
+ this._saveState();
240
+ }
241
+ return session;
242
+ }
243
+
244
+ // ===== Checkpoint Management =====
245
+
246
+ createCheckpoint(sessionId, label, agentStates, handoffHistory) {
247
+ const checkpoint = {
248
+ id: `checkpoint-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
249
+ sessionId,
250
+ label,
251
+ timestamp: nowIso(),
252
+ agentStates: agentStates || [],
253
+ handoffHistory: handoffHistory || [],
254
+ modelMetadata: this.state.modelMetadata
255
+ };
256
+
257
+ this.state.checkpoints.push(checkpoint);
258
+ this._saveState();
259
+ return checkpoint;
260
+ }
261
+
262
+ getCheckpoint(checkpointId) {
263
+ return this.state.checkpoints.find(c => c.id === checkpointId) || null;
264
+ }
265
+
266
+ listCheckpoints(sessionId = null) {
267
+ if (sessionId) {
268
+ return this.state.checkpoints.filter(c => c.sessionId === sessionId);
269
+ }
270
+ return [...this.state.checkpoints];
271
+ }
272
+
273
+ // ===== Queries =====
274
+
275
+ getQueuedTasks() {
276
+ return [...this.state.queue];
277
+ }
278
+
279
+ getInProgressTasks() {
280
+ return [...this.state.inProgress];
281
+ }
282
+
283
+ getCompletedTasks(limit = 10) {
284
+ return this.state.completed.slice(-limit);
285
+ }
286
+
287
+ getAgentStats(agentId) {
288
+ return this.state.agents[agentId] || null;
289
+ }
290
+
291
+ getFullState() {
292
+ return { ...this.state };
293
+ }
294
+
295
+ // ===== Utilities =====
296
+
297
+ _findTask(taskId, listName) {
298
+ return this.state[listName]?.find(t => t.id === taskId);
299
+ }
300
+
301
+ _moveTask(taskId, fromList, toList) {
302
+ const index = this.state[fromList]?.findIndex(t => t.id === taskId);
303
+ if (index !== -1) {
304
+ const [task] = this.state[fromList].splice(index, 1);
305
+ this.state[toList].push(task);
306
+ return task;
307
+ }
308
+ return null;
309
+ }
310
+
311
+ clearCompleted() {
312
+ this.state.completed = [];
313
+ this._saveState();
314
+ }
315
+
316
+ reset() {
317
+ this.state = {
318
+ version: '1.1.0',
319
+ schemaVersion: 2,
320
+ created: nowIso(),
321
+ queue: [],
322
+ inProgress: [],
323
+ completed: [],
324
+ failed: [],
325
+ agents: {},
326
+ sessions: [],
327
+ modelMetadata: {
328
+ modelId: 'unknown',
329
+ provider: 'unknown',
330
+ modelVersion: null,
331
+ capabilities: []
332
+ },
333
+ sessionContext: {
334
+ initiatedBy: null,
335
+ purpose: null,
336
+ parentSessionId: null
337
+ },
338
+ checkpoints: []
339
+ };
340
+ this._saveState();
341
+ }
342
+ }
343
+
344
+ module.exports = { AgentStateManager };
@@ -0,0 +1,365 @@
1
+ /**
2
+ * Supervisor Agent
3
+ *
4
+ * Orchestrates and decomposes tasks, manages handoffs to Builder/Verifier.
5
+ * Does NOT edit files directly - delegates all implementation to Builder.
6
+ *
7
+ * Operating Rules:
8
+ * - Start with a short plan (2-5 steps)
9
+ * - Decompose work into concrete file/symbol-level subtasks
10
+ * - Delegate implementation to Builder, validation to Verifier
11
+ * - Preserve existing behavior
12
+ * - Never execute terminal commands or edit files
13
+ */
14
+
15
+ const { BaseAgent, AgentRole, AgentCapabilities } = require('./base-agent');
16
+
17
+ class SupervisorAgent extends BaseAgent {
18
+ constructor(options = {}) {
19
+ super({
20
+ ...options,
21
+ role: AgentRole.SUPERVISOR,
22
+ name: options.name || 'supervisor',
23
+ description: 'Orchestrates tasks, decomposes plans, manages agent handoffs',
24
+ capabilities: [
25
+ AgentCapabilities.SEARCH,
26
+ AgentCapabilities.READ,
27
+ AgentCapabilities.WEB_FETCH,
28
+ AgentCapabilities.TODO,
29
+ AgentCapabilities.HANDOFF
30
+ ]
31
+ });
32
+
33
+ // Supervisor-specific state
34
+ this.currentPlan = null;
35
+ this.decomposedTasks = [];
36
+ this.assumptions = [];
37
+ }
38
+
39
+ getSystemPrompt() {
40
+ return `You are the SUPERVISOR agent in a multi-agent coding system.
41
+
42
+ # OPERATING CONTRACT (NON-NEGOTIABLE)
43
+ - **No guessing**: Probe or ground with tools (search, read).
44
+ - **Preserve functionalities**: Never disable core features.
45
+ - **Modularity**: Decompose into sub-modules.
46
+ - **Least privilege**: READ-ONLY access. Use Builder for any writes.
47
+ - **Recursion limits**: Depth ≤3; avoid >10 sub-calls without progress.
48
+ - **Security**: Audit all changes before approval.
49
+
50
+ # YOUR RESPONSIBILITIES
51
+ 1. Analyze user requests and create 2-5 step plans
52
+ 2. Decompose work into concrete file/symbol-level subtasks
53
+ 3. Delegate implementation to Builder agent
54
+ 4. Delegate validation to Verifier agent
55
+ 5. Aggregate results and provide final summary
56
+
57
+ # WORKFLOW
58
+ 1. Read state from agent_state.json before planning
59
+ 2. Create plan with explicit assumptions
60
+ 3. For each subtask:
61
+ - If implementation needed: Handoff to Builder
62
+ - If validation needed: Handoff to Verifier
63
+ 4. Aggregate results and verify completeness
64
+ 5. Update state with completed/failed tasks
65
+
66
+ # HANDOFF FORMAT
67
+ When handing off to Builder:
68
+ "Implement: [specific task]. Files: [file paths]. Constraints: [any limits]"
69
+
70
+ When handing off to Verifier:
71
+ "Verify: [what to check]. Changes: [summary of changes]. Tests: [required tests]"
72
+
73
+ # OUTPUT FORMAT
74
+ Always structure your response as:
75
+ 1. Analysis: (what you understand about the task)
76
+ 2. Plan: (numbered steps)
77
+ 3. Assumptions: (what you're assuming)
78
+ 4. Next Action: (handoff or completion)`;
79
+ }
80
+
81
+ async process(task, context = {}) {
82
+ this.log('info', 'Supervisor processing task', { task: task.description || task });
83
+
84
+ // Check recursion limits
85
+ const limits = this.checkRecursionLimits();
86
+ if (!limits.allowed) {
87
+ return {
88
+ success: false,
89
+ error: limits.reason,
90
+ suggestedAction: 'handoff_to_human'
91
+ };
92
+ }
93
+
94
+ try {
95
+ // Step 1: Analyze the task
96
+ const analysis = await this.analyzeTask(task, context);
97
+
98
+ // Step 2: Create plan
99
+ const plan = await this.createPlan(analysis);
100
+ this.currentPlan = plan;
101
+
102
+ // Step 3: Decompose into subtasks
103
+ this.decomposedTasks = await this.decomposeTasks(plan);
104
+
105
+ // Step 4: Execute plan (handoffs to Builder/Verifier)
106
+ const results = await this.executePlan(this.decomposedTasks, context);
107
+
108
+ // Step 5: Aggregate and return
109
+ return this.aggregateResults(results, context);
110
+
111
+ } catch (error) {
112
+ this.log('error', 'Supervisor processing failed', { error: error.message });
113
+ return {
114
+ success: false,
115
+ error: error.message,
116
+ state: this.getState()
117
+ };
118
+ }
119
+ }
120
+
121
+ async analyzeTask(task, context) {
122
+ const prompt = `Analyze this task and identify:
123
+ 1. What files/modules are involved?
124
+ 2. What changes are needed?
125
+ 3. What validation is required?
126
+
127
+ Task: ${typeof task === 'string' ? task : JSON.stringify(task)}
128
+ Context: ${JSON.stringify(context)}`;
129
+
130
+ const response = await this.chat(prompt);
131
+
132
+ return {
133
+ description: task,
134
+ analysis: response.text,
135
+ timestamp: new Date().toISOString()
136
+ };
137
+ }
138
+
139
+ async createPlan(analysis) {
140
+ const prompt = `Based on this analysis, create a 2-5 step execution plan.
141
+ Each step should be concrete and actionable.
142
+ Specify whether each step needs Builder (implementation) or Verifier (validation).
143
+
144
+ Analysis: ${analysis.analysis}
145
+
146
+ Current Model: ${this.modelMetadata?.modelId || 'unknown'}
147
+ Model Capabilities: ${this.modelMetadata?.capabilities?.join(', ') || 'standard'}`;
148
+
149
+ const response = await this.chat(prompt);
150
+
151
+ return {
152
+ steps: this.parseSteps(response.text),
153
+ rawPlan: response.text,
154
+ assumptions: this.extractAssumptions(response.text),
155
+ modelContext: {
156
+ modelId: this.modelMetadata?.modelId,
157
+ provider: this.modelMetadata?.provider,
158
+ createdAt: new Date().toISOString()
159
+ },
160
+ planId: `plan-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`
161
+ };
162
+ }
163
+
164
+ parseSteps(planText) {
165
+ const steps = [];
166
+ const lines = planText.split('\n');
167
+
168
+ for (const line of lines) {
169
+ const match = line.match(/^\d+\.\s*(.+)/);
170
+ if (match) {
171
+ const stepText = match[1];
172
+ const isBuilder = /implement|create|edit|add|modify|fix/i.test(stepText);
173
+ const isVerifier = /verify|test|validate|check|ensure/i.test(stepText);
174
+
175
+ steps.push({
176
+ description: stepText,
177
+ agent: isBuilder ? AgentRole.BUILDER : (isVerifier ? AgentRole.VERIFIER : AgentRole.SUPERVISOR),
178
+ status: 'pending'
179
+ });
180
+ }
181
+ }
182
+
183
+ return steps;
184
+ }
185
+
186
+ extractAssumptions(text) {
187
+ const assumptions = [];
188
+ const lines = text.split('\n');
189
+
190
+ let inAssumptions = false;
191
+ for (const line of lines) {
192
+ if (/assumption|assuming/i.test(line)) {
193
+ inAssumptions = true;
194
+ }
195
+ if (inAssumptions && line.trim().startsWith('-')) {
196
+ assumptions.push(line.trim().substring(1).trim());
197
+ }
198
+ }
199
+
200
+ this.assumptions = assumptions;
201
+ return assumptions;
202
+ }
203
+
204
+ async decomposeTasks(plan) {
205
+ const tasks = [];
206
+
207
+ for (let i = 0; i < plan.steps.length; i++) {
208
+ const step = plan.steps[i];
209
+ tasks.push({
210
+ id: `subtask-${i + 1}`,
211
+ step: i + 1,
212
+ description: step.description,
213
+ targetAgent: step.agent,
214
+ status: 'pending',
215
+ dependencies: i > 0 ? [`subtask-${i}`] : []
216
+ });
217
+ }
218
+
219
+ return tasks;
220
+ }
221
+
222
+ async executePlan(tasks, context) {
223
+ const results = [];
224
+
225
+ for (const task of tasks) {
226
+ // Check if dependencies are satisfied
227
+ const depsComplete = task.dependencies.every(depId => {
228
+ const dep = results.find(r => r.taskId === depId);
229
+ return dep && dep.success;
230
+ });
231
+
232
+ if (!depsComplete) {
233
+ results.push({
234
+ taskId: task.id,
235
+ success: false,
236
+ error: 'Dependencies not satisfied',
237
+ skipped: true
238
+ });
239
+ continue;
240
+ }
241
+
242
+ task.status = 'in-progress';
243
+
244
+ if (task.targetAgent === AgentRole.BUILDER) {
245
+ const result = await this.handoffToBuilder(
246
+ { ...context, taskId: task.id },
247
+ `Implement: ${task.description}`
248
+ );
249
+ results.push({
250
+ taskId: task.id,
251
+ agent: AgentRole.BUILDER,
252
+ ...result
253
+ });
254
+ } else if (task.targetAgent === AgentRole.VERIFIER) {
255
+ const result = await this.handoffToVerifier(
256
+ { ...context, taskId: task.id },
257
+ `Verify: ${task.description}`
258
+ );
259
+ results.push({
260
+ taskId: task.id,
261
+ agent: AgentRole.VERIFIER,
262
+ ...result
263
+ });
264
+ } else {
265
+ // Handle internally
266
+ results.push({
267
+ taskId: task.id,
268
+ agent: AgentRole.SUPERVISOR,
269
+ success: true,
270
+ note: 'Handled by supervisor'
271
+ });
272
+ }
273
+
274
+ task.status = results[results.length - 1].success ? 'completed' : 'failed';
275
+ }
276
+
277
+ return results;
278
+ }
279
+
280
+ aggregateResults(results, context) {
281
+ const successful = results.filter(r => r.success);
282
+ const failed = results.filter(r => !r.success && !r.skipped);
283
+ const skipped = results.filter(r => r.skipped);
284
+
285
+ const dependencyGraph = this.buildDependencyGraph(this.decomposedTasks);
286
+
287
+ return {
288
+ success: failed.length === 0,
289
+ summary: {
290
+ total: results.length,
291
+ successful: successful.length,
292
+ failed: failed.length,
293
+ skipped: skipped.length
294
+ },
295
+ plan: this.currentPlan,
296
+ results,
297
+ assumptions: this.assumptions,
298
+ dependencyGraph,
299
+ timestamp: new Date().toISOString()
300
+ };
301
+ }
302
+
303
+ buildDependencyGraph(tasks) {
304
+ const graph = {
305
+ nodes: tasks.map(t => ({
306
+ id: t.id,
307
+ description: t.description,
308
+ agent: t.targetAgent,
309
+ status: t.status
310
+ })),
311
+ edges: []
312
+ };
313
+
314
+ for (const task of tasks) {
315
+ for (const depId of task.dependencies || []) {
316
+ graph.edges.push({
317
+ from: depId,
318
+ to: task.id,
319
+ type: 'depends-on'
320
+ });
321
+ }
322
+ }
323
+
324
+ return graph;
325
+ }
326
+
327
+ // ===== Supervisor-specific Methods =====
328
+
329
+ async interpretPrompt(userPrompt) {
330
+ const prompt = `Parse this user request and extract:
331
+ 1. Primary goal
332
+ 2. Scope (files, modules, features)
333
+ 3. Constraints (time, compatibility, etc.)
334
+ 4. Success criteria
335
+
336
+ User request: "${userPrompt}"`;
337
+
338
+ const response = await this.chat(prompt);
339
+ return {
340
+ originalPrompt: userPrompt,
341
+ interpretation: response.text,
342
+ timestamp: new Date().toISOString()
343
+ };
344
+ }
345
+
346
+ async researchContext(topic, files = []) {
347
+ const readResults = await Promise.all(
348
+ files.map(f => this.read(f))
349
+ );
350
+
351
+ const prompt = `Based on these files, what context is relevant for: ${topic}
352
+
353
+ Files content:
354
+ ${readResults.map(r => `--- ${r.filePath} ---\n${r.content?.slice(0, 2000)}`).join('\n\n')}`;
355
+
356
+ const response = await this.chat(prompt);
357
+ return {
358
+ topic,
359
+ context: response.text,
360
+ filesRead: files
361
+ };
362
+ }
363
+ }
364
+
365
+ module.exports = { SupervisorAgent };