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.
- package/ARCHITECTURE.md +411 -0
- package/CONFIGURATION.md +302 -0
- package/CONTRIBUTING.md +225 -0
- package/ELECTRON_README.md +121 -0
- package/INSTALLATION.md +350 -0
- package/LICENSE.md +1 -0
- package/PROJECT_STATUS.md +229 -0
- package/QUICKSTART.md +255 -0
- package/README.md +167 -0
- package/TESTING.md +274 -0
- package/package.json +61 -0
- package/scripts/start.js +30 -0
- package/src/assets/tray-icon.png +0 -0
- package/src/cli/commands/agent.js +327 -0
- package/src/cli/commands/click.js +108 -0
- package/src/cli/commands/drag.js +85 -0
- package/src/cli/commands/find.js +109 -0
- package/src/cli/commands/keys.js +132 -0
- package/src/cli/commands/mouse.js +79 -0
- package/src/cli/commands/repl.js +290 -0
- package/src/cli/commands/screenshot.js +72 -0
- package/src/cli/commands/scroll.js +74 -0
- package/src/cli/commands/start.js +67 -0
- package/src/cli/commands/type.js +57 -0
- package/src/cli/commands/wait.js +84 -0
- package/src/cli/commands/window.js +104 -0
- package/src/cli/liku.js +249 -0
- package/src/cli/util/output.js +174 -0
- package/src/main/agents/base-agent.js +410 -0
- package/src/main/agents/builder.js +484 -0
- package/src/main/agents/index.js +62 -0
- package/src/main/agents/orchestrator.js +362 -0
- package/src/main/agents/researcher.js +511 -0
- package/src/main/agents/state-manager.js +344 -0
- package/src/main/agents/supervisor.js +365 -0
- package/src/main/agents/verifier.js +452 -0
- package/src/main/ai-service.js +1633 -0
- package/src/main/index.js +2208 -0
- package/src/main/inspect-service.js +467 -0
- package/src/main/system-automation.js +1186 -0
- package/src/main/ui-automation/config.js +76 -0
- package/src/main/ui-automation/core/helpers.js +41 -0
- package/src/main/ui-automation/core/index.js +15 -0
- package/src/main/ui-automation/core/powershell.js +82 -0
- package/src/main/ui-automation/elements/finder.js +274 -0
- package/src/main/ui-automation/elements/index.js +14 -0
- package/src/main/ui-automation/elements/wait.js +66 -0
- package/src/main/ui-automation/index.js +164 -0
- package/src/main/ui-automation/interactions/element-click.js +211 -0
- package/src/main/ui-automation/interactions/high-level.js +230 -0
- package/src/main/ui-automation/interactions/index.js +47 -0
- package/src/main/ui-automation/keyboard/index.js +15 -0
- package/src/main/ui-automation/keyboard/input.js +179 -0
- package/src/main/ui-automation/mouse/click.js +186 -0
- package/src/main/ui-automation/mouse/drag.js +88 -0
- package/src/main/ui-automation/mouse/index.js +30 -0
- package/src/main/ui-automation/mouse/movement.js +51 -0
- package/src/main/ui-automation/mouse/scroll.js +116 -0
- package/src/main/ui-automation/screenshot.js +183 -0
- package/src/main/ui-automation/window/index.js +23 -0
- package/src/main/ui-automation/window/manager.js +305 -0
- package/src/main/utils/time.js +62 -0
- package/src/main/visual-awareness.js +597 -0
- package/src/renderer/chat/chat.js +671 -0
- package/src/renderer/chat/index.html +725 -0
- package/src/renderer/chat/preload.js +112 -0
- package/src/renderer/overlay/index.html +648 -0
- package/src/renderer/overlay/overlay.js +782 -0
- package/src/renderer/overlay/preload.js +90 -0
- package/src/shared/grid-math.js +82 -0
- package/src/shared/inspect-types.js +230 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Agent Class
|
|
3
|
+
*
|
|
4
|
+
* Foundation for all agent types in the multi-agent system.
|
|
5
|
+
* Provides common functionality for AI interaction, tool usage, and handoffs.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const EventEmitter = require('events');
|
|
9
|
+
|
|
10
|
+
// Agent roles enum
|
|
11
|
+
const AgentRole = {
|
|
12
|
+
SUPERVISOR: 'supervisor',
|
|
13
|
+
BUILDER: 'builder',
|
|
14
|
+
VERIFIER: 'verifier',
|
|
15
|
+
RESEARCHER: 'researcher'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Agent capabilities
|
|
19
|
+
const AgentCapabilities = {
|
|
20
|
+
// Core capabilities
|
|
21
|
+
SEARCH: 'search',
|
|
22
|
+
READ: 'read',
|
|
23
|
+
EDIT: 'edit',
|
|
24
|
+
EXECUTE: 'execute',
|
|
25
|
+
|
|
26
|
+
// Advanced capabilities
|
|
27
|
+
WEB_FETCH: 'web_fetch',
|
|
28
|
+
TODO: 'todo',
|
|
29
|
+
HANDOFF: 'handoff',
|
|
30
|
+
|
|
31
|
+
// Vision capabilities
|
|
32
|
+
SCREENSHOT: 'screenshot',
|
|
33
|
+
VISUAL_ANALYSIS: 'visual_analysis'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
class BaseAgent extends EventEmitter {
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
super();
|
|
39
|
+
|
|
40
|
+
this.id = options.id || `agent-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
41
|
+
this.role = options.role || AgentRole.BUILDER;
|
|
42
|
+
this.name = options.name || `${this.role}-agent`;
|
|
43
|
+
this.description = options.description || '';
|
|
44
|
+
|
|
45
|
+
// AI service for LLM calls
|
|
46
|
+
this.aiService = options.aiService;
|
|
47
|
+
|
|
48
|
+
// State manager for persistence
|
|
49
|
+
this.stateManager = options.stateManager;
|
|
50
|
+
|
|
51
|
+
// Orchestrator reference for handoffs
|
|
52
|
+
this.orchestrator = options.orchestrator;
|
|
53
|
+
|
|
54
|
+
// Configuration
|
|
55
|
+
this.maxRecursionDepth = options.maxRecursionDepth || 3;
|
|
56
|
+
this.maxSubCalls = options.maxSubCalls || 10;
|
|
57
|
+
this.currentDepth = 0;
|
|
58
|
+
this.subCallCount = 0;
|
|
59
|
+
|
|
60
|
+
// Capabilities (subclasses override)
|
|
61
|
+
this.capabilities = options.capabilities || [];
|
|
62
|
+
|
|
63
|
+
// Model metadata tracking
|
|
64
|
+
this.modelMetadata = options.modelMetadata || null;
|
|
65
|
+
this.proofChain = [];
|
|
66
|
+
this.toolHistory = [];
|
|
67
|
+
this.metrics = {
|
|
68
|
+
totalCalls: 0,
|
|
69
|
+
successfulCalls: 0,
|
|
70
|
+
failedCalls: 0,
|
|
71
|
+
avgResponseTimeMs: 0,
|
|
72
|
+
tokenUsage: { prompt: 0, completion: 0 }
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Operating contract
|
|
76
|
+
this.contract = {
|
|
77
|
+
noGuessing: true,
|
|
78
|
+
preserveFunctionality: true,
|
|
79
|
+
modularity: true,
|
|
80
|
+
leastPrivilege: true,
|
|
81
|
+
recursionLimits: true,
|
|
82
|
+
security: true,
|
|
83
|
+
backgroundHygiene: true
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Conversation history for context
|
|
87
|
+
this.conversationHistory = [];
|
|
88
|
+
|
|
89
|
+
// Active processes (for background hygiene)
|
|
90
|
+
this.activeProcesses = new Map();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ===== Core Methods (to be overridden by subclasses) =====
|
|
94
|
+
|
|
95
|
+
async process(task, context = {}) {
|
|
96
|
+
throw new Error('process() must be implemented by subclass');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getSystemPrompt() {
|
|
100
|
+
throw new Error('getSystemPrompt() must be implemented by subclass');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ===== Common Functionality =====
|
|
104
|
+
|
|
105
|
+
async chat(message, options = {}) {
|
|
106
|
+
if (!this.aiService) {
|
|
107
|
+
throw new Error('AI service not configured');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Add to conversation history
|
|
111
|
+
this.conversationHistory.push({
|
|
112
|
+
role: 'user',
|
|
113
|
+
content: message,
|
|
114
|
+
timestamp: new Date().toISOString()
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const systemPrompt = this.getSystemPrompt();
|
|
118
|
+
const response = await this.aiService.chat(message, {
|
|
119
|
+
systemPrompt,
|
|
120
|
+
history: this.conversationHistory,
|
|
121
|
+
model: options.model,
|
|
122
|
+
...options
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Add response to history
|
|
126
|
+
this.conversationHistory.push({
|
|
127
|
+
role: 'assistant',
|
|
128
|
+
content: response.text,
|
|
129
|
+
timestamp: new Date().toISOString()
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return response;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ===== Tool Methods =====
|
|
136
|
+
|
|
137
|
+
async search(query, options = {}) {
|
|
138
|
+
this.emit('tool:search', { query, options });
|
|
139
|
+
|
|
140
|
+
// Implementation depends on available tools
|
|
141
|
+
return {
|
|
142
|
+
results: [],
|
|
143
|
+
query,
|
|
144
|
+
timestamp: new Date().toISOString()
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async read(filePath, options = {}) {
|
|
149
|
+
const fs = require('fs');
|
|
150
|
+
|
|
151
|
+
if (!fs.existsSync(filePath)) {
|
|
152
|
+
return { error: `File not found: ${filePath}` };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
156
|
+
this.emit('tool:read', { filePath, lines: content.split('\n').length });
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
content,
|
|
160
|
+
filePath,
|
|
161
|
+
lines: content.split('\n').length
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async edit(filePath, changes, options = {}) {
|
|
166
|
+
if (!this.capabilities.includes(AgentCapabilities.EDIT)) {
|
|
167
|
+
return { error: 'Agent does not have edit capability' };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.emit('tool:edit', { filePath, changes });
|
|
171
|
+
|
|
172
|
+
// Actual edit implementation would go here
|
|
173
|
+
return {
|
|
174
|
+
success: true,
|
|
175
|
+
filePath,
|
|
176
|
+
changes
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async execute(command, options = {}) {
|
|
181
|
+
const { exec, spawn } = require('child_process');
|
|
182
|
+
const { promisify } = require('util');
|
|
183
|
+
const execAsync = promisify(exec);
|
|
184
|
+
|
|
185
|
+
this.emit('tool:execute', { command, options });
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
if (options.background) {
|
|
189
|
+
// Background process with PID tracking
|
|
190
|
+
const child = spawn(command, [], {
|
|
191
|
+
shell: true,
|
|
192
|
+
detached: true,
|
|
193
|
+
stdio: ['ignore', 'pipe', 'pipe']
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const pid = child.pid;
|
|
197
|
+
this.activeProcesses.set(pid, { command, startedAt: new Date().toISOString() });
|
|
198
|
+
|
|
199
|
+
return {
|
|
200
|
+
pid,
|
|
201
|
+
command,
|
|
202
|
+
status: 'running'
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
207
|
+
timeout: options.timeout || 60000,
|
|
208
|
+
maxBuffer: options.maxBuffer || 10 * 1024 * 1024
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
stdout,
|
|
213
|
+
stderr,
|
|
214
|
+
success: true
|
|
215
|
+
};
|
|
216
|
+
} catch (error) {
|
|
217
|
+
return {
|
|
218
|
+
error: error.message,
|
|
219
|
+
stdout: error.stdout,
|
|
220
|
+
stderr: error.stderr,
|
|
221
|
+
success: false
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ===== Handoff Methods =====
|
|
227
|
+
|
|
228
|
+
async handoff(targetRole, context, message) {
|
|
229
|
+
if (!this.orchestrator) {
|
|
230
|
+
throw new Error('Orchestrator not configured for handoffs');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
this.emit('handoff', {
|
|
234
|
+
from: this.role,
|
|
235
|
+
to: targetRole,
|
|
236
|
+
context,
|
|
237
|
+
message
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Record handoff in state
|
|
241
|
+
if (this.stateManager && context.sessionId) {
|
|
242
|
+
this.stateManager.recordHandoff(
|
|
243
|
+
context.sessionId,
|
|
244
|
+
this.role,
|
|
245
|
+
targetRole,
|
|
246
|
+
{ message, timestamp: new Date().toISOString() }
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return this.orchestrator.executeHandoff(this, targetRole, context, message);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
handoffToSupervisor(context, message) {
|
|
254
|
+
return this.handoff(AgentRole.SUPERVISOR, context, message);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
handoffToBuilder(context, message) {
|
|
258
|
+
return this.handoff(AgentRole.BUILDER, context, message);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
handoffToVerifier(context, message) {
|
|
262
|
+
return this.handoff(AgentRole.VERIFIER, context, message);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ===== Recursion Control =====
|
|
266
|
+
|
|
267
|
+
checkRecursionLimits() {
|
|
268
|
+
if (this.currentDepth >= this.maxRecursionDepth) {
|
|
269
|
+
return {
|
|
270
|
+
allowed: false,
|
|
271
|
+
reason: `Max recursion depth (${this.maxRecursionDepth}) reached`
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (this.subCallCount >= this.maxSubCalls) {
|
|
276
|
+
return {
|
|
277
|
+
allowed: false,
|
|
278
|
+
reason: `Max sub-calls (${this.maxSubCalls}) reached`
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return { allowed: true };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
enterRecursion() {
|
|
286
|
+
this.currentDepth++;
|
|
287
|
+
this.subCallCount++;
|
|
288
|
+
return this.currentDepth;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
exitRecursion() {
|
|
292
|
+
this.currentDepth = Math.max(0, this.currentDepth - 1);
|
|
293
|
+
return this.currentDepth;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// ===== Logging & Proofs =====
|
|
297
|
+
|
|
298
|
+
log(level, message, data = {}) {
|
|
299
|
+
const entry = {
|
|
300
|
+
timestamp: new Date().toISOString(),
|
|
301
|
+
agent: this.id,
|
|
302
|
+
role: this.role,
|
|
303
|
+
level,
|
|
304
|
+
message,
|
|
305
|
+
data
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
this.emit('log', entry);
|
|
309
|
+
|
|
310
|
+
if (level === 'error') {
|
|
311
|
+
console.error(`[${this.role}] ${message}`, data);
|
|
312
|
+
} else {
|
|
313
|
+
console.log(`[${this.role}] ${message}`, data);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return entry;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
addProof(type, content, source = null) {
|
|
320
|
+
const proof = {
|
|
321
|
+
type,
|
|
322
|
+
content,
|
|
323
|
+
source,
|
|
324
|
+
timestamp: new Date().toISOString(),
|
|
325
|
+
agentId: this.id
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
this.emit('proof', proof);
|
|
329
|
+
return proof;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
addStructuredProof(proof) {
|
|
333
|
+
const structuredProof = {
|
|
334
|
+
id: `proof-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
335
|
+
...proof,
|
|
336
|
+
timestamp: new Date().toISOString(),
|
|
337
|
+
agentId: this.id,
|
|
338
|
+
agentRole: this.role,
|
|
339
|
+
modelMetadata: this.modelMetadata
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
this.proofChain.push(structuredProof);
|
|
343
|
+
this.emit('proof', structuredProof);
|
|
344
|
+
return structuredProof;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
recordToolExecution(toolName, input, output, durationMs, success) {
|
|
348
|
+
this.toolHistory.push({
|
|
349
|
+
id: `tool-${Date.now()}`,
|
|
350
|
+
toolName,
|
|
351
|
+
input,
|
|
352
|
+
output: success ? output : null,
|
|
353
|
+
error: success ? null : output,
|
|
354
|
+
durationMs,
|
|
355
|
+
success,
|
|
356
|
+
timestamp: new Date().toISOString()
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
this.metrics.totalCalls++;
|
|
360
|
+
if (success) {
|
|
361
|
+
this.metrics.successfulCalls++;
|
|
362
|
+
} else {
|
|
363
|
+
this.metrics.failedCalls++;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Update rolling average
|
|
367
|
+
const totalTime = this.metrics.avgResponseTimeMs * (this.metrics.totalCalls - 1) + durationMs;
|
|
368
|
+
this.metrics.avgResponseTimeMs = totalTime / this.metrics.totalCalls;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// ===== State Management =====
|
|
372
|
+
|
|
373
|
+
getState() {
|
|
374
|
+
return {
|
|
375
|
+
id: this.id,
|
|
376
|
+
role: this.role,
|
|
377
|
+
name: this.name,
|
|
378
|
+
currentDepth: this.currentDepth,
|
|
379
|
+
subCallCount: this.subCallCount,
|
|
380
|
+
activeProcesses: Array.from(this.activeProcesses.entries()),
|
|
381
|
+
conversationLength: this.conversationHistory.length,
|
|
382
|
+
modelMetadata: this.modelMetadata,
|
|
383
|
+
proofChainLength: this.proofChain.length,
|
|
384
|
+
metrics: this.metrics,
|
|
385
|
+
lastActivity: new Date().toISOString()
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
reset() {
|
|
390
|
+
this.conversationHistory = [];
|
|
391
|
+
this.currentDepth = 0;
|
|
392
|
+
this.subCallCount = 0;
|
|
393
|
+
this.activeProcesses.clear();
|
|
394
|
+
this.proofChain = [];
|
|
395
|
+
this.toolHistory = [];
|
|
396
|
+
this.metrics = {
|
|
397
|
+
totalCalls: 0,
|
|
398
|
+
successfulCalls: 0,
|
|
399
|
+
failedCalls: 0,
|
|
400
|
+
avgResponseTimeMs: 0,
|
|
401
|
+
tokenUsage: { prompt: 0, completion: 0 }
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
module.exports = {
|
|
407
|
+
BaseAgent,
|
|
408
|
+
AgentRole,
|
|
409
|
+
AgentCapabilities
|
|
410
|
+
};
|