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,452 @@
1
+ /**
2
+ * Verifier Agent
3
+ *
4
+ * Runs phased verification on Builder changes and returns proofs plus pass/fail verdict.
5
+ * READ-ONLY: Does not edit files.
6
+ *
7
+ * Operating Rules:
8
+ * - Verify based on provided diffs/outputs; do not speculate
9
+ * - Prefer smallest, most relevant checks first, then broaden
10
+ * - Phased verification: Lint → Build → Unit → Integration → E2E
11
+ */
12
+
13
+ const { BaseAgent, AgentRole, AgentCapabilities } = require('./base-agent');
14
+
15
+ class VerifierAgent extends BaseAgent {
16
+ constructor(options = {}) {
17
+ super({
18
+ ...options,
19
+ role: AgentRole.VERIFIER,
20
+ name: options.name || 'verifier',
21
+ description: 'Validates changes with phased verification pipeline',
22
+ capabilities: [
23
+ AgentCapabilities.SEARCH,
24
+ AgentCapabilities.READ,
25
+ AgentCapabilities.EXECUTE,
26
+ AgentCapabilities.TODO,
27
+ AgentCapabilities.HANDOFF
28
+ ]
29
+ // NOTE: No EDIT capability - Verifier is read-only
30
+ });
31
+
32
+ // Verifier-specific state
33
+ this.verificationResults = [];
34
+ this.currentPhase = null;
35
+ this.verdict = null;
36
+ }
37
+
38
+ getSystemPrompt() {
39
+ return `You are the VERIFIER agent in a multi-agent coding system.
40
+
41
+ # OPERATING CONTRACT (NON-NEGOTIABLE)
42
+ - **No guessing**: Verify based on provided changes only.
43
+ - **Preserve functionalities**: Read-only; no edits.
44
+ - **Modularity & robustness**: Phase-based verification.
45
+ - **Least privilege**: Read-only access only.
46
+ - **Recursion limits**: Depth ≤3; avoid >10 sub-calls without progress.
47
+ - **Security**: Check invariants/regressions; fail on issues.
48
+ - **Background hygiene**: PID-track long-running tests.
49
+
50
+ # YOUR RESPONSIBILITIES
51
+ 1. Receive changes from Builder/Supervisor
52
+ 2. Run verification pipeline sequentially
53
+ 3. Provide proofs/logs for each phase
54
+ 4. Issue verdict: Pass/fail + suggestions
55
+ 5. Hand off back to Supervisor
56
+
57
+ # VERIFICATION PIPELINE
58
+ Phase 1: LINT - ESLint/Prettier/code style
59
+ Phase 2: BUILD - Compilation/bundling
60
+ Phase 3: UNIT TESTS - Framework-specific unit tests
61
+ Phase 4: INTEGRATION - API tests, service integration
62
+ Phase 5: E2E - Playwright/Cypress end-to-end (optional)
63
+
64
+ # OUTPUT FORMAT
65
+ Always structure your response as:
66
+ 1. Phase: [current phase]
67
+ 2. Command: [what was run]
68
+ 3. Result: [pass/fail]
69
+ 4. Output: [relevant logs]
70
+ 5. Issues: [any problems found]
71
+ 6. Verdict: [overall pass/fail]
72
+ 7. Suggestions: [if failed, what to fix]`;
73
+ }
74
+
75
+ async process(task, context = {}) {
76
+ this.log('info', 'Verifier processing task', { task: task.description || task });
77
+
78
+ // Check recursion limits
79
+ const limits = this.checkRecursionLimits();
80
+ if (!limits.allowed) {
81
+ return {
82
+ success: false,
83
+ error: limits.reason,
84
+ phase: 'pre-check'
85
+ };
86
+ }
87
+
88
+ try {
89
+ this.enterRecursion();
90
+
91
+ // Extract changes to verify
92
+ const changes = context.diffs || context.changes || [];
93
+ const changedFiles = changes.map(c => c.file).filter(Boolean);
94
+
95
+ // Run verification pipeline
96
+ const results = await this.runVerificationPipeline(changedFiles, context);
97
+
98
+ // Compile verdict
99
+ const verdict = this.compileVerdict(results);
100
+ this.verdict = verdict;
101
+
102
+ this.exitRecursion();
103
+
104
+ return {
105
+ success: verdict.passed,
106
+ verdict,
107
+ results: this.verificationResults,
108
+ suggestedNext: verdict.passed ? 'complete' : 'supervisor',
109
+ suggestions: verdict.suggestions
110
+ };
111
+
112
+ } catch (error) {
113
+ this.exitRecursion();
114
+ return {
115
+ success: false,
116
+ error: error.message,
117
+ phase: this.currentPhase,
118
+ partialResults: this.verificationResults
119
+ };
120
+ }
121
+ }
122
+
123
+ async runVerificationPipeline(changedFiles, context) {
124
+ const phases = [
125
+ { name: 'lint', fn: () => this.runLint(changedFiles) },
126
+ { name: 'build', fn: () => this.runBuild() },
127
+ { name: 'unit', fn: () => this.runUnitTests(changedFiles) },
128
+ { name: 'integration', fn: () => this.runIntegrationTests(context) },
129
+ // E2E is optional and expensive - only run if explicitly requested
130
+ ...(context.includeE2E ? [{ name: 'e2e', fn: () => this.runE2ETests(context) }] : [])
131
+ ];
132
+
133
+ const results = [];
134
+
135
+ for (const phase of phases) {
136
+ this.currentPhase = phase.name;
137
+ this.log('info', `Starting verification phase: ${phase.name}`);
138
+
139
+ try {
140
+ const result = await phase.fn();
141
+ results.push({
142
+ phase: phase.name,
143
+ ...result,
144
+ timestamp: new Date().toISOString()
145
+ });
146
+
147
+ this.verificationResults.push(result);
148
+
149
+ // Stop on first failure unless told to continue
150
+ if (!result.passed && !context.continueOnFailure) {
151
+ this.log('warn', `Phase ${phase.name} failed, stopping pipeline`);
152
+ break;
153
+ }
154
+
155
+ } catch (error) {
156
+ results.push({
157
+ phase: phase.name,
158
+ passed: false,
159
+ error: error.message,
160
+ timestamp: new Date().toISOString()
161
+ });
162
+
163
+ if (!context.continueOnFailure) {
164
+ break;
165
+ }
166
+ }
167
+ }
168
+
169
+ return results;
170
+ }
171
+
172
+ async runLint(changedFiles) {
173
+ this.log('info', 'Running lint verification');
174
+
175
+ const commands = [
176
+ 'npm run lint --if-present 2>&1',
177
+ 'npx eslint --ext .js,.ts,.jsx,.tsx . 2>&1 || true',
178
+ 'npx prettier --check . 2>&1 || true'
179
+ ];
180
+
181
+ const outputs = [];
182
+ let passed = true;
183
+ const issues = [];
184
+
185
+ for (const cmd of commands) {
186
+ try {
187
+ const result = await this.execute(cmd, { timeout: 60000 });
188
+ outputs.push({
189
+ command: cmd,
190
+ output: result.stdout,
191
+ error: result.stderr
192
+ });
193
+
194
+ if (result.stderr?.includes('error') || result.stdout?.includes('error')) {
195
+ passed = false;
196
+ issues.push(this.extractLintIssues(result.stdout || result.stderr));
197
+ }
198
+ } catch (error) {
199
+ // Lint commands may exit non-zero, that's okay
200
+ outputs.push({ command: cmd, error: error.message });
201
+ }
202
+ }
203
+
204
+ this.addProof('lint', JSON.stringify(outputs).slice(0, 1000));
205
+
206
+ return {
207
+ phase: 'lint',
208
+ passed,
209
+ outputs,
210
+ issues: issues.flat()
211
+ };
212
+ }
213
+
214
+ extractLintIssues(output) {
215
+ const issues = [];
216
+ const lines = output.split('\n');
217
+
218
+ for (const line of lines) {
219
+ if (/error|warning/i.test(line) && line.includes(':')) {
220
+ issues.push(line.trim());
221
+ }
222
+ }
223
+
224
+ return issues.slice(0, 20); // Limit to first 20 issues
225
+ }
226
+
227
+ async runBuild() {
228
+ this.log('info', 'Running build verification');
229
+
230
+ const buildCommands = [
231
+ 'npm run build --if-present 2>&1',
232
+ 'npx tsc --noEmit 2>&1 || true'
233
+ ];
234
+
235
+ let passed = true;
236
+ const outputs = [];
237
+ const errors = [];
238
+
239
+ for (const cmd of buildCommands) {
240
+ try {
241
+ const result = await this.execute(cmd, { timeout: 120000 });
242
+ outputs.push({
243
+ command: cmd,
244
+ output: result.stdout?.slice(0, 2000),
245
+ exitCode: result.success ? 0 : 1
246
+ });
247
+
248
+ if (!result.success || result.stderr?.includes('error')) {
249
+ passed = false;
250
+ errors.push(result.stderr || result.stdout);
251
+ }
252
+ } catch (error) {
253
+ outputs.push({ command: cmd, error: error.message });
254
+ passed = false;
255
+ errors.push(error.message);
256
+ }
257
+ }
258
+
259
+ this.addProof('build', passed ? 'Build passed' : errors.join('\n').slice(0, 500));
260
+
261
+ return {
262
+ phase: 'build',
263
+ passed,
264
+ outputs,
265
+ errors
266
+ };
267
+ }
268
+
269
+ async runUnitTests(changedFiles) {
270
+ this.log('info', 'Running unit test verification');
271
+
272
+ // Determine test framework
273
+ let testCommand = 'npm test 2>&1';
274
+
275
+ // If specific files changed, try to run only related tests
276
+ if (changedFiles.length > 0 && changedFiles.length < 10) {
277
+ const testPatterns = changedFiles
278
+ .map(f => f.replace(/\.(js|ts|jsx|tsx)$/, ''))
279
+ .join('|');
280
+ testCommand = `npm test -- --testPathPattern="${testPatterns}" 2>&1 || npm test 2>&1`;
281
+ }
282
+
283
+ try {
284
+ const result = await this.execute(testCommand, { timeout: 180000 });
285
+
286
+ const passed = result.success &&
287
+ (result.stdout?.includes('passed') || !result.stdout?.includes('failed'));
288
+
289
+ const testCounts = this.parseTestOutput(result.stdout || '');
290
+
291
+ this.addProof('unit-tests',
292
+ `${testCounts.passed} passed, ${testCounts.failed} failed`
293
+ );
294
+
295
+ return {
296
+ phase: 'unit',
297
+ passed,
298
+ output: result.stdout?.slice(0, 3000),
299
+ testCounts,
300
+ errors: result.stderr
301
+ };
302
+ } catch (error) {
303
+ return {
304
+ phase: 'unit',
305
+ passed: false,
306
+ error: error.message,
307
+ testCounts: { passed: 0, failed: 0, skipped: 0 }
308
+ };
309
+ }
310
+ }
311
+
312
+ parseTestOutput(output) {
313
+ const counts = { passed: 0, failed: 0, skipped: 0 };
314
+
315
+ // Jest format
316
+ const jestMatch = output.match(/(\d+) passed.*?(\d+) failed/);
317
+ if (jestMatch) {
318
+ counts.passed = parseInt(jestMatch[1]) || 0;
319
+ counts.failed = parseInt(jestMatch[2]) || 0;
320
+ }
321
+
322
+ // Mocha format
323
+ const mochaMatch = output.match(/(\d+) passing.*?(\d+) failing/);
324
+ if (mochaMatch) {
325
+ counts.passed = parseInt(mochaMatch[1]) || 0;
326
+ counts.failed = parseInt(mochaMatch[2]) || 0;
327
+ }
328
+
329
+ return counts;
330
+ }
331
+
332
+ async runIntegrationTests(context) {
333
+ this.log('info', 'Running integration test verification');
334
+
335
+ // Check if integration tests exist
336
+ const integrationCommands = [
337
+ 'npm run test:integration --if-present 2>&1',
338
+ 'npm run test:api --if-present 2>&1'
339
+ ];
340
+
341
+ let ranAny = false;
342
+ let passed = true;
343
+ const outputs = [];
344
+
345
+ for (const cmd of integrationCommands) {
346
+ try {
347
+ const result = await this.execute(cmd, { timeout: 300000 });
348
+
349
+ if (!result.stdout?.includes('No integration tests')) {
350
+ ranAny = true;
351
+ outputs.push({
352
+ command: cmd,
353
+ output: result.stdout?.slice(0, 2000),
354
+ passed: result.success
355
+ });
356
+
357
+ if (!result.success) {
358
+ passed = false;
359
+ }
360
+ }
361
+ } catch (error) {
362
+ // Integration tests may not exist
363
+ }
364
+ }
365
+
366
+ return {
367
+ phase: 'integration',
368
+ passed: ranAny ? passed : true,
369
+ skipped: !ranAny,
370
+ outputs
371
+ };
372
+ }
373
+
374
+ async runE2ETests(context) {
375
+ this.log('info', 'Running E2E test verification');
376
+
377
+ // Playwright E2E
378
+ try {
379
+ // Start with critical path only
380
+ const result = await this.execute(
381
+ 'npx playwright test --grep "critical-path" 2>&1 || npx playwright test 2>&1',
382
+ { timeout: 600000 }
383
+ );
384
+
385
+ const passed = result.success && !result.stdout?.includes('failed');
386
+
387
+ this.addProof('e2e', passed ? 'E2E passed' : 'E2E failed');
388
+
389
+ return {
390
+ phase: 'e2e',
391
+ passed,
392
+ output: result.stdout?.slice(0, 3000),
393
+ traceAvailable: result.stdout?.includes('trace')
394
+ };
395
+ } catch (error) {
396
+ return {
397
+ phase: 'e2e',
398
+ passed: false,
399
+ error: error.message
400
+ };
401
+ }
402
+ }
403
+
404
+ compileVerdict(results) {
405
+ const allPassed = results.every(r => r.passed || r.skipped);
406
+ const failedPhases = results.filter(r => !r.passed && !r.skipped);
407
+
408
+ const suggestions = [];
409
+
410
+ for (const failed of failedPhases) {
411
+ switch (failed.phase) {
412
+ case 'lint':
413
+ suggestions.push('Fix linting errors before proceeding');
414
+ break;
415
+ case 'build':
416
+ suggestions.push('Resolve build/compilation errors');
417
+ break;
418
+ case 'unit':
419
+ suggestions.push('Fix failing unit tests');
420
+ break;
421
+ case 'integration':
422
+ suggestions.push('Address integration test failures');
423
+ break;
424
+ case 'e2e':
425
+ suggestions.push('Review E2E test failures, check traces');
426
+ break;
427
+ }
428
+ }
429
+
430
+ return {
431
+ passed: allPassed,
432
+ summary: {
433
+ total: results.length,
434
+ passed: results.filter(r => r.passed).length,
435
+ failed: failedPhases.length,
436
+ skipped: results.filter(r => r.skipped).length
437
+ },
438
+ failedPhases: failedPhases.map(f => f.phase),
439
+ suggestions,
440
+ timestamp: new Date().toISOString()
441
+ };
442
+ }
443
+
444
+ reset() {
445
+ super.reset();
446
+ this.verificationResults = [];
447
+ this.currentPhase = null;
448
+ this.verdict = null;
449
+ }
450
+ }
451
+
452
+ module.exports = { VerifierAgent };