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
package/TESTING.md
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# Testing Guide
|
|
2
|
+
|
|
3
|
+
## Manual Testing Checklist
|
|
4
|
+
|
|
5
|
+
### Initial Launch
|
|
6
|
+
- [ ] Application starts without errors
|
|
7
|
+
- [ ] Tray icon appears in system tray/menu bar
|
|
8
|
+
- [ ] Overlay window is invisible and click-through
|
|
9
|
+
- [ ] Chat window is hidden by default
|
|
10
|
+
|
|
11
|
+
### Tray Icon Functionality
|
|
12
|
+
- [ ] Right-click tray icon shows context menu
|
|
13
|
+
- [ ] "Open Chat" menu item works
|
|
14
|
+
- [ ] "Toggle Overlay" menu item works
|
|
15
|
+
- [ ] "Quit" menu item closes application
|
|
16
|
+
- [ ] Click tray icon toggles chat (macOS)
|
|
17
|
+
|
|
18
|
+
### Global Hotkeys
|
|
19
|
+
- [ ] `Ctrl+Alt+Space` (Cmd+Alt+Space on macOS) toggles chat window
|
|
20
|
+
- [ ] `Ctrl+Shift+O` (Cmd+Shift+O on macOS) toggles overlay visibility
|
|
21
|
+
- [ ] Hotkeys work from any application
|
|
22
|
+
|
|
23
|
+
### Chat Window
|
|
24
|
+
- [ ] Window appears at bottom-right corner
|
|
25
|
+
- [ ] Window is resizable
|
|
26
|
+
- [ ] Window can be dragged
|
|
27
|
+
- [ ] Closing window hides it (doesn't quit app)
|
|
28
|
+
- [ ] Window shows welcome message on first open
|
|
29
|
+
- [ ] Mode buttons are visible and functional
|
|
30
|
+
|
|
31
|
+
### Passive Mode
|
|
32
|
+
- [ ] Overlay is completely click-through
|
|
33
|
+
- [ ] Can interact with applications normally
|
|
34
|
+
- [ ] No dots visible on overlay
|
|
35
|
+
- [ ] Mode indicator not visible
|
|
36
|
+
|
|
37
|
+
### Selection Mode
|
|
38
|
+
- [ ] Click "Selection" button activates mode
|
|
39
|
+
- [ ] Dots appear on overlay (coarse grid, ~100px spacing)
|
|
40
|
+
- [ ] Mode indicator appears in top-right
|
|
41
|
+
- [ ] Dots are clickable
|
|
42
|
+
- [ ] Clicking dot shows message in chat
|
|
43
|
+
- [ ] Automatically returns to passive mode after dot click
|
|
44
|
+
- [ ] Cannot interact with applications behind overlay
|
|
45
|
+
|
|
46
|
+
### Chat Functionality
|
|
47
|
+
- [ ] Can type message in input field
|
|
48
|
+
- [ ] Enter key sends message
|
|
49
|
+
- [ ] Send button works
|
|
50
|
+
- [ ] Messages appear in chat history with timestamp
|
|
51
|
+
- [ ] User messages appear on right (blue)
|
|
52
|
+
- [ ] Agent messages appear on left (gray)
|
|
53
|
+
- [ ] System messages appear in center (italic)
|
|
54
|
+
- [ ] Chat history scrolls automatically
|
|
55
|
+
- [ ] Scrollbar works correctly
|
|
56
|
+
|
|
57
|
+
### IPC Communication
|
|
58
|
+
- [ ] Dot selection in overlay appears in chat
|
|
59
|
+
- [ ] Mode changes from chat affect overlay
|
|
60
|
+
- [ ] Messages from chat get echoed back (stub agent)
|
|
61
|
+
|
|
62
|
+
### Window Management
|
|
63
|
+
- [ ] Overlay stays on top of all windows
|
|
64
|
+
- [ ] Chat window can go behind other windows
|
|
65
|
+
- [ ] Minimizing chat window works
|
|
66
|
+
- [ ] Reopening chat restores position and size
|
|
67
|
+
- [ ] Chat window persists messages between hide/show
|
|
68
|
+
|
|
69
|
+
### Platform-Specific (macOS)
|
|
70
|
+
- [ ] App hidden from Dock
|
|
71
|
+
- [ ] Overlay floats above fullscreen apps
|
|
72
|
+
- [ ] Tray icon visible in menu bar
|
|
73
|
+
- [ ] Mission Control doesn't show overlay as separate space
|
|
74
|
+
- [ ] Works correctly with multiple displays
|
|
75
|
+
|
|
76
|
+
### Platform-Specific (Windows)
|
|
77
|
+
- [ ] Tray icon visible in system tray
|
|
78
|
+
- [ ] Overlay stays above most windows
|
|
79
|
+
- [ ] Works with fullscreen windows
|
|
80
|
+
- [ ] Alt+Tab doesn't show overlay
|
|
81
|
+
- [ ] Works correctly with multiple displays
|
|
82
|
+
|
|
83
|
+
### Performance
|
|
84
|
+
- [ ] Application starts quickly (< 3 seconds)
|
|
85
|
+
- [ ] Memory usage stays reasonable (< 300MB)
|
|
86
|
+
- [ ] CPU usage low when idle (< 1%)
|
|
87
|
+
- [ ] No lag when switching modes
|
|
88
|
+
- [ ] Smooth animations and transitions
|
|
89
|
+
- [ ] No memory leaks after extended use
|
|
90
|
+
|
|
91
|
+
### Edge Cases
|
|
92
|
+
- [ ] Changing screen resolution updates overlay
|
|
93
|
+
- [ ] Disconnecting/reconnecting displays works
|
|
94
|
+
- [ ] Switching between fullscreen apps works
|
|
95
|
+
- [ ] Overlay works on secondary displays
|
|
96
|
+
- [ ] System sleep/wake preserves state
|
|
97
|
+
- [ ] Rapid mode switching doesn't cause issues
|
|
98
|
+
- [ ] Many dots can be clicked in sequence
|
|
99
|
+
|
|
100
|
+
## Automated Testing
|
|
101
|
+
|
|
102
|
+
### Unit Tests (Future)
|
|
103
|
+
```javascript
|
|
104
|
+
// Example test structure
|
|
105
|
+
describe('Overlay Window', () => {
|
|
106
|
+
it('should create overlay window', () => {
|
|
107
|
+
// Test window creation
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should set click-through mode', () => {
|
|
111
|
+
// Test ignore mouse events
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should generate dot grid', () => {
|
|
115
|
+
// Test dot generation
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('IPC Communication', () => {
|
|
120
|
+
it('should send dot selection', () => {
|
|
121
|
+
// Test IPC message
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should handle mode changes', () => {
|
|
125
|
+
// Test mode switching
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Integration Tests (Future)
|
|
131
|
+
```javascript
|
|
132
|
+
const { Application } = require('spectron');
|
|
133
|
+
|
|
134
|
+
describe('Application Launch', () => {
|
|
135
|
+
let app;
|
|
136
|
+
|
|
137
|
+
beforeEach(async () => {
|
|
138
|
+
app = new Application({
|
|
139
|
+
path: electron,
|
|
140
|
+
args: [path.join(__dirname, '..')]
|
|
141
|
+
});
|
|
142
|
+
await app.start();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
afterEach(async () => {
|
|
146
|
+
if (app && app.isRunning()) {
|
|
147
|
+
await app.stop();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should show tray icon', async () => {
|
|
152
|
+
// Test tray presence
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Performance Testing
|
|
158
|
+
|
|
159
|
+
### Memory Profiling
|
|
160
|
+
1. Open Chrome DevTools (Cmd+Alt+I / Ctrl+Shift+I)
|
|
161
|
+
2. Go to Memory tab
|
|
162
|
+
3. Take heap snapshot
|
|
163
|
+
4. Use application for 5-10 minutes
|
|
164
|
+
5. Take another snapshot
|
|
165
|
+
6. Compare for memory leaks
|
|
166
|
+
|
|
167
|
+
### CPU Profiling
|
|
168
|
+
1. Open Performance tab in DevTools
|
|
169
|
+
2. Record while using application
|
|
170
|
+
3. Look for long tasks (> 50ms)
|
|
171
|
+
4. Identify optimization opportunities
|
|
172
|
+
|
|
173
|
+
### Startup Time
|
|
174
|
+
```bash
|
|
175
|
+
# Measure startup time
|
|
176
|
+
time npm start
|
|
177
|
+
# Target: < 3 seconds to first window
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Security Testing
|
|
181
|
+
|
|
182
|
+
### CSP Validation
|
|
183
|
+
1. Open DevTools Console
|
|
184
|
+
2. Look for CSP violations
|
|
185
|
+
3. Should see no errors
|
|
186
|
+
|
|
187
|
+
### IPC Security
|
|
188
|
+
1. Verify context isolation is enabled
|
|
189
|
+
2. Verify node integration is disabled
|
|
190
|
+
3. Check preload scripts expose only necessary APIs
|
|
191
|
+
|
|
192
|
+
### Dependency Audit
|
|
193
|
+
```bash
|
|
194
|
+
npm audit
|
|
195
|
+
# Should show 0 vulnerabilities
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Browser Testing
|
|
199
|
+
|
|
200
|
+
### Overlay Rendering
|
|
201
|
+
- [ ] Transparent background works
|
|
202
|
+
- [ ] Dots render correctly
|
|
203
|
+
- [ ] Labels visible and positioned correctly
|
|
204
|
+
- [ ] Hover effects work smoothly
|
|
205
|
+
- [ ] CSS transforms work correctly
|
|
206
|
+
|
|
207
|
+
### Chat Rendering
|
|
208
|
+
- [ ] Dark theme displays correctly
|
|
209
|
+
- [ ] Fonts load properly
|
|
210
|
+
- [ ] Scrolling is smooth
|
|
211
|
+
- [ ] Input field responsive
|
|
212
|
+
- [ ] Buttons work correctly
|
|
213
|
+
|
|
214
|
+
## Debugging Tips
|
|
215
|
+
|
|
216
|
+
### Enable DevTools
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// In main process
|
|
220
|
+
overlayWindow.webContents.openDevTools({ mode: 'detach' });
|
|
221
|
+
chatWindow.webContents.openDevTools({ mode: 'detach' });
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Console Logging
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
// Main process logs
|
|
228
|
+
console.log('Main process:', data);
|
|
229
|
+
|
|
230
|
+
// Renderer process logs appear in DevTools console
|
|
231
|
+
console.log('Renderer:', data);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### IPC Debugging
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
// Log all IPC messages
|
|
238
|
+
ipcMain.on('*', (event, ...args) => {
|
|
239
|
+
console.log('IPC:', event.channel, args);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Network Monitoring
|
|
244
|
+
|
|
245
|
+
Use DevTools Network tab to check:
|
|
246
|
+
- No unexpected network requests
|
|
247
|
+
- All local resources load correctly
|
|
248
|
+
|
|
249
|
+
## Known Issues
|
|
250
|
+
|
|
251
|
+
### macOS
|
|
252
|
+
- Mission Control may show overlay briefly when switching spaces
|
|
253
|
+
- Some fullscreen games might not be covered by overlay
|
|
254
|
+
- Accessibility permissions required for synthetic input
|
|
255
|
+
|
|
256
|
+
### Windows
|
|
257
|
+
- Exclusive fullscreen games not covered
|
|
258
|
+
- Some UWP apps may be above overlay
|
|
259
|
+
- Windows Defender SmartScreen may flag first run
|
|
260
|
+
|
|
261
|
+
### General
|
|
262
|
+
- High DPI displays may need scaling adjustments
|
|
263
|
+
- Multiple displays require per-display dot generation
|
|
264
|
+
- Very large screens (> 4K) may need coarser grid
|
|
265
|
+
|
|
266
|
+
## Reporting Issues
|
|
267
|
+
|
|
268
|
+
When reporting issues, include:
|
|
269
|
+
1. Operating system and version
|
|
270
|
+
2. Electron version (`npm list electron`)
|
|
271
|
+
3. Steps to reproduce
|
|
272
|
+
4. Expected vs actual behavior
|
|
273
|
+
5. Console logs (DevTools + terminal)
|
|
274
|
+
6. Screenshots if applicable
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "copilot-liku-cli",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "GitHub Copilot CLI with headless agent + ultra-thin overlay architecture",
|
|
5
|
+
"main": "src/main/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"liku": "./src/cli/liku.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "node scripts/start.js",
|
|
11
|
+
"test": "node scripts/test-grid.js",
|
|
12
|
+
"test:ui": "node scripts/test-ui-automation-baseline.js",
|
|
13
|
+
"liku": "node src/cli/liku.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"copilot",
|
|
17
|
+
"electron",
|
|
18
|
+
"overlay",
|
|
19
|
+
"agent",
|
|
20
|
+
"cli",
|
|
21
|
+
"automation",
|
|
22
|
+
"ui-automation",
|
|
23
|
+
"ai"
|
|
24
|
+
],
|
|
25
|
+
"author": "GitHub",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/TayDa64/copilot-Liku-cli.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/TayDa64/copilot-Liku-cli/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/TayDa64/copilot-Liku-cli#readme",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=22.0.0",
|
|
37
|
+
"npm": ">=10.0.0"
|
|
38
|
+
},
|
|
39
|
+
"os": [
|
|
40
|
+
"darwin",
|
|
41
|
+
"win32",
|
|
42
|
+
"linux"
|
|
43
|
+
],
|
|
44
|
+
"files": [
|
|
45
|
+
"src/",
|
|
46
|
+
"scripts/start.js",
|
|
47
|
+
"README.md",
|
|
48
|
+
"LICENSE.md",
|
|
49
|
+
"QUICKSTART.md",
|
|
50
|
+
"INSTALLATION.md",
|
|
51
|
+
"CONTRIBUTING.md",
|
|
52
|
+
"ARCHITECTURE.md",
|
|
53
|
+
"CONFIGURATION.md",
|
|
54
|
+
"TESTING.md",
|
|
55
|
+
"ELECTRON_README.md",
|
|
56
|
+
"PROJECT_STATUS.md"
|
|
57
|
+
],
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"electron": "^35.7.5"
|
|
60
|
+
}
|
|
61
|
+
}
|
package/scripts/start.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const { spawn } = require('child_process');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// Copy environment and force Electron to run with its GUI
|
|
5
|
+
const env = { ...process.env };
|
|
6
|
+
|
|
7
|
+
if (env.ELECTRON_RUN_AS_NODE) {
|
|
8
|
+
console.warn('Clearing ELECTRON_RUN_AS_NODE before launching Electron GUI.');
|
|
9
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// The electron package exports the path to the binary when required from Node
|
|
13
|
+
const electronPath = require('electron');
|
|
14
|
+
const appDir = path.resolve(__dirname, '..');
|
|
15
|
+
|
|
16
|
+
const child = spawn(electronPath, ['.'], {
|
|
17
|
+
cwd: appDir,
|
|
18
|
+
env,
|
|
19
|
+
stdio: 'inherit',
|
|
20
|
+
windowsHide: false
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
child.on('exit', (code, signal) => {
|
|
24
|
+
if (signal) {
|
|
25
|
+
console.log(`Electron exited via signal ${signal}`);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
} else {
|
|
28
|
+
process.exit(code ?? 0);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
Binary file
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent CLI Command
|
|
3
|
+
*
|
|
4
|
+
* CLI interface for the multi-agent system.
|
|
5
|
+
* Supports spawning agents, running tasks, and managing state.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* agent spawn supervisor - Spawn supervisor agent
|
|
9
|
+
* agent run <task> - Run task through orchestrator
|
|
10
|
+
* agent status - Show agent system status
|
|
11
|
+
* agent reset - Reset all agents
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
|
|
16
|
+
// Lazy load to avoid circular dependencies
|
|
17
|
+
let agentSystem = null;
|
|
18
|
+
let orchestrator = null;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create an AI service adapter that wraps the existing ai-service.js
|
|
22
|
+
* to provide the interface expected by the agent system
|
|
23
|
+
*/
|
|
24
|
+
function createAIServiceAdapter() {
|
|
25
|
+
try {
|
|
26
|
+
const aiServiceModule = require('../../main/ai-service');
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
// Adapter method: agents call chat(), we call sendMessage()
|
|
30
|
+
chat: async (message, options = {}) => {
|
|
31
|
+
const result = await aiServiceModule.sendMessage(message, {
|
|
32
|
+
includeVisualContext: options.includeVisual || false
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
if (!result.success) {
|
|
36
|
+
throw new Error(result.error || 'AI service call failed');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
text: result.message,
|
|
41
|
+
provider: result.provider,
|
|
42
|
+
success: true
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
// Pass through other methods
|
|
47
|
+
getStatus: aiServiceModule.getStatus,
|
|
48
|
+
setProvider: aiServiceModule.setProvider,
|
|
49
|
+
getCurrentCopilotModel: aiServiceModule.getCurrentCopilotModel,
|
|
50
|
+
addVisualContext: aiServiceModule.addVisualContext
|
|
51
|
+
};
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.warn('AI service not available:', e.message);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function getOrchestrator() {
|
|
59
|
+
if (!orchestrator) {
|
|
60
|
+
const { createAgentSystem } = require('../../main/agents');
|
|
61
|
+
|
|
62
|
+
// Create AI service adapter
|
|
63
|
+
const aiService = createAIServiceAdapter();
|
|
64
|
+
|
|
65
|
+
if (!aiService) {
|
|
66
|
+
console.warn('AI service adapter not available, agents will have limited capability');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
orchestrator = createAgentSystem({
|
|
70
|
+
aiService,
|
|
71
|
+
statePath: path.join(process.cwd(), '.github', 'agent_state.json'),
|
|
72
|
+
maxRecursionDepth: 3,
|
|
73
|
+
maxSubCalls: 10,
|
|
74
|
+
enableLongContext: true
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Setup event listeners
|
|
78
|
+
orchestrator.on('agent:log', (entry) => {
|
|
79
|
+
console.log(`[${entry.role}] ${entry.message}`);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
orchestrator.on('handoff:execute', (handoff) => {
|
|
83
|
+
console.log(`ā Handoff: ${handoff.from} ā ${handoff.to}`);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
orchestrator.on('task:complete', ({ task, result }) => {
|
|
87
|
+
console.log(`ā Task completed: ${result.success ? 'SUCCESS' : 'FAILED'}`);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return orchestrator;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ===== CLI Commands =====
|
|
95
|
+
|
|
96
|
+
async function handleSpawn(args) {
|
|
97
|
+
const [agentType] = args;
|
|
98
|
+
const validTypes = ['supervisor', 'builder', 'verifier', 'researcher'];
|
|
99
|
+
|
|
100
|
+
if (!agentType || !validTypes.includes(agentType.toLowerCase())) {
|
|
101
|
+
console.log('Usage: agent spawn <supervisor|builder|verifier|researcher>');
|
|
102
|
+
console.log('\nAvailable agents:');
|
|
103
|
+
console.log(' supervisor - Orchestrates tasks, decomposes plans');
|
|
104
|
+
console.log(' builder - Implements code changes');
|
|
105
|
+
console.log(' verifier - Validates changes');
|
|
106
|
+
console.log(' researcher - Gathers context and information');
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const orch = getOrchestrator();
|
|
111
|
+
const agent = orch.getAgent(agentType.toLowerCase());
|
|
112
|
+
|
|
113
|
+
if (agent) {
|
|
114
|
+
console.log(`ā ${agentType} agent ready`);
|
|
115
|
+
console.log(` ID: ${agent.id}`);
|
|
116
|
+
console.log(` Capabilities: ${agent.capabilities.join(', ')}`);
|
|
117
|
+
} else {
|
|
118
|
+
console.error(`ā Failed to spawn ${agentType} agent`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function handleRun(args) {
|
|
123
|
+
const task = args.join(' ');
|
|
124
|
+
|
|
125
|
+
if (!task) {
|
|
126
|
+
console.log('Usage: agent run <task description>');
|
|
127
|
+
console.log('\nExample:');
|
|
128
|
+
console.log(' agent run "Add error handling to the login function"');
|
|
129
|
+
console.log(' agent run "Research how authentication is implemented"');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
console.log(`\nš¤ Starting multi-agent task...`);
|
|
134
|
+
console.log(`Task: ${task}\n`);
|
|
135
|
+
|
|
136
|
+
const orch = getOrchestrator();
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
const result = await orch.orchestrate(task);
|
|
140
|
+
|
|
141
|
+
console.log('\n' + '='.repeat(50));
|
|
142
|
+
console.log('RESULT');
|
|
143
|
+
console.log('='.repeat(50));
|
|
144
|
+
|
|
145
|
+
if (result.success) {
|
|
146
|
+
console.log('ā Task completed successfully');
|
|
147
|
+
|
|
148
|
+
if (result.result?.summary) {
|
|
149
|
+
console.log('\nSummary:');
|
|
150
|
+
console.log(JSON.stringify(result.result.summary, null, 2));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (result.result?.diffs?.length > 0) {
|
|
154
|
+
console.log(`\nChanges: ${result.result.diffs.length} files modified`);
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
console.log('ā Task failed');
|
|
158
|
+
console.log(`Error: ${result.error || result.result?.error || 'Unknown error'}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
console.log(`\nHandoffs: ${result.handoffs?.length || 0}`);
|
|
162
|
+
console.log(`Session: ${result.session}`);
|
|
163
|
+
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error(`ā Error: ${error.message}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function handleStatus() {
|
|
170
|
+
const orch = getOrchestrator();
|
|
171
|
+
const state = orch.getState();
|
|
172
|
+
const stats = orch.getStats();
|
|
173
|
+
|
|
174
|
+
console.log('\nš¤ Multi-Agent System Status\n');
|
|
175
|
+
|
|
176
|
+
console.log('Session:');
|
|
177
|
+
if (state.session) {
|
|
178
|
+
console.log(` ID: ${state.session.id}`);
|
|
179
|
+
console.log(` Started: ${state.session.startedAt}`);
|
|
180
|
+
console.log(` Tasks: ${state.session.tasks?.length || 0}`);
|
|
181
|
+
console.log(` Handoffs: ${state.session.handoffs?.length || 0}`);
|
|
182
|
+
} else {
|
|
183
|
+
console.log(' No active session');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
console.log('\nAgents:');
|
|
187
|
+
for (const { role, state: agentState } of state.agents) {
|
|
188
|
+
console.log(` ${role}:`);
|
|
189
|
+
console.log(` Depth: ${agentState.currentDepth}/${agentState.maxRecursionDepth || 3}`);
|
|
190
|
+
console.log(` Sub-calls: ${agentState.subCallCount}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
console.log('\nStatistics:');
|
|
194
|
+
console.log(` Sessions: ${stats.sessions}`);
|
|
195
|
+
console.log(` Completed: ${stats.tasksCompleted}`);
|
|
196
|
+
console.log(` Failed: ${stats.tasksFailed}`);
|
|
197
|
+
console.log(` In Progress: ${stats.tasksInProgress}`);
|
|
198
|
+
console.log(` Queued: ${stats.tasksQueued}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function handleReset() {
|
|
202
|
+
const orch = getOrchestrator();
|
|
203
|
+
orch.reset();
|
|
204
|
+
console.log('ā Agent system reset');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async function handleResearch(args) {
|
|
208
|
+
const query = args.join(' ');
|
|
209
|
+
|
|
210
|
+
if (!query) {
|
|
211
|
+
console.log('Usage: agent research <query>');
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log(`\nš Researching: ${query}\n`);
|
|
216
|
+
|
|
217
|
+
const orch = getOrchestrator();
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
const result = await orch.research(query);
|
|
221
|
+
|
|
222
|
+
if (result.success && result.result?.findings) {
|
|
223
|
+
console.log('\nFindings:');
|
|
224
|
+
console.log(result.result.findings);
|
|
225
|
+
|
|
226
|
+
if (result.result.sources?.length > 0) {
|
|
227
|
+
console.log('\nSources:');
|
|
228
|
+
result.result.sources.forEach(s => console.log(` - ${s}`));
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
console.log('ā Research failed');
|
|
232
|
+
console.log(result.error || 'No findings');
|
|
233
|
+
}
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error(`ā Error: ${error.message}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
async function handleVerify(args) {
|
|
240
|
+
console.log('\nā Running verification pipeline...\n');
|
|
241
|
+
|
|
242
|
+
const orch = getOrchestrator();
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const result = await orch.verify([], {
|
|
246
|
+
includeE2E: args.includes('--e2e'),
|
|
247
|
+
continueOnFailure: args.includes('--continue')
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
if (result.success) {
|
|
251
|
+
console.log('ā All verifications passed');
|
|
252
|
+
} else {
|
|
253
|
+
console.log('ā Verification failed');
|
|
254
|
+
|
|
255
|
+
if (result.result?.verdict?.suggestions) {
|
|
256
|
+
console.log('\nSuggestions:');
|
|
257
|
+
result.result.verdict.suggestions.forEach(s => console.log(` - ${s}`));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (result.result?.results) {
|
|
262
|
+
console.log('\nPhase Results:');
|
|
263
|
+
result.result.results.forEach(r => {
|
|
264
|
+
const status = r.passed ? 'ā' : (r.skipped ? '-' : 'ā');
|
|
265
|
+
console.log(` ${status} ${r.phase}`);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error(`ā Error: ${error.message}`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ===== Main Entry Point =====
|
|
274
|
+
|
|
275
|
+
async function main(args = []) {
|
|
276
|
+
const [command, ...rest] = args;
|
|
277
|
+
|
|
278
|
+
if (!command) {
|
|
279
|
+
console.log('Copilot-Liku Multi-Agent System');
|
|
280
|
+
console.log('================================\n');
|
|
281
|
+
console.log('Commands:');
|
|
282
|
+
console.log(' spawn <type> - Spawn an agent (supervisor/builder/verifier/researcher)');
|
|
283
|
+
console.log(' run <task> - Run a task through the orchestrator');
|
|
284
|
+
console.log(' research <query> - Research a topic');
|
|
285
|
+
console.log(' verify - Run verification pipeline');
|
|
286
|
+
console.log(' status - Show system status');
|
|
287
|
+
console.log(' reset - Reset all agents');
|
|
288
|
+
console.log('\nExamples:');
|
|
289
|
+
console.log(' agent spawn supervisor');
|
|
290
|
+
console.log(' agent run "Add input validation to user form"');
|
|
291
|
+
console.log(' agent research "How is authentication handled?"');
|
|
292
|
+
console.log(' agent verify --e2e');
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
switch (command.toLowerCase()) {
|
|
297
|
+
case 'spawn':
|
|
298
|
+
await handleSpawn(rest);
|
|
299
|
+
break;
|
|
300
|
+
case 'run':
|
|
301
|
+
await handleRun(rest);
|
|
302
|
+
break;
|
|
303
|
+
case 'research':
|
|
304
|
+
await handleResearch(rest);
|
|
305
|
+
break;
|
|
306
|
+
case 'verify':
|
|
307
|
+
await handleVerify(rest);
|
|
308
|
+
break;
|
|
309
|
+
case 'status':
|
|
310
|
+
await handleStatus();
|
|
311
|
+
break;
|
|
312
|
+
case 'reset':
|
|
313
|
+
await handleReset();
|
|
314
|
+
break;
|
|
315
|
+
default:
|
|
316
|
+
console.log(`Unknown command: ${command}`);
|
|
317
|
+
console.log('Run "agent" without arguments for help');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Export for use as module
|
|
322
|
+
module.exports = { main, getOrchestrator };
|
|
323
|
+
|
|
324
|
+
// Run if called directly
|
|
325
|
+
if (require.main === module) {
|
|
326
|
+
main(process.argv.slice(2));
|
|
327
|
+
}
|