copilot-liku-cli 0.0.3 → 0.0.8

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 (46) hide show
  1. package/QUICKSTART.md +24 -0
  2. package/README.md +85 -33
  3. package/package.json +23 -14
  4. package/scripts/postinstall.js +63 -0
  5. package/src/cli/commands/window.js +66 -0
  6. package/src/main/agents/base-agent.js +15 -7
  7. package/src/main/agents/builder.js +211 -0
  8. package/src/main/agents/index.js +7 -4
  9. package/src/main/agents/orchestrator.js +13 -0
  10. package/src/main/agents/producer.js +891 -0
  11. package/src/main/agents/researcher.js +78 -0
  12. package/src/main/agents/state-manager.js +134 -2
  13. package/src/main/agents/verifier.js +201 -0
  14. package/src/main/ai-service.js +349 -35
  15. package/src/main/index.js +702 -113
  16. package/src/main/inspect-service.js +24 -1
  17. package/src/main/python-bridge.js +395 -0
  18. package/src/main/system-automation.js +876 -131
  19. package/src/main/ui-automation/core/ui-provider.js +99 -0
  20. package/src/main/ui-automation/core/uia-host.js +214 -0
  21. package/src/main/ui-automation/index.js +30 -0
  22. package/src/main/ui-automation/interactions/element-click.js +6 -6
  23. package/src/main/ui-automation/interactions/high-level.js +28 -6
  24. package/src/main/ui-automation/interactions/index.js +21 -0
  25. package/src/main/ui-automation/interactions/pattern-actions.js +236 -0
  26. package/src/main/ui-automation/window/index.js +6 -0
  27. package/src/main/ui-automation/window/manager.js +173 -26
  28. package/src/main/ui-watcher.js +401 -58
  29. package/src/main/visual-awareness.js +18 -1
  30. package/src/native/windows-uia/Program.cs +89 -0
  31. package/src/native/windows-uia/build.ps1 +24 -0
  32. package/src/native/windows-uia-dotnet/Program.cs +920 -0
  33. package/src/native/windows-uia-dotnet/WindowsUIA.csproj +11 -0
  34. package/src/native/windows-uia-dotnet/build.ps1 +24 -0
  35. package/src/renderer/chat/chat.js +915 -671
  36. package/src/renderer/chat/index.html +2 -4
  37. package/src/renderer/chat/preload.js +8 -1
  38. package/src/renderer/overlay/overlay.js +157 -8
  39. package/src/renderer/overlay/preload.js +4 -0
  40. package/src/shared/inspect-types.js +82 -6
  41. package/ARCHITECTURE.md +0 -411
  42. package/CONFIGURATION.md +0 -302
  43. package/CONTRIBUTING.md +0 -225
  44. package/ELECTRON_README.md +0 -121
  45. package/PROJECT_STATUS.md +0 -229
  46. package/TESTING.md +0 -274
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  const { BaseAgent, AgentRole, AgentCapabilities } = require('./base-agent');
15
+ const { PythonBridge } = require('../python-bridge');
15
16
  const fs = require('fs');
16
17
  const path = require('path');
17
18
 
@@ -38,6 +39,9 @@ class BuilderAgent extends BaseAgent {
38
39
  this.blockers = [];
39
40
  this.attemptCount = 0;
40
41
  this.maxAttempts = 3;
42
+
43
+ // PythonBridge for music generation (lazy init via shared singleton)
44
+ this.pythonBridge = null;
41
45
  }
42
46
 
43
47
  getSystemPrompt() {
@@ -479,6 +483,213 @@ Provide the change in unified diff format:
479
483
  this.blockers = [];
480
484
  this.attemptCount = 0;
481
485
  }
486
+
487
+ // ===== Music Generation Methods (Sprint 3 — Task 3.2) =====
488
+
489
+ /**
490
+ * Lazily initialise and start the shared PythonBridge.
491
+ * @returns {Promise<PythonBridge>}
492
+ */
493
+ async ensurePythonBridge() {
494
+ if (!this.pythonBridge) {
495
+ this.pythonBridge = PythonBridge.getShared();
496
+ }
497
+ if (!this.pythonBridge.isRunning) {
498
+ const alive = await this.pythonBridge.isAlive();
499
+ if (!alive) {
500
+ this.log('info', 'Starting PythonBridge for music generation');
501
+ await this.pythonBridge.start();
502
+ } else {
503
+ this.log('info', 'PythonBridge connected to existing server');
504
+ }
505
+ }
506
+ return this.pythonBridge;
507
+ }
508
+
509
+ /**
510
+ * Generate music synchronously via the Python engine.
511
+ *
512
+ * @param {string} prompt Natural-language music prompt.
513
+ * @param {object} [options] Extra params forwarded to generate_sync.
514
+ * @returns {Promise<object>} Full GenerationResult dict from the server.
515
+ */
516
+ async generateMusic(prompt, options = {}) {
517
+ await this.ensurePythonBridge();
518
+ if (options.trackProgress === undefined) {
519
+ options.trackProgress = true;
520
+ }
521
+ this.log('info', 'Generating music', { prompt, options });
522
+
523
+ const result = await this.pythonBridge.call('generate_sync', {
524
+ prompt,
525
+ ...options,
526
+ });
527
+
528
+ if (options.trackProgress && result && result.task_id) {
529
+ await this.pollProgress(result.task_id, options.progressIntervalMs, options.progressTimeoutMs);
530
+ }
531
+
532
+ this.log('info', 'Music generation complete', {
533
+ taskId: result.task_id,
534
+ success: result.success,
535
+ });
536
+
537
+ this.addStructuredProof({
538
+ type: 'music-generation',
539
+ prompt,
540
+ taskId: result.task_id,
541
+ success: result.success,
542
+ midiPath: result.midi_path || null,
543
+ });
544
+
545
+ return result;
546
+ }
547
+
548
+ /**
549
+ * Generate music from a Score Plan (Copilot orchestration).
550
+ *
551
+ * @param {object} scorePlan Score Plan dict with at least a prompt.
552
+ * @param {object} [options] Extra params forwarded to generate_sync.
553
+ * @returns {Promise<object>} Full GenerationResult dict from the server.
554
+ */
555
+ async generateMusicFromScorePlan(scorePlan, options = {}) {
556
+ await this.ensurePythonBridge();
557
+ if (options.trackProgress === undefined) {
558
+ options.trackProgress = true;
559
+ }
560
+ const planPrompt = (scorePlan && scorePlan.prompt) ? String(scorePlan.prompt) : '';
561
+ const prompt = planPrompt || options.prompt || 'Score plan generation';
562
+ this.log('info', 'Generating music from score plan', { prompt, options });
563
+
564
+ const rpcTimeoutMs = Number(options.rpcTimeoutMs || 900000);
565
+ const watchdogIntervalMs = Number(options.watchdogIntervalMs || 15000);
566
+ const callStartedAt = Date.now();
567
+ const watchdog = setInterval(() => {
568
+ const elapsedSec = Math.floor((Date.now() - callStartedAt) / 1000);
569
+ this.log('info', 'Waiting on generate_sync...', {
570
+ elapsedSec,
571
+ rpcTimeoutMs,
572
+ prompt: prompt.slice(0, 80)
573
+ });
574
+ }, watchdogIntervalMs);
575
+
576
+ let result;
577
+ try {
578
+ result = await this.pythonBridge.call('generate_sync', {
579
+ prompt,
580
+ score_plan: scorePlan,
581
+ ...options,
582
+ }, rpcTimeoutMs);
583
+ } finally {
584
+ clearInterval(watchdog);
585
+ }
586
+
587
+ if (options.trackProgress && result && result.task_id) {
588
+ await this.pollProgress(result.task_id, options.progressIntervalMs, options.progressTimeoutMs);
589
+ }
590
+
591
+ this.log('info', 'Score plan generation complete', {
592
+ taskId: result.task_id,
593
+ success: result.success,
594
+ });
595
+
596
+ this.addStructuredProof({
597
+ type: 'music-generation',
598
+ prompt,
599
+ taskId: result.task_id,
600
+ success: result.success,
601
+ midiPath: result.midi_path || null,
602
+ scorePlan: true,
603
+ });
604
+
605
+ return result;
606
+ }
607
+
608
+ /**
609
+ * Kick off an async generation with a section override.
610
+ *
611
+ * @param {string} taskId Original task to reference.
612
+ * @param {string} section Section identifier to regenerate.
613
+ * @param {object} [options]
614
+ * @returns {Promise<object>} { task_id, request_id }
615
+ */
616
+ async regenerateSection(taskId, section, options = {}) {
617
+ await this.ensurePythonBridge();
618
+ this.log('info', 'Regenerating section', { taskId, section });
619
+
620
+ const result = await this.pythonBridge.call('generate', {
621
+ prompt: options.prompt || `Regenerate section ${section}`,
622
+ section,
623
+ original_task_id: taskId,
624
+ ...options,
625
+ });
626
+
627
+ return result;
628
+ }
629
+
630
+ /**
631
+ * Poll the status of a running generation task.
632
+ *
633
+ * @param {string} taskId
634
+ * @returns {Promise<object>}
635
+ */
636
+ async getGenerationStatus(taskId) {
637
+ await this.ensurePythonBridge();
638
+ return this.pythonBridge.call('get_status', { task_id: taskId });
639
+ }
640
+
641
+ /**
642
+ * Poll progress for a task and log status for visibility.
643
+ *
644
+ * @param {string} taskId
645
+ * @param {number} [intervalMs=1000]
646
+ * @param {number} [maxMs=600000] // 10 minutes default
647
+ * @returns {Promise<object>}
648
+ */
649
+ async pollProgress(taskId, intervalMs = 1000, maxMs = 600000) {
650
+ await this.ensurePythonBridge();
651
+ const start = Date.now();
652
+ while (true) {
653
+ const status = await this.getGenerationStatus(taskId);
654
+ if (status && status.progress) {
655
+ const { step, percent, message } = status.progress;
656
+ this.log('info', 'Progress', { taskId, step, percent, message });
657
+ }
658
+ const done = status && (status.status === 'completed' || status.status === 'failed' || status.status === 'cancelled');
659
+ if (done) {
660
+ return status;
661
+ }
662
+ if (Date.now() - start > maxMs) {
663
+ this.log('warn', 'Progress polling timed out', { taskId });
664
+ return status;
665
+ }
666
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
667
+ }
668
+ }
669
+
670
+ /**
671
+ * Cancel a running generation task.
672
+ *
673
+ * @param {string} taskId
674
+ * @returns {Promise<object>}
675
+ */
676
+ async cancelGeneration(taskId) {
677
+ await this.ensurePythonBridge();
678
+ this.log('info', 'Cancelling generation', { taskId });
679
+ return this.pythonBridge.call('cancel', { task_id: taskId });
680
+ }
681
+
682
+ /**
683
+ * Stop and release the PythonBridge.
684
+ * @returns {Promise<void>}
685
+ */
686
+ async disposePythonBridge() {
687
+ if (this.pythonBridge) {
688
+ this.log('info', 'Disposing PythonBridge');
689
+ await this.pythonBridge.stop();
690
+ this.pythonBridge = null;
691
+ }
692
+ }
482
693
  }
483
694
 
484
695
  module.exports = { BuilderAgent };
@@ -15,6 +15,7 @@ const { AgentOrchestrator } = require('./orchestrator');
15
15
  const { SupervisorAgent } = require('./supervisor');
16
16
  const { BuilderAgent } = require('./builder');
17
17
  const { VerifierAgent } = require('./verifier');
18
+ const { ProducerAgent } = require('./producer');
18
19
  const { ResearcherAgent } = require('./researcher');
19
20
  const { AgentStateManager } = require('./state-manager');
20
21
 
@@ -23,14 +24,15 @@ module.exports = {
23
24
  SupervisorAgent,
24
25
  BuilderAgent,
25
26
  VerifierAgent,
27
+ ProducerAgent,
26
28
  ResearcherAgent,
27
29
  AgentStateManager,
28
30
 
29
31
  // Factory function for creating configured orchestrator
30
- createAgentSystem: (options = {}) => {
32
+ createAgentSystem: (aiService, options = {}) => {
31
33
  const stateManager = new AgentStateManager(options.statePath);
32
34
 
33
- const modelMetadata = options.aiService?.getModelMetadata?.() || null;
35
+ const modelMetadata = aiService?.getModelMetadata?.() || null;
34
36
 
35
37
  if (modelMetadata) {
36
38
  stateManager.setModelMetadata(modelMetadata);
@@ -38,14 +40,15 @@ module.exports = {
38
40
 
39
41
  const orchestrator = new AgentOrchestrator({
40
42
  stateManager,
41
- aiService: options.aiService,
43
+ aiService: aiService,
42
44
  maxRecursionDepth: options.maxRecursionDepth || 3,
43
45
  maxSubCalls: options.maxSubCalls || 10,
44
46
  enableLongContext: options.enableLongContext !== false,
45
47
  modelMetadata
46
48
  });
47
49
 
48
- return orchestrator;
50
+ // Return object with both orchestrator and stateManager
51
+ return { orchestrator, stateManager };
49
52
  },
50
53
 
51
54
  // Recovery function for checkpoint restoration
@@ -15,6 +15,7 @@ const EventEmitter = require('events');
15
15
  const { SupervisorAgent } = require('./supervisor');
16
16
  const { BuilderAgent } = require('./builder');
17
17
  const { VerifierAgent } = require('./verifier');
18
+ const { ProducerAgent } = require('./producer');
18
19
  const { ResearcherAgent } = require('./researcher');
19
20
  const { AgentStateManager } = require('./state-manager');
20
21
  const { AgentRole } = require('./base-agent');
@@ -64,6 +65,7 @@ class AgentOrchestrator extends EventEmitter {
64
65
  this.agents.set(AgentRole.BUILDER, new BuilderAgent(commonOptions));
65
66
  this.agents.set(AgentRole.VERIFIER, new VerifierAgent(commonOptions));
66
67
  this.agents.set(AgentRole.RESEARCHER, new ResearcherAgent(commonOptions));
68
+ this.agents.set(AgentRole.PRODUCER, new ProducerAgent(commonOptions));
67
69
 
68
70
  // Register agents with state manager
69
71
  for (const [role, agent] of this.agents) {
@@ -270,6 +272,10 @@ class AgentOrchestrator extends EventEmitter {
270
272
  return this.agents.get(AgentRole.RESEARCHER);
271
273
  }
272
274
 
275
+ getProducer() {
276
+ return this.agents.get(AgentRole.PRODUCER);
277
+ }
278
+
273
279
  // ===== Convenience Methods =====
274
280
 
275
281
  async research(query, options = {}) {
@@ -302,6 +308,13 @@ class AgentOrchestrator extends EventEmitter {
302
308
  });
303
309
  }
304
310
 
311
+ async produce(task, options = {}) {
312
+ return this.execute(task, {
313
+ ...options,
314
+ startAgent: AgentRole.PRODUCER
315
+ });
316
+ }
317
+
305
318
  // ===== State & Diagnostics =====
306
319
 
307
320
  getState() {