agentgui 1.0.917 → 1.0.918
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/database-schema.js +0 -58
- package/lib/db-queries-cleanup.js +0 -12
- package/lib/db-queries-del.js +0 -1
- package/lib/db-queries.js +0 -4
- package/lib/http-handler.js +1 -10
- package/lib/plugins/database-plugin.js +1 -1
- package/lib/process-message.js +2 -2
- package/lib/provider-config.js +0 -16
- package/lib/recovery.js +2 -12
- package/lib/routes-agent-actions.js +2 -58
- package/lib/routes-debug.js +1 -7
- package/lib/routes-registry.js +5 -17
- package/lib/server-startup.js +1 -59
- package/lib/stream-event-handler.js +1 -3
- package/lib/ws-handlers-session2.js +2 -23
- package/lib/ws-handlers-util.js +106 -175
- package/lib/ws-legacy-handlers.js +1 -104
- package/lib/ws-setup.js +1 -3
- package/package.json +1 -15
- package/server.js +9 -26
- package/test.js +1 -21
- package/ecosystem.config.cjs +0 -22
- package/lib/checkpoint-manager.js +0 -182
- package/lib/db-queries-tools.js +0 -131
- package/lib/db-queries-voice.js +0 -85
- package/lib/oauth-codex.js +0 -164
- package/lib/oauth-common.js +0 -92
- package/lib/oauth-gemini.js +0 -199
- package/lib/plugins/auth-plugin.js +0 -132
- package/lib/plugins/speech-plugin.js +0 -72
- package/lib/plugins/tools-plugin.js +0 -120
- package/lib/pm2-manager.js +0 -170
- package/lib/routes-oauth.js +0 -105
- package/lib/routes-speech.js +0 -173
- package/lib/routes-tools.js +0 -184
- package/lib/speech-manager.js +0 -200
- package/lib/speech.js +0 -50
- package/lib/tool-install-machine.js +0 -157
- package/lib/tool-manager.js +0 -98
- package/lib/tool-provisioner.js +0 -98
- package/lib/tool-spawner.js +0 -163
- package/lib/tool-version-check.js +0 -196
- package/lib/tool-version-fetch.js +0 -68
- package/lib/ws-handlers-oauth.js +0 -76
- package/static/js/agent-auth-oauth.js +0 -159
- package/static/js/pm2-monitor.js +0 -151
- package/static/js/stt-handler.js +0 -147
- package/static/js/tool-install-machine.js +0 -155
- package/static/js/tools-manager-ui.js +0 -124
- package/static/js/tools-manager.js +0 -172
- package/static/js/voice-machine.js +0 -145
- package/static/js/voice.js +0 -134
package/static/js/pm2-monitor.js
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
const ACTIVE_STATES = new Set(['online', 'launching', 'stopping', 'waiting restart']);
|
|
3
|
-
|
|
4
|
-
window.pm2Monitor = { processes: [], logsModalOpen: null, initialized: false };
|
|
5
|
-
|
|
6
|
-
const panel = document.getElementById('pm2MonitorPanel');
|
|
7
|
-
const list = document.getElementById('pm2ProcessList');
|
|
8
|
-
const refreshBtn = document.getElementById('pm2RefreshBtn');
|
|
9
|
-
|
|
10
|
-
function send(msg) {
|
|
11
|
-
if (window.wsManager && window.wsManager.isConnected) window.wsManager.sendMessage(msg);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function setPanelVisible(visible) {
|
|
15
|
-
if (!panel) return;
|
|
16
|
-
panel.style.display = visible ? 'flex' : 'none';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function renderProcessList(processes) {
|
|
20
|
-
if (!list) return;
|
|
21
|
-
const active = processes.filter(p => ACTIVE_STATES.has(p.status));
|
|
22
|
-
const inactive = processes.filter(p => !ACTIVE_STATES.has(p.status));
|
|
23
|
-
const ordered = [...active, ...inactive];
|
|
24
|
-
list.innerHTML = ordered.map(proc => {
|
|
25
|
-
const isActive = ACTIVE_STATES.has(proc.status);
|
|
26
|
-
const uptimeSec = proc.uptime ? Math.floor((Date.now() - proc.uptime) / 1000) : null;
|
|
27
|
-
return `<div class="pm2-process-item ${proc.status}" data-pm2-name="${escAttr(proc.name)}">
|
|
28
|
-
<div class="pm2-process-name">${escHtml(proc.name)} <span class="pm2-status-dot pm2-status-${proc.status}"></span></div>
|
|
29
|
-
<div class="pm2-process-meta">
|
|
30
|
-
<span>${proc.status}</span>
|
|
31
|
-
<span>${(proc.cpu || 0).toFixed(1)}% CPU</span>
|
|
32
|
-
<span>${fmtBytes(proc.memory)}</span>
|
|
33
|
-
${uptimeSec !== null ? `<span>${fmtUptime(uptimeSec)}</span>` : ''}
|
|
34
|
-
<span>#${proc.pid || '-'}</span>
|
|
35
|
-
${proc.restarts > 0 ? `<span>${proc.restarts}x restarts</span>` : ''}
|
|
36
|
-
</div>
|
|
37
|
-
<div class="pm2-process-actions">
|
|
38
|
-
${!isActive ? `<button class="pm2-btn" onclick="window.pm2Monitor.startProcess('${escAttr(proc.name)}')">Start</button>` : ''}
|
|
39
|
-
${proc.status === 'online' ? `<button class="pm2-btn danger" onclick="window.pm2Monitor.stopProcess('${escAttr(proc.name)}')">Stop</button>` : ''}
|
|
40
|
-
<button class="pm2-btn" onclick="window.pm2Monitor.restartProcess('${escAttr(proc.name)}')">Restart</button>
|
|
41
|
-
<button class="pm2-btn" onclick="window.pm2Monitor.showLogs('${escAttr(proc.name)}')">Logs</button>
|
|
42
|
-
<button class="pm2-btn danger" onclick="window.pm2Monitor.deleteProcess('${escAttr(proc.name)}')">Delete</button>
|
|
43
|
-
</div>
|
|
44
|
-
</div>`;
|
|
45
|
-
}).join('');
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function handleMessage(msg) {
|
|
49
|
-
if (msg.type === 'pm2_monit_update') {
|
|
50
|
-
const procs = msg.processes || [];
|
|
51
|
-
window.pm2Monitor.processes = procs;
|
|
52
|
-
const hasActive = msg.hasActive || procs.some(p => ACTIVE_STATES.has(p.status));
|
|
53
|
-
setPanelVisible(hasActive);
|
|
54
|
-
if (hasActive) renderProcessList(procs);
|
|
55
|
-
} else if (msg.type === 'pm2_list_response') {
|
|
56
|
-
const procs = msg.processes || [];
|
|
57
|
-
window.pm2Monitor.processes = procs;
|
|
58
|
-
const hasActive = procs.some(p => ACTIVE_STATES.has(p.status));
|
|
59
|
-
setPanelVisible(hasActive);
|
|
60
|
-
if (hasActive) renderProcessList(procs);
|
|
61
|
-
} else if (msg.type === 'pm2_unavailable') {
|
|
62
|
-
setPanelVisible(false);
|
|
63
|
-
} else if (msg.type === 'pm2_start_response' || msg.type === 'pm2_stop_response' ||
|
|
64
|
-
msg.type === 'pm2_restart_response' || msg.type === 'pm2_delete_response') {
|
|
65
|
-
const action = msg.type.replace('pm2_', '').replace('_response', '');
|
|
66
|
-
if (msg.success) {
|
|
67
|
-
toast(`PM2 ${action} ${msg.name} succeeded`, 'success');
|
|
68
|
-
setTimeout(() => send({ type: 'pm2_list' }), 500);
|
|
69
|
-
} else {
|
|
70
|
-
toast(`PM2 ${action} ${msg.name} failed: ${msg.error}`, 'error');
|
|
71
|
-
}
|
|
72
|
-
} else if (msg.type === 'pm2_logs_response') {
|
|
73
|
-
if (msg.success) showLogsModal(msg.name, msg.logs);
|
|
74
|
-
else toast(`Logs error: ${msg.error}`, 'error');
|
|
75
|
-
} else if (msg.type === 'pm2_flush_logs_response') {
|
|
76
|
-
toast(msg.success ? 'Logs flushed' : `Flush failed: ${msg.error}`, msg.success ? 'success' : 'error');
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function init() {
|
|
81
|
-
if (window.pm2Monitor.initialized) return;
|
|
82
|
-
window.pm2Monitor.initialized = true;
|
|
83
|
-
setPanelVisible(false);
|
|
84
|
-
if (refreshBtn) refreshBtn.addEventListener('click', () => send({ type: 'pm2_list' }));
|
|
85
|
-
document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && window.pm2Monitor.logsModalOpen) window.pm2Monitor.closeLogsModal(); });
|
|
86
|
-
if (window.wsManager) {
|
|
87
|
-
window.wsManager.on('message', handleMessage);
|
|
88
|
-
window.wsManager.on('connected', () => {
|
|
89
|
-
send({ type: 'pm2_start_monitoring' });
|
|
90
|
-
send({ type: 'pm2_list' });
|
|
91
|
-
});
|
|
92
|
-
if (window.wsManager.isConnected) {
|
|
93
|
-
send({ type: 'pm2_start_monitoring' });
|
|
94
|
-
send({ type: 'pm2_list' });
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function showLogsModal(name, logs) {
|
|
100
|
-
if (window.pm2Monitor.logsModalOpen) window.pm2Monitor.closeLogsModal();
|
|
101
|
-
const modal = document.createElement('div');
|
|
102
|
-
modal.className = 'pm2-logs-modal';
|
|
103
|
-
modal.innerHTML = `<div class="pm2-logs-content">
|
|
104
|
-
<div class="pm2-logs-header"><span>Logs: ${escHtml(name)}</span><button class="pm2-btn" onclick="window.pm2Monitor.closeLogsModal()">Close</button></div>
|
|
105
|
-
<div class="pm2-logs-body">${escHtml(logs || 'No logs available')}</div>
|
|
106
|
-
<div class="pm2-logs-footer">
|
|
107
|
-
<button class="pm2-btn" onclick="window.pm2Monitor.flushLogs('${escAttr(name)}')">Flush</button>
|
|
108
|
-
<button class="pm2-btn" onclick="window.pm2Monitor.closeLogsModal()">Close</button>
|
|
109
|
-
</div></div>`;
|
|
110
|
-
document.body.appendChild(modal);
|
|
111
|
-
window.pm2Monitor.logsModalOpen = name;
|
|
112
|
-
modal.addEventListener('click', (e) => { if (e.target === modal) window.pm2Monitor.closeLogsModal(); });
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function toast(msg, type) {
|
|
116
|
-
const t = document.createElement('div');
|
|
117
|
-
t.className = 'pm2-toast';
|
|
118
|
-
t.textContent = msg;
|
|
119
|
-
const bg = type === 'error' ? 'var(--color-error)' : type === 'success' ? 'var(--color-success)' : 'var(--color-primary)';
|
|
120
|
-
t.style.cssText = `position:fixed;top:1rem;right:1rem;padding:0.5rem 1rem;border-radius:0.375rem;font-size:0.8rem;color:white;z-index:10000;background:${bg}`;
|
|
121
|
-
document.body.appendChild(t);
|
|
122
|
-
setTimeout(() => { t.style.opacity = '0'; t.style.transition = 'opacity 0.3s'; setTimeout(() => t.remove(), 300); }, 3000);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function escHtml(s) { if (!s) return ''; const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
|
126
|
-
function escAttr(s) { return (s || '').replace(/"/g, '"').replace(/'/g, '''); }
|
|
127
|
-
function fmtBytes(b) {
|
|
128
|
-
if (!b || typeof b !== 'number') return '0 B';
|
|
129
|
-
const u = ['B','KB','MB','GB'], i = Math.min(Math.floor(Math.log(b) / Math.log(1024)), 3);
|
|
130
|
-
return (b / Math.pow(1024, i)).toFixed(1) + ' ' + u[i];
|
|
131
|
-
}
|
|
132
|
-
function fmtUptime(s) {
|
|
133
|
-
if (!s || s < 0) return '0s';
|
|
134
|
-
const d = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60;
|
|
135
|
-
if (d > 0) return `${d}d ${h}h`;
|
|
136
|
-
if (h > 0) return `${h}h ${m}m`;
|
|
137
|
-
if (m > 0) return `${m}m ${sec}s`;
|
|
138
|
-
return `${sec}s`;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
window.pm2Monitor.closeLogsModal = () => { const m = document.querySelector('.pm2-logs-modal'); if (m) m.remove(); window.pm2Monitor.logsModalOpen = null; };
|
|
142
|
-
window.pm2Monitor.startProcess = (name) => send({ type: 'pm2_start', name });
|
|
143
|
-
window.pm2Monitor.stopProcess = (name) => send({ type: 'pm2_stop', name });
|
|
144
|
-
window.pm2Monitor.restartProcess = (name) => send({ type: 'pm2_restart', name });
|
|
145
|
-
window.pm2Monitor.deleteProcess = (name) => { if (confirm(`Delete PM2 process "${name}"?`)) send({ type: 'pm2_delete', name }); };
|
|
146
|
-
window.pm2Monitor.showLogs = (name) => send({ type: 'pm2_logs', name, lines: 200 });
|
|
147
|
-
window.pm2Monitor.flushLogs = (name) => send({ type: 'pm2_flush_logs', name });
|
|
148
|
-
|
|
149
|
-
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => setTimeout(init, 150));
|
|
150
|
-
else setTimeout(init, 150);
|
|
151
|
-
})();
|
package/static/js/stt-handler.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
var BASE = window.__BASE_URL || '';
|
|
3
|
-
var isRecording = false;
|
|
4
|
-
var mediaStream = null;
|
|
5
|
-
var audioContext = null;
|
|
6
|
-
var workletNode = null;
|
|
7
|
-
var recordedChunks = [];
|
|
8
|
-
var TARGET_SAMPLE_RATE = 16000;
|
|
9
|
-
|
|
10
|
-
function rmApi() { return window.recordingMachineAPI; }
|
|
11
|
-
|
|
12
|
-
window.STTHandler = {
|
|
13
|
-
isRecording: function() { return rmApi()?.isRecording() || isRecording; },
|
|
14
|
-
|
|
15
|
-
startRecording: async function() {
|
|
16
|
-
if (isRecording || rmApi()?.isRecording()) return;
|
|
17
|
-
try {
|
|
18
|
-
mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
19
|
-
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
20
|
-
var source = audioContext.createMediaStreamSource(mediaStream);
|
|
21
|
-
recordedChunks = [];
|
|
22
|
-
await audioContext.audioWorklet.addModule(BASE + '/js/audio-recorder-processor.js');
|
|
23
|
-
workletNode = new AudioWorkletNode(audioContext, 'recorder-processor');
|
|
24
|
-
workletNode.port.onmessage = function(e) {
|
|
25
|
-
recordedChunks.push(e.data);
|
|
26
|
-
};
|
|
27
|
-
source.connect(workletNode);
|
|
28
|
-
isRecording = true;
|
|
29
|
-
if (rmApi()) rmApi().send({ type: 'START' });
|
|
30
|
-
return { success: true };
|
|
31
|
-
} catch (e) {
|
|
32
|
-
isRecording = false;
|
|
33
|
-
if (rmApi()) rmApi().send({ type: 'ERROR', error: e.message });
|
|
34
|
-
return { success: false, error: e.message };
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
stopRecording: async function() {
|
|
39
|
-
if (!isRecording && !rmApi()?.isRecording()) return { success: false, error: 'Not recording' };
|
|
40
|
-
isRecording = false;
|
|
41
|
-
if (rmApi()) rmApi().send({ type: 'STOP' });
|
|
42
|
-
|
|
43
|
-
if (workletNode) {
|
|
44
|
-
workletNode.port.postMessage('stop');
|
|
45
|
-
workletNode.disconnect();
|
|
46
|
-
workletNode = null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (mediaStream) {
|
|
50
|
-
mediaStream.getTracks().forEach(function(t) { t.stop(); });
|
|
51
|
-
mediaStream = null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
var sourceSampleRate = audioContext ? audioContext.sampleRate : 48000;
|
|
55
|
-
if (audioContext) {
|
|
56
|
-
audioContext.close().catch(function() {});
|
|
57
|
-
audioContext = null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (recordedChunks.length === 0) {
|
|
61
|
-
return { success: false, error: 'No audio recorded' };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
var totalLen = 0;
|
|
65
|
-
for (var i = 0; i < recordedChunks.length; i++) totalLen += recordedChunks[i].length;
|
|
66
|
-
var merged = new Float32Array(totalLen);
|
|
67
|
-
var offset = 0;
|
|
68
|
-
for (var j = 0; j < recordedChunks.length; j++) {
|
|
69
|
-
merged.set(recordedChunks[j], offset);
|
|
70
|
-
offset += recordedChunks[j].length;
|
|
71
|
-
}
|
|
72
|
-
recordedChunks = [];
|
|
73
|
-
|
|
74
|
-
var resampled = resampleBuffer(merged, sourceSampleRate, TARGET_SAMPLE_RATE);
|
|
75
|
-
var wavBuffer = encodeWav(resampled, TARGET_SAMPLE_RATE);
|
|
76
|
-
|
|
77
|
-
try {
|
|
78
|
-
var resp = await fetch(BASE + '/api/stt', {
|
|
79
|
-
method: 'POST',
|
|
80
|
-
headers: { 'Content-Type': 'audio/wav' },
|
|
81
|
-
body: wavBuffer
|
|
82
|
-
});
|
|
83
|
-
var data = await resp.json();
|
|
84
|
-
if (data.text) {
|
|
85
|
-
if (rmApi()) rmApi().send({ type: 'COMPLETE' });
|
|
86
|
-
return { success: true, text: data.text };
|
|
87
|
-
} else if (data.error) {
|
|
88
|
-
if (rmApi()) rmApi().send({ type: 'ERROR', error: data.error });
|
|
89
|
-
return { success: false, error: data.error };
|
|
90
|
-
} else {
|
|
91
|
-
if (rmApi()) rmApi().send({ type: 'ERROR', error: 'No transcription returned' });
|
|
92
|
-
return { success: false, error: 'No transcription returned' };
|
|
93
|
-
}
|
|
94
|
-
} catch (e) {
|
|
95
|
-
if (rmApi()) rmApi().send({ type: 'ERROR', error: e.message });
|
|
96
|
-
return { success: false, error: 'Transcription failed: ' + e.message };
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
function resampleBuffer(inputBuffer, fromRate, toRate) {
|
|
102
|
-
if (fromRate === toRate) return inputBuffer;
|
|
103
|
-
var ratio = fromRate / toRate;
|
|
104
|
-
var newLen = Math.round(inputBuffer.length / ratio);
|
|
105
|
-
var result = new Float32Array(newLen);
|
|
106
|
-
for (var i = 0; i < newLen; i++) {
|
|
107
|
-
var srcIdx = i * ratio;
|
|
108
|
-
var lo = Math.floor(srcIdx);
|
|
109
|
-
var hi = Math.min(lo + 1, inputBuffer.length - 1);
|
|
110
|
-
var frac = srcIdx - lo;
|
|
111
|
-
result[i] = inputBuffer[lo] * (1 - frac) + inputBuffer[hi] * frac;
|
|
112
|
-
}
|
|
113
|
-
return result;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function encodeWav(float32Audio, sampleRate) {
|
|
117
|
-
var numSamples = float32Audio.length;
|
|
118
|
-
var bytesPerSample = 2;
|
|
119
|
-
var dataSize = numSamples * bytesPerSample;
|
|
120
|
-
var buffer = new ArrayBuffer(44 + dataSize);
|
|
121
|
-
var view = new DataView(buffer);
|
|
122
|
-
|
|
123
|
-
function writeStr(off, str) {
|
|
124
|
-
for (var i = 0; i < str.length; i++) view.setUint8(off + i, str.charCodeAt(i));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
writeStr(0, 'RIFF');
|
|
128
|
-
view.setUint32(4, 36 + dataSize, true);
|
|
129
|
-
writeStr(8, 'WAVE');
|
|
130
|
-
writeStr(12, 'fmt ');
|
|
131
|
-
view.setUint32(16, 16, true);
|
|
132
|
-
view.setUint16(20, 1, true);
|
|
133
|
-
view.setUint16(22, 1, true);
|
|
134
|
-
view.setUint32(24, sampleRate, true);
|
|
135
|
-
view.setUint32(28, sampleRate * bytesPerSample, true);
|
|
136
|
-
view.setUint16(32, bytesPerSample, true);
|
|
137
|
-
view.setUint16(34, 16, true);
|
|
138
|
-
writeStr(36, 'data');
|
|
139
|
-
view.setUint32(40, dataSize, true);
|
|
140
|
-
|
|
141
|
-
for (var i = 0; i < numSamples; i++) {
|
|
142
|
-
var s = Math.max(-1, Math.min(1, float32Audio[i]));
|
|
143
|
-
view.setInt16(44 + i * 2, s < 0 ? s * 32768 : s * 32767, true);
|
|
144
|
-
}
|
|
145
|
-
return buffer;
|
|
146
|
-
}
|
|
147
|
-
})();
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
const { createMachine, createActor, assign } = XState;
|
|
3
|
-
|
|
4
|
-
const toolInstallMachine = createMachine({
|
|
5
|
-
id: 'tool-install-ui',
|
|
6
|
-
initial: 'idle',
|
|
7
|
-
context: {
|
|
8
|
-
version: null,
|
|
9
|
-
error: null,
|
|
10
|
-
progress: 0,
|
|
11
|
-
installedVersion: null,
|
|
12
|
-
publishedVersion: null,
|
|
13
|
-
},
|
|
14
|
-
states: {
|
|
15
|
-
idle: {
|
|
16
|
-
entry: assign({ error: null, progress: 0 }),
|
|
17
|
-
on: {
|
|
18
|
-
INSTALL: 'installing',
|
|
19
|
-
UPDATE: 'updating',
|
|
20
|
-
SET_INSTALLED: {
|
|
21
|
-
target: 'installed',
|
|
22
|
-
actions: assign(({ event }) => ({
|
|
23
|
-
installedVersion: event.installedVersion || null,
|
|
24
|
-
publishedVersion: event.publishedVersion || null,
|
|
25
|
-
version: event.version || event.installedVersion || null,
|
|
26
|
-
})),
|
|
27
|
-
},
|
|
28
|
-
SET_NEEDS_UPDATE: {
|
|
29
|
-
target: 'needs_update',
|
|
30
|
-
actions: assign(({ event }) => ({
|
|
31
|
-
installedVersion: event.installedVersion || null,
|
|
32
|
-
publishedVersion: event.publishedVersion || null,
|
|
33
|
-
})),
|
|
34
|
-
},
|
|
35
|
-
SET_FAILED: {
|
|
36
|
-
target: 'failed',
|
|
37
|
-
actions: assign(({ event }) => ({ error: event.error || null })),
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
installing: {
|
|
42
|
-
entry: assign({ error: null, progress: 0 }),
|
|
43
|
-
on: {
|
|
44
|
-
PROGRESS: {
|
|
45
|
-
actions: assign(({ context, event }) => ({
|
|
46
|
-
progress: Math.min(event.progress || context.progress + 5, 90),
|
|
47
|
-
})),
|
|
48
|
-
},
|
|
49
|
-
COMPLETE: {
|
|
50
|
-
target: 'installed',
|
|
51
|
-
actions: assign(({ event }) => ({
|
|
52
|
-
version: event.version || null,
|
|
53
|
-
installedVersion: event.installedVersion || null,
|
|
54
|
-
publishedVersion: event.publishedVersion || null,
|
|
55
|
-
progress: 100,
|
|
56
|
-
error: null,
|
|
57
|
-
})),
|
|
58
|
-
},
|
|
59
|
-
FAILED: {
|
|
60
|
-
target: 'failed',
|
|
61
|
-
actions: assign(({ event }) => ({ error: event.error || null, progress: 0 })),
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
installed: {
|
|
66
|
-
on: {
|
|
67
|
-
UPDATE: 'updating',
|
|
68
|
-
SET_NEEDS_UPDATE: {
|
|
69
|
-
target: 'needs_update',
|
|
70
|
-
actions: assign(({ event }) => ({
|
|
71
|
-
installedVersion: event.installedVersion || null,
|
|
72
|
-
publishedVersion: event.publishedVersion || null,
|
|
73
|
-
})),
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
updating: {
|
|
78
|
-
entry: assign({ error: null, progress: 0 }),
|
|
79
|
-
on: {
|
|
80
|
-
PROGRESS: {
|
|
81
|
-
actions: assign(({ context, event }) => ({
|
|
82
|
-
progress: Math.min(event.progress || context.progress + 5, 90),
|
|
83
|
-
})),
|
|
84
|
-
},
|
|
85
|
-
COMPLETE: {
|
|
86
|
-
target: 'installed',
|
|
87
|
-
actions: assign(({ event }) => ({
|
|
88
|
-
version: event.version || null,
|
|
89
|
-
installedVersion: event.installedVersion || null,
|
|
90
|
-
publishedVersion: event.publishedVersion || null,
|
|
91
|
-
progress: 100,
|
|
92
|
-
error: null,
|
|
93
|
-
})),
|
|
94
|
-
},
|
|
95
|
-
FAILED: {
|
|
96
|
-
target: 'failed',
|
|
97
|
-
actions: assign(({ event }) => ({ error: event.error || null, progress: 0 })),
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
needs_update: {
|
|
102
|
-
on: {
|
|
103
|
-
UPDATE: 'updating',
|
|
104
|
-
SET_INSTALLED: {
|
|
105
|
-
target: 'installed',
|
|
106
|
-
actions: assign(({ event }) => ({
|
|
107
|
-
installedVersion: event.installedVersion || null,
|
|
108
|
-
publishedVersion: event.publishedVersion || null,
|
|
109
|
-
})),
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
failed: {
|
|
114
|
-
on: {
|
|
115
|
-
INSTALL: 'installing',
|
|
116
|
-
UPDATE: 'updating',
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const toolInstallMachines = new Map();
|
|
123
|
-
|
|
124
|
-
function getOrCreate(toolId) {
|
|
125
|
-
if (toolInstallMachines.has(toolId)) return toolInstallMachines.get(toolId);
|
|
126
|
-
const actor = createActor(toolInstallMachine);
|
|
127
|
-
actor.start();
|
|
128
|
-
toolInstallMachines.set(toolId, actor);
|
|
129
|
-
return actor;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function sendEvent(toolId, event) {
|
|
133
|
-
const actor = getOrCreate(toolId);
|
|
134
|
-
actor.send(event);
|
|
135
|
-
return actor.getSnapshot();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function getState(toolId) {
|
|
139
|
-
const actor = toolInstallMachines.get(toolId);
|
|
140
|
-
return actor ? actor.getSnapshot().value : 'idle';
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function isLocked(toolId) {
|
|
144
|
-
const s = getState(toolId);
|
|
145
|
-
return s === 'installing' || s === 'updating';
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function remove(toolId) {
|
|
149
|
-
const actor = toolInstallMachines.get(toolId);
|
|
150
|
-
if (actor) { actor.stop(); toolInstallMachines.delete(toolId); }
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
window.__toolInstallMachines = toolInstallMachines;
|
|
154
|
-
window.toolInstallMachineAPI = { getOrCreate, send: sendEvent, getState, isLocked, remove };
|
|
155
|
-
})();
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
(function() {
|
|
2
|
-
window.toolsManagerUI = {
|
|
3
|
-
getStatusColor: function(tool) {
|
|
4
|
-
var ms = window.toolInstallMachineAPI ? window.toolInstallMachineAPI.getState(tool.id) : null;
|
|
5
|
-
if (ms === 'installing' || ms === 'updating') return '#3b82f6';
|
|
6
|
-
if (ms === 'needs_update') return '#f59e0b';
|
|
7
|
-
if (ms === 'installed') return '#10b981';
|
|
8
|
-
if (ms === 'failed') return '#ef4444';
|
|
9
|
-
if (tool.status === 'installing' || tool.status === 'updating') return '#3b82f6';
|
|
10
|
-
if (tool.status === 'needs_update' || (tool.status === 'installed' && tool.hasUpdate)) return '#f59e0b';
|
|
11
|
-
if (tool.status === 'installed') return '#10b981';
|
|
12
|
-
if (tool.status === 'failed') return '#ef4444';
|
|
13
|
-
return '#6b7280';
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
getStatusText: function(tool) {
|
|
17
|
-
var ms = window.toolInstallMachineAPI ? window.toolInstallMachineAPI.getState(tool.id) : null;
|
|
18
|
-
if (ms === 'installing') return 'Installing...';
|
|
19
|
-
if (ms === 'updating') return 'Updating...';
|
|
20
|
-
if (ms === 'needs_update') return 'Update available';
|
|
21
|
-
if (ms === 'installed') return tool.hasUpdate ? 'Update available' : 'Up-to-date';
|
|
22
|
-
if (ms === 'failed') return 'Installation failed';
|
|
23
|
-
if (tool.status === 'installing') return 'Installing...';
|
|
24
|
-
if (tool.status === 'updating') return 'Updating...';
|
|
25
|
-
if (tool.status === 'needs_update') return 'Update available';
|
|
26
|
-
if (tool.status === 'installed') return tool.hasUpdate ? 'Update available' : 'Up-to-date';
|
|
27
|
-
if (tool.status === 'failed') return 'Installation failed';
|
|
28
|
-
return 'Not installed';
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
getStatusClass: function(tool) {
|
|
32
|
-
var ms = window.toolInstallMachineAPI ? window.toolInstallMachineAPI.getState(tool.id) : null;
|
|
33
|
-
if (ms === 'installing' || ms === 'updating') return 'installing';
|
|
34
|
-
if (ms === 'needs_update') return 'updating';
|
|
35
|
-
if (ms === 'installed') return 'installed';
|
|
36
|
-
if (ms === 'failed') return 'failed';
|
|
37
|
-
if (tool.status === 'installing' || tool.status === 'updating') return 'installing';
|
|
38
|
-
if (tool.status === 'needs_update' || (tool.status === 'installed' && tool.hasUpdate)) return 'updating';
|
|
39
|
-
if (tool.status === 'installed') return 'installed';
|
|
40
|
-
if (tool.status === 'failed') return 'failed';
|
|
41
|
-
return 'not-installed';
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
renderToolCard: function(tool, isRefreshing) {
|
|
45
|
-
var h = window.webjsx && window.webjsx.createElement;
|
|
46
|
-
if (!h) return null;
|
|
47
|
-
var ui = window.toolsManagerUI;
|
|
48
|
-
var statusClass = ui.getStatusClass(tool);
|
|
49
|
-
var ms = window.toolInstallMachineAPI ? window.toolInstallMachineAPI.getState(tool.id) : null;
|
|
50
|
-
var isInstalling = ms === 'installing' || ms === 'updating';
|
|
51
|
-
var snap = window.__toolInstallMachines && window.__toolInstallMachines.get(tool.id) ? window.__toolInstallMachines.get(tool.id).getSnapshot() : null;
|
|
52
|
-
var progress = snap ? snap.context.progress : 0;
|
|
53
|
-
var locked = window.toolInstallMachineAPI ? window.toolInstallMachineAPI.isLocked(tool.id) : false;
|
|
54
|
-
var canInstall = ms === 'idle' || ms === 'failed' || tool.status === 'not_installed' || tool.status === 'failed';
|
|
55
|
-
var canUpdate = ms === 'needs_update' || tool.hasUpdate || tool.status === 'needs_update';
|
|
56
|
-
var iv = (snap && snap.context.installedVersion) || tool.installedVersion;
|
|
57
|
-
var pv = (snap && snap.context.publishedVersion) || tool.publishedVersion;
|
|
58
|
-
var versionChildren = [];
|
|
59
|
-
if (iv) versionChildren.push(h('span', { class: 'tool-version-item' }, 'v' + iv));
|
|
60
|
-
if (pv && iv !== pv) versionChildren.push(h('span', { class: 'tool-version-item' }, '(v' + pv + ' available)'));
|
|
61
|
-
var actionBtn = canInstall
|
|
62
|
-
? h('button', { class: 'tool-btn tool-btn-primary', disabled: locked, onClick: function() { window.toolsManager.install(tool.id); } }, 'Install')
|
|
63
|
-
: canUpdate
|
|
64
|
-
? h('button', { class: 'tool-btn tool-btn-primary', disabled: locked, onClick: function() { window.toolsManager.update(tool.id); } }, 'Update')
|
|
65
|
-
: h('button', { class: 'tool-btn tool-btn-secondary', disabled: isRefreshing, onClick: function() { window.toolsManager.refresh(); } }, '\u2713');
|
|
66
|
-
return h('div', { class: 'tool-item' },
|
|
67
|
-
h('div', { style: 'display:flex;flex-direction:column;gap:0.3rem;' },
|
|
68
|
-
h('div', { class: 'tool-header' }, h('span', { class: 'tool-name' }, tool.name || tool.id)),
|
|
69
|
-
h('div', { class: 'tool-status-indicator ' + statusClass },
|
|
70
|
-
h('span', { class: 'tool-status-dot' }),
|
|
71
|
-
h('span', {}, ui.getStatusText(tool))
|
|
72
|
-
),
|
|
73
|
-
versionChildren.length ? h('div', { class: 'tool-versions' }, ...versionChildren) : null,
|
|
74
|
-
isInstalling && progress !== undefined
|
|
75
|
-
? h('div', { class: 'tool-progress-container' }, h('div', { class: 'tool-progress-bar' }, h('div', { class: 'tool-progress-fill', style: 'width:' + Math.min(progress, 100) + '%' })))
|
|
76
|
-
: null,
|
|
77
|
-
tool.error_message ? h('div', { class: 'tool-error-message' }, 'Error: ' + tool.error_message.substring(0, 40)) : null
|
|
78
|
-
),
|
|
79
|
-
h('div', { class: 'tool-actions' }, actionBtn)
|
|
80
|
-
);
|
|
81
|
-
},
|
|
82
|
-
|
|
83
|
-
esc: function(s) {
|
|
84
|
-
var d = document.createElement('div');
|
|
85
|
-
d.textContent = s;
|
|
86
|
-
return d.innerHTML;
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
updateVoiceSelector: function(voices) {
|
|
90
|
-
var voiceSelector = document.getElementById('toolsVoiceSelector');
|
|
91
|
-
if (!voiceSelector || !voices || !Array.isArray(voices)) return;
|
|
92
|
-
var currentValue = voiceSelector.value || localStorage.getItem('toolsVoice') || 'default';
|
|
93
|
-
voiceSelector.innerHTML = '';
|
|
94
|
-
var builtIn = voices.filter(function(v) { return !v.isCustom; });
|
|
95
|
-
var custom = voices.filter(function(v) { return v.isCustom; });
|
|
96
|
-
if (builtIn.length) {
|
|
97
|
-
var grp1 = document.createElement('optgroup');
|
|
98
|
-
grp1.label = 'Built-in Voices';
|
|
99
|
-
builtIn.forEach(function(voice) {
|
|
100
|
-
var opt = document.createElement('option');
|
|
101
|
-
opt.value = voice.id;
|
|
102
|
-
var parts = [];
|
|
103
|
-
if (voice.gender && voice.gender !== 'custom') parts.push(voice.gender);
|
|
104
|
-
if (voice.accent && voice.accent !== 'custom') parts.push(voice.accent);
|
|
105
|
-
opt.textContent = voice.name + (parts.length ? ' (' + parts.join(', ') + ')' : '');
|
|
106
|
-
grp1.appendChild(opt);
|
|
107
|
-
});
|
|
108
|
-
voiceSelector.appendChild(grp1);
|
|
109
|
-
}
|
|
110
|
-
if (custom.length) {
|
|
111
|
-
var grp2 = document.createElement('optgroup');
|
|
112
|
-
grp2.label = 'Custom Voices';
|
|
113
|
-
custom.forEach(function(voice) {
|
|
114
|
-
var opt = document.createElement('option');
|
|
115
|
-
opt.value = voice.id;
|
|
116
|
-
opt.textContent = voice.name;
|
|
117
|
-
grp2.appendChild(opt);
|
|
118
|
-
});
|
|
119
|
-
voiceSelector.appendChild(grp2);
|
|
120
|
-
}
|
|
121
|
-
if (voiceSelector.querySelector('option[value="' + currentValue + '"]')) voiceSelector.value = currentValue;
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
})();
|