clideck 1.31.13 → 1.31.15
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/handlers.js +39 -1
- package/package.json +1 -1
- package/plugin-loader.js +8 -0
- package/plugins/voice-input/clideck-plugin.json +1 -1
- package/public/index.html +1 -1
- package/public/js/app.js +19 -1
package/handlers.js
CHANGED
|
@@ -295,6 +295,13 @@ function remoteCliEnv() {
|
|
|
295
295
|
return { ...process.env, CLIDECK_PORT: String(PORT) };
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
+
function remoteVoiceCapabilityError() {
|
|
299
|
+
const voicePlugin = plugins.getInfo().find(p => p.id === 'voice-input' && p.installed);
|
|
300
|
+
return voicePlugin
|
|
301
|
+
? 'Restart CliDeck so the Voice Input plugin update can finish loading.'
|
|
302
|
+
: 'Install the Voice Input plugin in CliDeck first.';
|
|
303
|
+
}
|
|
304
|
+
|
|
298
305
|
function onConnection(ws) {
|
|
299
306
|
sessions.clients.add(ws);
|
|
300
307
|
|
|
@@ -606,7 +613,7 @@ function onConnection(ws) {
|
|
|
606
613
|
const requestId = String(msg.requestId || '');
|
|
607
614
|
const replyError = (error) => ws.send(JSON.stringify({ type: 'remote.voice.error', requestId, error }));
|
|
608
615
|
if (!plugins.hasCapability('voice-input', 'transcribeAudio')) {
|
|
609
|
-
replyError(
|
|
616
|
+
replyError(remoteVoiceCapabilityError());
|
|
610
617
|
break;
|
|
611
618
|
}
|
|
612
619
|
if (typeof msg.audio !== 'string' || !msg.audio) {
|
|
@@ -619,6 +626,37 @@ function onConnection(ws) {
|
|
|
619
626
|
break;
|
|
620
627
|
}
|
|
621
628
|
|
|
629
|
+
case 'remote.voice.send': {
|
|
630
|
+
const requestId = String(msg.requestId || '');
|
|
631
|
+
const id = String(msg.id || '');
|
|
632
|
+
const replyError = (error) => ws.send(JSON.stringify({ type: 'remote.voice.error', requestId, error }));
|
|
633
|
+
if (!plugins.hasCapability('voice-input', 'transcribeAudio')) {
|
|
634
|
+
replyError(remoteVoiceCapabilityError());
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
if (!id || !sessions.getSessions().has(id)) {
|
|
638
|
+
replyError('Session is not available.');
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
if (typeof msg.audio !== 'string' || !msg.audio) {
|
|
642
|
+
replyError('No audio received.');
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
plugins.invoke('voice-input', 'transcribeAudio', { audio: msg.audio })
|
|
646
|
+
.then(result => {
|
|
647
|
+
const text = String(result?.text || '').trim();
|
|
648
|
+
if (!text) {
|
|
649
|
+
ws.send(JSON.stringify({ type: 'remote.voice.sent', requestId, id, skipped: true }));
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
sessions.input({ id, data: text });
|
|
653
|
+
setTimeout(() => sessions.input({ id, data: '\r' }), 150);
|
|
654
|
+
ws.send(JSON.stringify({ type: 'remote.voice.sent', requestId, id, text }));
|
|
655
|
+
})
|
|
656
|
+
.catch(e => replyError(e.message || 'Voice transcription failed.'));
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
|
|
622
660
|
case 'remote.install': {
|
|
623
661
|
const update = !!msg.update;
|
|
624
662
|
const proc = require('child_process').spawn('npm', ['install', '-g', 'clideck-remote'], {
|
package/package.json
CHANGED
package/plugin-loader.js
CHANGED
|
@@ -445,6 +445,12 @@ async function invoke(pluginId, name, data = {}) {
|
|
|
445
445
|
|
|
446
446
|
function getInfo() {
|
|
447
447
|
const cfg = getConfigFn?.();
|
|
448
|
+
const capabilitiesFor = (pluginId) => {
|
|
449
|
+
const prefix = `${pluginId}.`;
|
|
450
|
+
return [...backendHandlers.keys()]
|
|
451
|
+
.filter(k => k.startsWith(prefix))
|
|
452
|
+
.map(k => k.slice(prefix.length));
|
|
453
|
+
};
|
|
448
454
|
const installed = [...plugins.values()].map(p => ({
|
|
449
455
|
id: p.manifest.id,
|
|
450
456
|
name: p.manifest.name,
|
|
@@ -456,6 +462,7 @@ function getInfo() {
|
|
|
456
462
|
settingValues: cfg?.pluginSettings?.[p.manifest.id] || {},
|
|
457
463
|
dynamicOptions: p.dynamicOptions || {},
|
|
458
464
|
actions: p.actions,
|
|
465
|
+
capabilities: capabilitiesFor(p.manifest.id),
|
|
459
466
|
hasClient: existsSync(join(p.dir, 'client.js')),
|
|
460
467
|
bundled: BUNDLED_IDS.has(p.manifest.id),
|
|
461
468
|
installed: true,
|
|
@@ -471,6 +478,7 @@ function getInfo() {
|
|
|
471
478
|
settingValues: {},
|
|
472
479
|
dynamicOptions: {},
|
|
473
480
|
actions: [],
|
|
481
|
+
capabilities: [],
|
|
474
482
|
hasClient: false,
|
|
475
483
|
bundled: BUNDLED_IDS.has(u.manifest.id),
|
|
476
484
|
installed: false,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "voice-input",
|
|
3
3
|
"name": "Voice Input",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.1",
|
|
5
5
|
"author": "CliDeck",
|
|
6
6
|
"description": "Dictate prompts with your voice using Whisper speech-to-text",
|
|
7
7
|
"icon": "<svg class=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z\"/><path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/><line x1=\"12\" y1=\"19\" x2=\"12\" y2=\"23\"/><line x1=\"8\" y1=\"23\" x2=\"16\" y2=\"23\"/></svg>",
|
package/public/index.html
CHANGED
|
@@ -355,7 +355,7 @@
|
|
|
355
355
|
<div id="remote-modal" class="absolute inset-0 z-[260] bg-black/60 backdrop-blur-sm hidden items-center justify-center">
|
|
356
356
|
<div style="background:var(--color-dialog);border:1px solid color-mix(in srgb, var(--color-muted) 40%, transparent);box-shadow:0 25px 60px -12px var(--color-shadow)" class="rounded-2xl w-[340px] flex flex-col overflow-hidden">
|
|
357
357
|
<div class="px-5 py-3.5 flex items-center justify-between">
|
|
358
|
-
<span class="text-[13px] font-semibold text-slate-200">Mobile Remote</span>
|
|
358
|
+
<span id="remote-modal-title" class="text-[13px] font-semibold text-slate-200">Mobile Remote</span>
|
|
359
359
|
<button id="remote-close" class="w-6 h-6 flex items-center justify-center rounded-md text-slate-500 hover:text-slate-300 hover:bg-slate-700/50 transition-colors">
|
|
360
360
|
<svg class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
|
|
361
361
|
</button>
|
package/public/js/app.js
CHANGED
|
@@ -1184,12 +1184,28 @@ function setRemotePane(pane) {
|
|
|
1184
1184
|
}
|
|
1185
1185
|
}
|
|
1186
1186
|
|
|
1187
|
+
function remoteTitle() {
|
|
1188
|
+
const version = state.remoteVersion && state.remoteVersion !== 'not installed'
|
|
1189
|
+
? ` v${state.remoteVersion}`
|
|
1190
|
+
: '';
|
|
1191
|
+
return `Mobile Remote${version}`;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
function updateRemoteTitle() {
|
|
1195
|
+
const title = remoteTitle();
|
|
1196
|
+
const modalTitle = document.getElementById('remote-modal-title');
|
|
1197
|
+
const introTitle = document.getElementById('remote-intro-title');
|
|
1198
|
+
if (modalTitle) modalTitle.textContent = title;
|
|
1199
|
+
if (introTitle) introTitle.textContent = `CliDeck ${title}`;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1187
1202
|
function showRemoteIntro(opts = {}) {
|
|
1188
1203
|
const title = document.getElementById('remote-intro-title');
|
|
1189
1204
|
const text = document.getElementById('remote-intro-text');
|
|
1190
1205
|
const foot = document.getElementById('remote-intro-foot');
|
|
1191
1206
|
const btn = document.getElementById('remote-add');
|
|
1192
|
-
|
|
1207
|
+
updateRemoteTitle();
|
|
1208
|
+
if (opts.title) title.textContent = opts.title;
|
|
1193
1209
|
text.textContent = opts.text || 'Control your AI agents from your phone. See live status, send messages, and get notifications — all end-to-end encrypted.';
|
|
1194
1210
|
foot.innerHTML = opts.foot || 'Installs the <code class="text-slate-500">clideck-remote</code> package via npm';
|
|
1195
1211
|
btn.textContent = opts.button || 'Add to CliDeck';
|
|
@@ -1236,6 +1252,7 @@ function finishRemotePreflight() {
|
|
|
1236
1252
|
}
|
|
1237
1253
|
|
|
1238
1254
|
function openRemoteModal() {
|
|
1255
|
+
updateRemoteTitle();
|
|
1239
1256
|
remoteModalOpen = true;
|
|
1240
1257
|
remoteModal.classList.remove('hidden');
|
|
1241
1258
|
remoteModal.style.display = 'flex';
|
|
@@ -1326,6 +1343,7 @@ function handleRemoteStatus(msg) {
|
|
|
1326
1343
|
remoteLastStatus = msg;
|
|
1327
1344
|
remoteInstalled = !!msg.installed;
|
|
1328
1345
|
state.remoteVersion = msg.version || (msg.installed ? null : 'not installed');
|
|
1346
|
+
updateRemoteTitle();
|
|
1329
1347
|
updateVersionFooter();
|
|
1330
1348
|
const wasPaired = remoteState === 'paired';
|
|
1331
1349
|
const preflighting = !!remotePreflight?.pending;
|