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.
- package/QUICKSTART.md +24 -0
- package/README.md +85 -33
- package/package.json +23 -14
- package/scripts/postinstall.js +63 -0
- package/src/cli/commands/window.js +66 -0
- package/src/main/agents/base-agent.js +15 -7
- package/src/main/agents/builder.js +211 -0
- package/src/main/agents/index.js +7 -4
- package/src/main/agents/orchestrator.js +13 -0
- package/src/main/agents/producer.js +891 -0
- package/src/main/agents/researcher.js +78 -0
- package/src/main/agents/state-manager.js +134 -2
- package/src/main/agents/verifier.js +201 -0
- package/src/main/ai-service.js +349 -35
- package/src/main/index.js +702 -113
- package/src/main/inspect-service.js +24 -1
- package/src/main/python-bridge.js +395 -0
- package/src/main/system-automation.js +876 -131
- package/src/main/ui-automation/core/ui-provider.js +99 -0
- package/src/main/ui-automation/core/uia-host.js +214 -0
- package/src/main/ui-automation/index.js +30 -0
- package/src/main/ui-automation/interactions/element-click.js +6 -6
- package/src/main/ui-automation/interactions/high-level.js +28 -6
- package/src/main/ui-automation/interactions/index.js +21 -0
- package/src/main/ui-automation/interactions/pattern-actions.js +236 -0
- package/src/main/ui-automation/window/index.js +6 -0
- package/src/main/ui-automation/window/manager.js +173 -26
- package/src/main/ui-watcher.js +401 -58
- package/src/main/visual-awareness.js +18 -1
- package/src/native/windows-uia/Program.cs +89 -0
- package/src/native/windows-uia/build.ps1 +24 -0
- package/src/native/windows-uia-dotnet/Program.cs +920 -0
- package/src/native/windows-uia-dotnet/WindowsUIA.csproj +11 -0
- package/src/native/windows-uia-dotnet/build.ps1 +24 -0
- package/src/renderer/chat/chat.js +915 -671
- package/src/renderer/chat/index.html +2 -4
- package/src/renderer/chat/preload.js +8 -1
- package/src/renderer/overlay/overlay.js +157 -8
- package/src/renderer/overlay/preload.js +4 -0
- package/src/shared/inspect-types.js +82 -6
- package/ARCHITECTURE.md +0 -411
- package/CONFIGURATION.md +0 -302
- package/CONTRIBUTING.md +0 -225
- package/ELECTRON_README.md +0 -121
- package/PROJECT_STATUS.md +0 -229
- 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 };
|
package/src/main/agents/index.js
CHANGED
|
@@ -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 =
|
|
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:
|
|
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
|
-
|
|
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() {
|