@agentdeck/bridge 0.1.0 → 0.2.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.
- package/LICENSE +21 -0
- package/dist/adapters/claude-code.d.ts +11 -27
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +29 -123
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex-cli.d.ts +21 -0
- package/dist/adapters/codex-cli.d.ts.map +1 -0
- package/dist/adapters/codex-cli.js +53 -0
- package/dist/adapters/codex-cli.js.map +1 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +13 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/monitor.d.ts +34 -0
- package/dist/adapters/monitor.d.ts.map +1 -0
- package/dist/adapters/monitor.js +86 -0
- package/dist/adapters/monitor.js.map +1 -0
- package/dist/adapters/openclaw.d.ts +36 -2
- package/dist/adapters/openclaw.d.ts.map +1 -1
- package/dist/adapters/openclaw.js +329 -59
- package/dist/adapters/openclaw.js.map +1 -1
- package/dist/adapters/opencode-adapter.d.ts +48 -0
- package/dist/adapters/opencode-adapter.d.ts.map +1 -0
- package/dist/adapters/opencode-adapter.js +345 -0
- package/dist/adapters/opencode-adapter.js.map +1 -0
- package/dist/adapters/pty-adapter.d.ts +56 -0
- package/dist/adapters/pty-adapter.d.ts.map +1 -0
- package/dist/adapters/pty-adapter.js +143 -0
- package/dist/adapters/pty-adapter.js.map +1 -0
- package/dist/adb-reverse.d.ts +25 -0
- package/dist/adb-reverse.d.ts.map +1 -0
- package/dist/adb-reverse.js +129 -0
- package/dist/adb-reverse.js.map +1 -0
- package/dist/antigravity-local.d.ts +7 -0
- package/dist/antigravity-local.d.ts.map +1 -0
- package/dist/antigravity-local.js +153 -0
- package/dist/antigravity-local.js.map +1 -0
- package/dist/apme/adapters/claude-hook.d.ts +15 -0
- package/dist/apme/adapters/claude-hook.d.ts.map +1 -0
- package/dist/apme/adapters/claude-hook.js +85 -0
- package/dist/apme/adapters/claude-hook.js.map +1 -0
- package/dist/apme/adapters/claude-pty.d.ts +28 -0
- package/dist/apme/adapters/claude-pty.d.ts.map +1 -0
- package/dist/apme/adapters/claude-pty.js +88 -0
- package/dist/apme/adapters/claude-pty.js.map +1 -0
- package/dist/apme/adapters/timeline.d.ts +16 -0
- package/dist/apme/adapters/timeline.d.ts.map +1 -0
- package/dist/apme/adapters/timeline.js +66 -0
- package/dist/apme/adapters/timeline.js.map +1 -0
- package/dist/apme/classifier.d.ts +53 -0
- package/dist/apme/classifier.d.ts.map +1 -0
- package/dist/apme/classifier.js +266 -0
- package/dist/apme/classifier.js.map +1 -0
- package/dist/apme/claude-transcript-reader.d.ts +38 -0
- package/dist/apme/claude-transcript-reader.d.ts.map +1 -0
- package/dist/apme/claude-transcript-reader.js +127 -0
- package/dist/apme/claude-transcript-reader.js.map +1 -0
- package/dist/apme/collector.d.ts +108 -0
- package/dist/apme/collector.d.ts.map +1 -0
- package/dist/apme/collector.js +659 -0
- package/dist/apme/collector.js.map +1 -0
- package/dist/apme/dashboard-html.d.ts +9 -0
- package/dist/apme/dashboard-html.d.ts.map +1 -0
- package/dist/apme/dashboard-html.js +416 -0
- package/dist/apme/dashboard-html.js.map +1 -0
- package/dist/apme/http.d.ts +19 -0
- package/dist/apme/http.d.ts.map +1 -0
- package/dist/apme/http.js +210 -0
- package/dist/apme/http.js.map +1 -0
- package/dist/apme/hw-sampler.d.ts +30 -0
- package/dist/apme/hw-sampler.d.ts.map +1 -0
- package/dist/apme/hw-sampler.js +106 -0
- package/dist/apme/hw-sampler.js.map +1 -0
- package/dist/apme/index.d.ts +43 -0
- package/dist/apme/index.d.ts.map +1 -0
- package/dist/apme/index.js +75 -0
- package/dist/apme/index.js.map +1 -0
- package/dist/apme/outcome.d.ts +48 -0
- package/dist/apme/outcome.d.ts.map +1 -0
- package/dist/apme/outcome.js +232 -0
- package/dist/apme/outcome.js.map +1 -0
- package/dist/apme/recommend.d.ts +32 -0
- package/dist/apme/recommend.d.ts.map +1 -0
- package/dist/apme/recommend.js +41 -0
- package/dist/apme/recommend.js.map +1 -0
- package/dist/apme/runner.d.ts +94 -0
- package/dist/apme/runner.d.ts.map +1 -0
- package/dist/apme/runner.js +812 -0
- package/dist/apme/runner.js.map +1 -0
- package/dist/apme/settings.d.ts +65 -0
- package/dist/apme/settings.d.ts.map +1 -0
- package/dist/apme/settings.js +97 -0
- package/dist/apme/settings.js.map +1 -0
- package/dist/apme/store.d.ts +99 -0
- package/dist/apme/store.d.ts.map +1 -0
- package/dist/apme/store.js +911 -0
- package/dist/apme/store.js.map +1 -0
- package/dist/apme/tuner.d.ts +64 -0
- package/dist/apme/tuner.d.ts.map +1 -0
- package/dist/apme/tuner.js +297 -0
- package/dist/apme/tuner.js.map +1 -0
- package/dist/apme/types.d.ts +11 -0
- package/dist/apme/types.d.ts.map +1 -0
- package/dist/apme/types.js +10 -0
- package/dist/apme/types.js.map +1 -0
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +15 -5
- package/dist/auth.js.map +1 -1
- package/dist/bridge-core.d.ts +162 -0
- package/dist/bridge-core.d.ts.map +1 -0
- package/dist/bridge-core.js +627 -0
- package/dist/bridge-core.js.map +1 -0
- package/dist/check-deps.d.ts +3 -1
- package/dist/check-deps.d.ts.map +1 -1
- package/dist/check-deps.js +34 -13
- package/dist/check-deps.js.map +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1235 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-auth.d.ts +10 -0
- package/dist/codex-auth.d.ts.map +1 -0
- package/dist/codex-auth.js +63 -0
- package/dist/codex-auth.js.map +1 -0
- package/dist/codex-output-parser.d.ts +21 -0
- package/dist/codex-output-parser.d.ts.map +1 -0
- package/dist/codex-output-parser.js +253 -0
- package/dist/codex-output-parser.js.map +1 -0
- package/dist/d200h/hid-protocol.d.ts +62 -0
- package/dist/d200h/hid-protocol.d.ts.map +1 -0
- package/dist/d200h/hid-protocol.js +124 -0
- package/dist/d200h/hid-protocol.js.map +1 -0
- package/dist/d200h/image-renderer.d.ts +36 -0
- package/dist/d200h/image-renderer.d.ts.map +1 -0
- package/dist/d200h/image-renderer.js +487 -0
- package/dist/d200h/image-renderer.js.map +1 -0
- package/dist/daemon-server.d.ts +19 -0
- package/dist/daemon-server.d.ts.map +1 -0
- package/dist/daemon-server.js +1168 -0
- package/dist/daemon-server.js.map +1 -0
- package/dist/daemon-ws-client.d.ts +82 -0
- package/dist/daemon-ws-client.d.ts.map +1 -0
- package/dist/daemon-ws-client.js +179 -0
- package/dist/daemon-ws-client.js.map +1 -0
- package/dist/daemon.d.ts +10 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +56 -0
- package/dist/daemon.js.map +1 -0
- package/dist/display-monitor.d.ts +25 -0
- package/dist/display-monitor.d.ts.map +1 -0
- package/dist/display-monitor.js +143 -0
- package/dist/display-monitor.js.map +1 -0
- package/dist/esp32-serial.d.ts +112 -0
- package/dist/esp32-serial.d.ts.map +1 -0
- package/dist/esp32-serial.js +502 -0
- package/dist/esp32-serial.js.map +1 -0
- package/dist/gateway-probe.d.ts +12 -0
- package/dist/gateway-probe.d.ts.map +1 -0
- package/dist/gateway-probe.js +39 -0
- package/dist/gateway-probe.js.map +1 -0
- package/dist/hook-migration.d.ts +2 -0
- package/dist/hook-migration.d.ts.map +1 -0
- package/dist/hook-migration.js +104 -0
- package/dist/hook-migration.js.map +1 -0
- package/dist/hook-server.d.ts +29 -0
- package/dist/hook-server.d.ts.map +1 -1
- package/dist/hook-server.js +366 -8
- package/dist/hook-server.js.map +1 -1
- package/dist/index.d.ts +20 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1304 -562
- package/dist/index.js.map +1 -1
- package/dist/log-stream.d.ts +26 -0
- package/dist/log-stream.d.ts.map +1 -0
- package/dist/log-stream.js +111 -0
- package/dist/log-stream.js.map +1 -0
- package/dist/logger.d.ts +9 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +36 -5
- package/dist/logger.js.map +1 -1
- package/dist/mdns.d.ts +15 -1
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +143 -28
- package/dist/mdns.js.map +1 -1
- package/dist/mlx-probe.d.ts +14 -0
- package/dist/mlx-probe.d.ts.map +1 -0
- package/dist/mlx-probe.js +44 -0
- package/dist/mlx-probe.js.map +1 -0
- package/dist/model-catalog.d.ts +5 -3
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +45 -29
- package/dist/model-catalog.js.map +1 -1
- package/dist/modules/adb-module.d.ts +14 -0
- package/dist/modules/adb-module.d.ts.map +1 -0
- package/dist/modules/adb-module.js +36 -0
- package/dist/modules/adb-module.js.map +1 -0
- package/dist/modules/d200h-module.d.ts +43 -0
- package/dist/modules/d200h-module.d.ts.map +1 -0
- package/dist/modules/d200h-module.js +360 -0
- package/dist/modules/d200h-module.js.map +1 -0
- package/dist/modules/d200h-renderer.d.ts +7 -0
- package/dist/modules/d200h-renderer.d.ts.map +1 -0
- package/dist/modules/d200h-renderer.js +321 -0
- package/dist/modules/d200h-renderer.js.map +1 -0
- package/dist/modules/index.d.ts +23 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +65 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/mdns-module.d.ts +12 -0
- package/dist/modules/mdns-module.d.ts.map +1 -0
- package/dist/modules/mdns-module.js +21 -0
- package/dist/modules/mdns-module.js.map +1 -0
- package/dist/modules/pixoo-module.d.ts +8 -0
- package/dist/modules/pixoo-module.d.ts.map +1 -0
- package/dist/modules/pixoo-module.js +24 -0
- package/dist/modules/pixoo-module.js.map +1 -0
- package/dist/modules/serial-module.d.ts +18 -0
- package/dist/modules/serial-module.d.ts.map +1 -0
- package/dist/modules/serial-module.js +47 -0
- package/dist/modules/serial-module.js.map +1 -0
- package/dist/modules/types.d.ts +39 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +2 -0
- package/dist/modules/types.js.map +1 -0
- package/dist/ollama-probe.d.ts +13 -0
- package/dist/ollama-probe.d.ts.map +1 -0
- package/dist/ollama-probe.js +46 -0
- package/dist/ollama-probe.js.map +1 -0
- package/dist/opencode-client.d.ts +126 -0
- package/dist/opencode-client.d.ts.map +1 -0
- package/dist/opencode-client.js +181 -0
- package/dist/opencode-client.js.map +1 -0
- package/dist/output-parser.d.ts +3 -0
- package/dist/output-parser.d.ts.map +1 -1
- package/dist/output-parser.js +29 -3
- package/dist/output-parser.js.map +1 -1
- package/dist/passive-observer.d.ts +38 -0
- package/dist/passive-observer.d.ts.map +1 -0
- package/dist/passive-observer.js +632 -0
- package/dist/passive-observer.js.map +1 -0
- package/dist/pixoo/pixoo-bridge.d.ts +50 -0
- package/dist/pixoo/pixoo-bridge.d.ts.map +1 -0
- package/dist/pixoo/pixoo-bridge.js +280 -0
- package/dist/pixoo/pixoo-bridge.js.map +1 -0
- package/dist/pixoo/pixoo-camera.d.ts +80 -0
- package/dist/pixoo/pixoo-camera.d.ts.map +1 -0
- package/dist/pixoo/pixoo-camera.js +271 -0
- package/dist/pixoo/pixoo-camera.js.map +1 -0
- package/dist/pixoo/pixoo-client.d.ts +67 -0
- package/dist/pixoo/pixoo-client.d.ts.map +1 -0
- package/dist/pixoo/pixoo-client.js +335 -0
- package/dist/pixoo/pixoo-client.js.map +1 -0
- package/dist/pixoo/pixoo-font.d.ts +24 -0
- package/dist/pixoo/pixoo-font.d.ts.map +1 -0
- package/dist/pixoo/pixoo-font.js +121 -0
- package/dist/pixoo/pixoo-font.js.map +1 -0
- package/dist/pixoo/pixoo-renderer.d.ts +32 -0
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -0
- package/dist/pixoo/pixoo-renderer.js +696 -0
- package/dist/pixoo/pixoo-renderer.js.map +1 -0
- package/dist/pixoo/pixoo-settings.d.ts +10 -0
- package/dist/pixoo/pixoo-settings.d.ts.map +1 -0
- package/dist/pixoo/pixoo-settings.js +47 -0
- package/dist/pixoo/pixoo-settings.js.map +1 -0
- package/dist/pixoo/pixoo-sprites.d.ts +187 -0
- package/dist/pixoo/pixoo-sprites.d.ts.map +1 -0
- package/dist/pixoo/pixoo-sprites.js +926 -0
- package/dist/pixoo/pixoo-sprites.js.map +1 -0
- package/dist/pty-manager.d.ts +1 -1
- package/dist/pty-manager.d.ts.map +1 -1
- package/dist/pty-manager.js +36 -15
- package/dist/pty-manager.js.map +1 -1
- package/dist/session-aggregator.d.ts +41 -0
- package/dist/session-aggregator.d.ts.map +1 -0
- package/dist/session-aggregator.js +76 -0
- package/dist/session-aggregator.js.map +1 -0
- package/dist/session-focus-relay.d.ts +35 -0
- package/dist/session-focus-relay.d.ts.map +1 -0
- package/dist/session-focus-relay.js +127 -0
- package/dist/session-focus-relay.js.map +1 -0
- package/dist/session-registry.d.ts +88 -1
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +222 -15
- package/dist/session-registry.js.map +1 -1
- package/dist/session-timeline-relay.d.ts +27 -0
- package/dist/session-timeline-relay.d.ts.map +1 -0
- package/dist/session-timeline-relay.js +124 -0
- package/dist/session-timeline-relay.js.map +1 -0
- package/dist/state-machine.d.ts +1 -0
- package/dist/state-machine.d.ts.map +1 -1
- package/dist/state-machine.js +14 -0
- package/dist/state-machine.js.map +1 -1
- package/dist/terminal-status.d.ts +28 -0
- package/dist/terminal-status.d.ts.map +1 -0
- package/dist/terminal-status.js +152 -0
- package/dist/terminal-status.js.map +1 -0
- package/dist/timeline-store.d.ts +22 -0
- package/dist/timeline-store.d.ts.map +1 -0
- package/dist/timeline-store.js +79 -0
- package/dist/timeline-store.js.map +1 -0
- package/dist/timeline-summarizer.d.ts +14 -0
- package/dist/timeline-summarizer.d.ts.map +1 -0
- package/dist/timeline-summarizer.js +154 -0
- package/dist/timeline-summarizer.js.map +1 -0
- package/dist/tts.d.ts +25 -0
- package/dist/tts.d.ts.map +1 -0
- package/dist/tts.js +99 -0
- package/dist/tts.js.map +1 -0
- package/dist/tui/ansi.d.ts +92 -0
- package/dist/tui/ansi.d.ts.map +1 -0
- package/dist/tui/ansi.js +181 -0
- package/dist/tui/ansi.js.map +1 -0
- package/dist/tui/dashboard.d.ts +35 -0
- package/dist/tui/dashboard.d.ts.map +1 -0
- package/dist/tui/dashboard.js +436 -0
- package/dist/tui/dashboard.js.map +1 -0
- package/dist/tui/gauge.d.ts +15 -0
- package/dist/tui/gauge.d.ts.map +1 -0
- package/dist/tui/gauge.js +82 -0
- package/dist/tui/gauge.js.map +1 -0
- package/dist/tui/renderer.d.ts +15 -0
- package/dist/tui/renderer.d.ts.map +1 -0
- package/dist/tui/renderer.js +758 -0
- package/dist/tui/renderer.js.map +1 -0
- package/dist/tui/screen.d.ts +27 -0
- package/dist/tui/screen.d.ts.map +1 -0
- package/dist/tui/screen.js +109 -0
- package/dist/tui/screen.js.map +1 -0
- package/dist/tui/terrarium.d.ts +96 -0
- package/dist/tui/terrarium.d.ts.map +1 -0
- package/dist/tui/terrarium.js +912 -0
- package/dist/tui/terrarium.js.map +1 -0
- package/dist/types.d.ts +4 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -2
- package/dist/types.js.map +1 -1
- package/dist/usage-api.d.ts +9 -2
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +224 -42
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts +12 -0
- package/dist/usage-event.d.ts.map +1 -0
- package/dist/usage-event.js +78 -0
- package/dist/usage-event.js.map +1 -0
- package/dist/usage-tracker.d.ts +4 -0
- package/dist/usage-tracker.d.ts.map +1 -1
- package/dist/usage-tracker.js +17 -0
- package/dist/usage-tracker.js.map +1 -1
- package/dist/utility-proxy.d.ts +30 -0
- package/dist/utility-proxy.d.ts.map +1 -0
- package/dist/utility-proxy.js +217 -0
- package/dist/utility-proxy.js.map +1 -0
- package/dist/utils/project-name.d.ts +22 -0
- package/dist/utils/project-name.d.ts.map +1 -0
- package/dist/utils/project-name.js +72 -0
- package/dist/utils/project-name.js.map +1 -0
- package/dist/version-check.d.ts +26 -0
- package/dist/version-check.d.ts.map +1 -0
- package/dist/version-check.js +225 -0
- package/dist/version-check.js.map +1 -0
- package/dist/voice-assistant.d.ts +63 -0
- package/dist/voice-assistant.d.ts.map +1 -0
- package/dist/voice-assistant.js +406 -0
- package/dist/voice-assistant.js.map +1 -0
- package/dist/voice.d.ts +2 -0
- package/dist/voice.d.ts.map +1 -1
- package/dist/voice.js +26 -1
- package/dist/voice.js.map +1 -1
- package/dist/wake-word.d.ts +35 -0
- package/dist/wake-word.d.ts.map +1 -0
- package/dist/wake-word.js +225 -0
- package/dist/wake-word.js.map +1 -0
- package/dist/whisper-server-manager.d.ts +1 -1
- package/dist/whisper-server-manager.js +1 -1
- package/dist/wifi-config.d.ts +24 -0
- package/dist/wifi-config.d.ts.map +1 -0
- package/dist/wifi-config.js +84 -0
- package/dist/wifi-config.js.map +1 -0
- package/dist/ws-server.d.ts +12 -0
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +81 -3
- package/dist/ws-server.js.map +1 -1
- package/package.json +21 -13
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wake Word Listener — Porcupine (Picovoice) wrapper.
|
|
3
|
+
*
|
|
4
|
+
* Continuously captures audio from the Mac microphone via @picovoice/pvrecorder-node
|
|
5
|
+
* and runs Porcupine wake word detection for "오픈클로".
|
|
6
|
+
*
|
|
7
|
+
* Emits 'detected' when the wake word is heard.
|
|
8
|
+
* Provides start() / stop() / isListening() interface.
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from 'events';
|
|
11
|
+
import { existsSync, readFileSync, readdirSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { homedir } from 'os';
|
|
14
|
+
import { log, debug } from './logger.js';
|
|
15
|
+
import { WAKE_WORD_MODEL_DIR, PICOVOICE_ACCESS_KEY_FILE, } from '@agentdeck/shared';
|
|
16
|
+
const TAG = 'WakeWord';
|
|
17
|
+
/** Find the .ppn keyword model file in the wake word model directory */
|
|
18
|
+
function findPpnModel() {
|
|
19
|
+
if (!existsSync(WAKE_WORD_MODEL_DIR))
|
|
20
|
+
return null;
|
|
21
|
+
const files = readdirSync(WAKE_WORD_MODEL_DIR).filter(f => f.endsWith('.ppn'));
|
|
22
|
+
if (files.length === 0)
|
|
23
|
+
return null;
|
|
24
|
+
const preferred = files.find(f => /openclaw|오픈클로/i.test(f));
|
|
25
|
+
return join(WAKE_WORD_MODEL_DIR, preferred ?? files[0]);
|
|
26
|
+
}
|
|
27
|
+
/** Find the Porcupine language model (.pv) — Korean for "오픈클로" */
|
|
28
|
+
function findLanguageModel() {
|
|
29
|
+
// 1. Check wake-word dir for language model
|
|
30
|
+
if (existsSync(WAKE_WORD_MODEL_DIR)) {
|
|
31
|
+
const pvFiles = readdirSync(WAKE_WORD_MODEL_DIR).filter(f => f.endsWith('.pv'));
|
|
32
|
+
const koModel = pvFiles.find(f => /ko|korean/i.test(f));
|
|
33
|
+
if (koModel)
|
|
34
|
+
return join(WAKE_WORD_MODEL_DIR, koModel);
|
|
35
|
+
if (pvFiles.length > 0)
|
|
36
|
+
return join(WAKE_WORD_MODEL_DIR, pvFiles[0]);
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
/** Read Picovoice access key from file */
|
|
41
|
+
function readAccessKey() {
|
|
42
|
+
try {
|
|
43
|
+
if (!existsSync(PICOVOICE_ACCESS_KEY_FILE))
|
|
44
|
+
return null;
|
|
45
|
+
return readFileSync(PICOVOICE_ACCESS_KEY_FILE, 'utf-8').trim();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const DEFAULT_SENSITIVITY = 0.8;
|
|
52
|
+
/** Read wakeWordMic + wakeWordSensitivity from settings.json */
|
|
53
|
+
function getWakeWordSettings(PvRecorder) {
|
|
54
|
+
let deviceIndex = -1;
|
|
55
|
+
let sensitivity = DEFAULT_SENSITIVITY;
|
|
56
|
+
try {
|
|
57
|
+
const settings = JSON.parse(readFileSync(join(homedir(), '.agentdeck', 'settings.json'), 'utf-8'));
|
|
58
|
+
// Mic
|
|
59
|
+
const micName = settings.wakeWordMic;
|
|
60
|
+
if (micName) {
|
|
61
|
+
const devices = PvRecorder.getAvailableDevices();
|
|
62
|
+
const idx = devices.findIndex((d) => d.toLowerCase().includes(micName.toLowerCase()));
|
|
63
|
+
if (idx >= 0) {
|
|
64
|
+
debug(TAG, `Configured mic "${micName}" → device ${idx}: ${devices[idx]}`);
|
|
65
|
+
deviceIndex = idx;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
debug(TAG, `Configured mic "${micName}" not found, using system default`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// Sensitivity
|
|
72
|
+
const sens = settings.wakeWordSensitivity;
|
|
73
|
+
if (typeof sens === 'number' && sens >= 0 && sens <= 1) {
|
|
74
|
+
sensitivity = sens;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch { /* ok */ }
|
|
78
|
+
return { deviceIndex, sensitivity };
|
|
79
|
+
}
|
|
80
|
+
export class WakeWordListener extends EventEmitter {
|
|
81
|
+
listening = false;
|
|
82
|
+
/** Whether the detection loop is actively running (false during pause) */
|
|
83
|
+
active = false;
|
|
84
|
+
porcupine = null;
|
|
85
|
+
recorder = null;
|
|
86
|
+
accessKey;
|
|
87
|
+
keywordPath;
|
|
88
|
+
languageModelPath;
|
|
89
|
+
constructor() {
|
|
90
|
+
super();
|
|
91
|
+
this.accessKey = readAccessKey() ?? '';
|
|
92
|
+
this.keywordPath = findPpnModel() ?? '';
|
|
93
|
+
this.languageModelPath = findLanguageModel();
|
|
94
|
+
}
|
|
95
|
+
/** Check if wake word detection is available (deps + model + key) */
|
|
96
|
+
isAvailable() {
|
|
97
|
+
if (!this.accessKey) {
|
|
98
|
+
debug(TAG, `Access key not found at ${PICOVOICE_ACCESS_KEY_FILE}`);
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
if (!this.keywordPath || !existsSync(this.keywordPath)) {
|
|
102
|
+
debug(TAG, `No .ppn model found in ${WAKE_WORD_MODEL_DIR}`);
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
async start() {
|
|
108
|
+
if (this.listening)
|
|
109
|
+
return true;
|
|
110
|
+
if (!this.isAvailable()) {
|
|
111
|
+
debug(TAG, 'Cannot start — missing access key or model');
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
// Dynamic imports — these are optional deps
|
|
116
|
+
const { Porcupine } = await import('@picovoice/porcupine-node');
|
|
117
|
+
const { PvRecorder } = await import('@picovoice/pvrecorder-node');
|
|
118
|
+
const options = {};
|
|
119
|
+
if (this.languageModelPath) {
|
|
120
|
+
options.modelPath = this.languageModelPath;
|
|
121
|
+
debug(TAG, `Using language model: ${this.languageModelPath}`);
|
|
122
|
+
}
|
|
123
|
+
const wwSettings = getWakeWordSettings(PvRecorder);
|
|
124
|
+
this.porcupine = new Porcupine(this.accessKey, [this.keywordPath], [wwSettings.sensitivity], options);
|
|
125
|
+
const frameLength = this.porcupine.frameLength;
|
|
126
|
+
const deviceIndex = wwSettings.deviceIndex;
|
|
127
|
+
this.recorder = new PvRecorder(frameLength, deviceIndex);
|
|
128
|
+
this.recorder.start();
|
|
129
|
+
this.listening = true;
|
|
130
|
+
this.active = true;
|
|
131
|
+
log(`Listening on "${this.recorder.getSelectedDevice()}"`);
|
|
132
|
+
debug(TAG, `Listening on "${this.recorder.getSelectedDevice()}" (keyword: ${this.keywordPath})`);
|
|
133
|
+
// Detection loop
|
|
134
|
+
this.runDetectionLoop();
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
139
|
+
debug(TAG, `Failed to start: ${msg}`);
|
|
140
|
+
this.cleanup();
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
stop() {
|
|
145
|
+
if (!this.listening)
|
|
146
|
+
return;
|
|
147
|
+
debug(TAG, 'Stopping');
|
|
148
|
+
this.listening = false;
|
|
149
|
+
this.active = false;
|
|
150
|
+
this.cleanup();
|
|
151
|
+
}
|
|
152
|
+
isListening() {
|
|
153
|
+
return this.listening;
|
|
154
|
+
}
|
|
155
|
+
/** Temporarily pause detection (e.g., while recording user speech).
|
|
156
|
+
* Sets active=false so the detection loop exits naturally,
|
|
157
|
+
* then stops the recorder. */
|
|
158
|
+
pause() {
|
|
159
|
+
if (this.recorder && this.listening && this.active) {
|
|
160
|
+
this.active = false;
|
|
161
|
+
try {
|
|
162
|
+
this.recorder.stop();
|
|
163
|
+
}
|
|
164
|
+
catch { /* ok */ }
|
|
165
|
+
debug(TAG, 'Paused');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/** Resume detection after pause — starts a fresh detection loop */
|
|
169
|
+
resume() {
|
|
170
|
+
if (this.recorder && this.listening && !this.active) {
|
|
171
|
+
try {
|
|
172
|
+
this.recorder.start();
|
|
173
|
+
}
|
|
174
|
+
catch { /* ok */ }
|
|
175
|
+
this.active = true;
|
|
176
|
+
debug(TAG, 'Resumed');
|
|
177
|
+
this.runDetectionLoop();
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async runDetectionLoop() {
|
|
181
|
+
while (this.active && this.listening && this.recorder && this.porcupine) {
|
|
182
|
+
try {
|
|
183
|
+
const pcm = await this.recorder.read();
|
|
184
|
+
if (!this.active)
|
|
185
|
+
break;
|
|
186
|
+
const keywordIndex = this.porcupine.process(pcm);
|
|
187
|
+
if (keywordIndex >= 0) {
|
|
188
|
+
log('Detected!');
|
|
189
|
+
this.emit('detected', {
|
|
190
|
+
deviceId: 'mac-builtin',
|
|
191
|
+
timestamp: Date.now(),
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
if (!this.active || !this.listening)
|
|
197
|
+
break;
|
|
198
|
+
debug(TAG, `Detection loop error: ${err}`);
|
|
199
|
+
await new Promise(r => setTimeout(r, 100));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
debug(TAG, `Detection loop exited (active=${this.active}, listening=${this.listening})`);
|
|
203
|
+
}
|
|
204
|
+
cleanup() {
|
|
205
|
+
if (this.recorder) {
|
|
206
|
+
try {
|
|
207
|
+
this.recorder.stop();
|
|
208
|
+
}
|
|
209
|
+
catch { /* ok */ }
|
|
210
|
+
try {
|
|
211
|
+
this.recorder.release();
|
|
212
|
+
}
|
|
213
|
+
catch { /* ok */ }
|
|
214
|
+
this.recorder = null;
|
|
215
|
+
}
|
|
216
|
+
if (this.porcupine) {
|
|
217
|
+
try {
|
|
218
|
+
this.porcupine.release();
|
|
219
|
+
}
|
|
220
|
+
catch { /* ok */ }
|
|
221
|
+
this.porcupine = null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=wake-word.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wake-word.js","sourceRoot":"","sources":["../src/wake-word.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Whisper-server singleton manager.
|
|
3
3
|
*
|
|
4
|
-
* Fixed port 9100 — one server shared across all
|
|
4
|
+
* Fixed port 9100 — one server shared across all agentdeck sessions.
|
|
5
5
|
* Info file at ~/.agentdeck/whisper-server.json for discovery.
|
|
6
6
|
* Last session to exit kills the server.
|
|
7
7
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Whisper-server singleton manager.
|
|
3
3
|
*
|
|
4
|
-
* Fixed port 9100 — one server shared across all
|
|
4
|
+
* Fixed port 9100 — one server shared across all agentdeck sessions.
|
|
5
5
|
* Info file at ~/.agentdeck/whisper-server.json for discovery.
|
|
6
6
|
* Last session to exit kills the server.
|
|
7
7
|
*/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WiFi credential management for ESP32 auto-provisioning.
|
|
3
|
+
*
|
|
4
|
+
* Stores SSID/password in ~/.agentdeck/wifi-config.json.
|
|
5
|
+
* Can auto-detect current macOS WiFi SSID and query Keychain for password.
|
|
6
|
+
*/
|
|
7
|
+
export interface WifiConfig {
|
|
8
|
+
ssid: string;
|
|
9
|
+
password: string;
|
|
10
|
+
autoProvision: boolean;
|
|
11
|
+
}
|
|
12
|
+
/** Load saved WiFi config, or null if not configured. */
|
|
13
|
+
export declare function loadWifiConfig(): WifiConfig | null;
|
|
14
|
+
/** Save WiFi config to disk. */
|
|
15
|
+
export declare function saveWifiConfig(config: WifiConfig): void;
|
|
16
|
+
/** Detect current macOS WiFi SSID. Returns null on other platforms or if not connected. */
|
|
17
|
+
export declare function detectCurrentSSID(): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Try to retrieve WiFi password from macOS Keychain.
|
|
20
|
+
* Requires user approval (Touch ID / password dialog) on first access.
|
|
21
|
+
* Returns null if not found or denied.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getKeychainPassword(ssid: string): string | null;
|
|
24
|
+
//# sourceMappingURL=wifi-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wifi-config.d.ts","sourceRoot":"","sources":["../src/wifi-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,yDAAyD;AACzD,wBAAgB,cAAc,IAAI,UAAU,GAAG,IAAI,CAelD;AAED,gCAAgC;AAChC,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CASvD;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAoBjD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW/D"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WiFi credential management for ESP32 auto-provisioning.
|
|
3
|
+
*
|
|
4
|
+
* Stores SSID/password in ~/.agentdeck/wifi-config.json.
|
|
5
|
+
* Can auto-detect current macOS WiFi SSID and query Keychain for password.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { homedir } from 'os';
|
|
10
|
+
import { execSync } from 'child_process';
|
|
11
|
+
import { debug } from './logger.js';
|
|
12
|
+
const AGENTDECK_DIR = join(homedir(), '.agentdeck');
|
|
13
|
+
const WIFI_CONFIG_FILE = join(AGENTDECK_DIR, 'wifi-config.json');
|
|
14
|
+
/** Load saved WiFi config, or null if not configured. */
|
|
15
|
+
export function loadWifiConfig() {
|
|
16
|
+
try {
|
|
17
|
+
if (!existsSync(WIFI_CONFIG_FILE))
|
|
18
|
+
return null;
|
|
19
|
+
const data = JSON.parse(readFileSync(WIFI_CONFIG_FILE, 'utf-8'));
|
|
20
|
+
if (data.ssid && data.password) {
|
|
21
|
+
return {
|
|
22
|
+
ssid: data.ssid,
|
|
23
|
+
password: data.password,
|
|
24
|
+
autoProvision: data.autoProvision !== false,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
debug('wifi-config', 'Failed to load wifi-config.json');
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
/** Save WiFi config to disk. */
|
|
34
|
+
export function saveWifiConfig(config) {
|
|
35
|
+
try {
|
|
36
|
+
mkdirSync(AGENTDECK_DIR, { recursive: true });
|
|
37
|
+
writeFileSync(WIFI_CONFIG_FILE, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
|
|
38
|
+
debug('wifi-config', `Saved WiFi config for SSID: ${config.ssid}`);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
debug('wifi-config', `Failed to save wifi-config.json: ${err}`);
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Detect current macOS WiFi SSID. Returns null on other platforms or if not connected. */
|
|
46
|
+
export function detectCurrentSSID() {
|
|
47
|
+
if (process.platform !== 'darwin')
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
// Find the actual Wi-Fi interface (not always en0 — e.g. en1 on Mac Studio)
|
|
51
|
+
const ports = execSync('networksetup -listallhardwareports', {
|
|
52
|
+
encoding: 'utf-8', timeout: 3000,
|
|
53
|
+
});
|
|
54
|
+
const wifiMatch = ports.match(/Hardware Port: Wi-Fi\nDevice: (en\d+)/);
|
|
55
|
+
const iface = wifiMatch ? wifiMatch[1] : 'en0';
|
|
56
|
+
const output = execSync(`networksetup -getairportnetwork ${iface}`, {
|
|
57
|
+
encoding: 'utf-8',
|
|
58
|
+
timeout: 3000,
|
|
59
|
+
}).trim();
|
|
60
|
+
// Output: "Current Wi-Fi Network: MyNetwork"
|
|
61
|
+
const match = output.match(/Current Wi-Fi Network:\s*(.+)/);
|
|
62
|
+
return match ? match[1].trim() : null;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Try to retrieve WiFi password from macOS Keychain.
|
|
70
|
+
* Requires user approval (Touch ID / password dialog) on first access.
|
|
71
|
+
* Returns null if not found or denied.
|
|
72
|
+
*/
|
|
73
|
+
export function getKeychainPassword(ssid) {
|
|
74
|
+
if (process.platform !== 'darwin')
|
|
75
|
+
return null;
|
|
76
|
+
try {
|
|
77
|
+
const output = execSync(`security find-generic-password -ga "${ssid.replace(/"/g, '\\"')}" -w 2>/dev/null`, { encoding: 'utf-8', timeout: 10000 }).trim();
|
|
78
|
+
return output || null;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=wifi-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wifi-config.js","sourceRoot":"","sources":["../src/wifi-config.ts"],"names":[],"mappings":"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"}
|
package/dist/ws-server.d.ts
CHANGED
|
@@ -4,11 +4,23 @@ import type { BridgeEvent, PluginCommand } from './types.js';
|
|
|
4
4
|
export declare class WsServer {
|
|
5
5
|
private wss;
|
|
6
6
|
private commandCallback;
|
|
7
|
+
private rawMessageCallback;
|
|
7
8
|
private onConnectCallback;
|
|
8
9
|
private onDisconnectCallback;
|
|
10
|
+
private clientAlive;
|
|
11
|
+
private pingTimer;
|
|
9
12
|
constructor(server: Server);
|
|
13
|
+
private broadcastHooks;
|
|
14
|
+
/** Register a hook that gets called on every broadcast (e.g., ESP32 serial relay). */
|
|
15
|
+
onBroadcast(hook: (event: BridgeEvent) => void): void;
|
|
10
16
|
broadcast(event: BridgeEvent): void;
|
|
11
17
|
onCommand(callback: (cmd: PluginCommand) => void): void;
|
|
18
|
+
/** Inject a command from a non-WS source (e.g., D200H agent via stdout/stdin pipe). */
|
|
19
|
+
dispatchCommand(cmd: PluginCommand): void;
|
|
20
|
+
/** Register a callback for raw messages before PluginCommand dispatch. Return true to consume. */
|
|
21
|
+
onRawMessage(callback: (msg: Record<string, unknown>, sender: WebSocket) => boolean): void;
|
|
22
|
+
/** Broadcast to all clients except the sender */
|
|
23
|
+
broadcastExcept(event: BridgeEvent, except: WebSocket): void;
|
|
12
24
|
onClientConnect(callback: (ws: WebSocket) => void): void;
|
|
13
25
|
onClientDisconnect(callback: () => void): void;
|
|
14
26
|
sendTo(ws: WebSocket, event: BridgeEvent): void;
|
package/dist/ws-server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-server.d.ts","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"ws-server.d.ts","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,SAAS,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,MAAM,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAK7D,qBAAa,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,kBAAkB,CAA+E;IACzG,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,SAAS,CAAiC;gBAEtC,MAAM,EAAE,MAAM;IAqF1B,OAAO,CAAC,cAAc,CAA2C;IAEjE,sFAAsF;IACtF,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,IAAI;IAIrD,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAenC,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IAIvD,uFAAuF;IACvF,eAAe,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI;IAIzC,kGAAkG;IAClG,YAAY,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,GAAG,IAAI;IAI1F,iDAAiD;IACjD,eAAe,CAAC,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI;IAS5D,eAAe,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,GAAG,IAAI;IAIxD,kBAAkB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAI9C,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI;IAM/C,cAAc,IAAI,MAAM;IAIxB,KAAK,IAAI,IAAI;CASd"}
|
package/dist/ws-server.js
CHANGED
|
@@ -1,13 +1,41 @@
|
|
|
1
1
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
2
2
|
import { isLocalConnection, validateToken } from './auth.js';
|
|
3
3
|
import { debug } from './logger.js';
|
|
4
|
+
import { WS_PING_INTERVAL_MS } from '@agentdeck/shared';
|
|
4
5
|
export class WsServer {
|
|
5
6
|
wss;
|
|
6
7
|
commandCallback = null;
|
|
8
|
+
rawMessageCallback = null;
|
|
7
9
|
onConnectCallback = null;
|
|
8
10
|
onDisconnectCallback = null;
|
|
11
|
+
clientAlive = new Map();
|
|
12
|
+
pingTimer;
|
|
9
13
|
constructor(server) {
|
|
10
14
|
this.wss = new WebSocketServer({ server });
|
|
15
|
+
// Catch server-level errors (e.g., upgrade failures, internal ws errors)
|
|
16
|
+
// Without this handler, EventEmitter throws synchronously → process dies
|
|
17
|
+
this.wss.on('error', (err) => {
|
|
18
|
+
debug('WS', `WebSocketServer error: ${err}`);
|
|
19
|
+
});
|
|
20
|
+
// Server-side ping/pong to detect zombie connections
|
|
21
|
+
this.pingTimer = setInterval(() => {
|
|
22
|
+
const dead = [];
|
|
23
|
+
for (const ws of this.wss.clients) {
|
|
24
|
+
if (this.clientAlive.get(ws) === false) {
|
|
25
|
+
dead.push(ws);
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
this.clientAlive.set(ws, false);
|
|
29
|
+
ws.ping();
|
|
30
|
+
}
|
|
31
|
+
// Terminate outside iteration — ws.terminate() synchronously removes
|
|
32
|
+
// the client from wss.clients Set, which would corrupt the iterator.
|
|
33
|
+
for (const ws of dead) {
|
|
34
|
+
debug('WS', 'Terminating unresponsive client');
|
|
35
|
+
this.clientAlive.delete(ws);
|
|
36
|
+
ws.terminate();
|
|
37
|
+
}
|
|
38
|
+
}, WS_PING_INTERVAL_MS);
|
|
11
39
|
this.wss.on('connection', (ws, req) => {
|
|
12
40
|
// Token auth for remote connections
|
|
13
41
|
const remoteIp = req.socket.remoteAddress || '';
|
|
@@ -22,14 +50,22 @@ export class WsServer {
|
|
|
22
50
|
debug('WS', `Remote client authenticated from ${remoteIp}`);
|
|
23
51
|
}
|
|
24
52
|
debug('WS', 'Plugin connected');
|
|
53
|
+
this.clientAlive.set(ws, true);
|
|
25
54
|
// Send current state to newly connected client
|
|
26
55
|
if (this.onConnectCallback) {
|
|
27
56
|
this.onConnectCallback(ws);
|
|
28
57
|
}
|
|
58
|
+
ws.on('pong', () => {
|
|
59
|
+
this.clientAlive.set(ws, true);
|
|
60
|
+
});
|
|
29
61
|
ws.on('message', (data) => {
|
|
30
62
|
try {
|
|
31
63
|
const msg = JSON.parse(data.toString());
|
|
32
64
|
debug('WS', `recv cmd: ${msg.type}`);
|
|
65
|
+
// Allow raw message callback to intercept relay events (e.g. deck_slot_map)
|
|
66
|
+
if (this.rawMessageCallback && this.rawMessageCallback(msg, ws)) {
|
|
67
|
+
return; // handled
|
|
68
|
+
}
|
|
33
69
|
if (this.commandCallback) {
|
|
34
70
|
this.commandCallback(msg);
|
|
35
71
|
}
|
|
@@ -40,6 +76,7 @@ export class WsServer {
|
|
|
40
76
|
});
|
|
41
77
|
ws.on('close', () => {
|
|
42
78
|
debug('WS', 'Plugin disconnected');
|
|
79
|
+
this.clientAlive.delete(ws);
|
|
43
80
|
if (this.onDisconnectCallback) {
|
|
44
81
|
this.onDisconnectCallback();
|
|
45
82
|
}
|
|
@@ -49,19 +86,54 @@ export class WsServer {
|
|
|
49
86
|
});
|
|
50
87
|
});
|
|
51
88
|
}
|
|
89
|
+
broadcastHooks = [];
|
|
90
|
+
/** Register a hook that gets called on every broadcast (e.g., ESP32 serial relay). */
|
|
91
|
+
onBroadcast(hook) {
|
|
92
|
+
this.broadcastHooks.push(hook);
|
|
93
|
+
}
|
|
52
94
|
broadcast(event) {
|
|
53
95
|
const payload = JSON.stringify(event);
|
|
54
96
|
const clientCount = this.wss.clients.size;
|
|
55
97
|
debug('WS', `broadcast(${event.type}) to ${clientCount} clients`);
|
|
56
98
|
for (const client of this.wss.clients) {
|
|
57
99
|
if (client.readyState === WebSocket.OPEN) {
|
|
58
|
-
|
|
100
|
+
try {
|
|
101
|
+
client.send(payload);
|
|
102
|
+
}
|
|
103
|
+
catch { /* client disconnecting */ }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Relay to registered hooks (ESP32 serial, etc.)
|
|
107
|
+
for (const hook of this.broadcastHooks) {
|
|
108
|
+
try {
|
|
109
|
+
hook(event);
|
|
59
110
|
}
|
|
111
|
+
catch { /* best-effort */ }
|
|
60
112
|
}
|
|
61
113
|
}
|
|
62
114
|
onCommand(callback) {
|
|
63
115
|
this.commandCallback = callback;
|
|
64
116
|
}
|
|
117
|
+
/** Inject a command from a non-WS source (e.g., D200H agent via stdout/stdin pipe). */
|
|
118
|
+
dispatchCommand(cmd) {
|
|
119
|
+
this.commandCallback?.(cmd);
|
|
120
|
+
}
|
|
121
|
+
/** Register a callback for raw messages before PluginCommand dispatch. Return true to consume. */
|
|
122
|
+
onRawMessage(callback) {
|
|
123
|
+
this.rawMessageCallback = callback;
|
|
124
|
+
}
|
|
125
|
+
/** Broadcast to all clients except the sender */
|
|
126
|
+
broadcastExcept(event, except) {
|
|
127
|
+
const payload = JSON.stringify(event);
|
|
128
|
+
for (const client of this.wss.clients) {
|
|
129
|
+
if (client !== except && client.readyState === WebSocket.OPEN) {
|
|
130
|
+
try {
|
|
131
|
+
client.send(payload);
|
|
132
|
+
}
|
|
133
|
+
catch { /* client disconnecting */ }
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
65
137
|
onClientConnect(callback) {
|
|
66
138
|
this.onConnectCallback = callback;
|
|
67
139
|
}
|
|
@@ -70,14 +142,20 @@ export class WsServer {
|
|
|
70
142
|
}
|
|
71
143
|
sendTo(ws, event) {
|
|
72
144
|
if (ws.readyState === WebSocket.OPEN) {
|
|
73
|
-
|
|
145
|
+
try {
|
|
146
|
+
ws.send(JSON.stringify(event));
|
|
147
|
+
}
|
|
148
|
+
catch { /* client disconnecting */ }
|
|
74
149
|
}
|
|
75
150
|
}
|
|
76
151
|
getClientCount() {
|
|
77
152
|
return this.wss.clients.size;
|
|
78
153
|
}
|
|
79
154
|
close() {
|
|
80
|
-
|
|
155
|
+
clearInterval(this.pingTimer);
|
|
156
|
+
this.clientAlive.clear();
|
|
157
|
+
// Spread to array — client.close() modifies wss.clients Set
|
|
158
|
+
for (const client of [...this.wss.clients]) {
|
|
81
159
|
client.close();
|
|
82
160
|
}
|
|
83
161
|
this.wss.close();
|
package/dist/ws-server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-server.js","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAGhD,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ws-server.js","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentdeck/bridge",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -14,30 +14,38 @@
|
|
|
14
14
|
],
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
16
|
"bin": {
|
|
17
|
-
"
|
|
17
|
+
"agentdeck": "./dist/cli.js"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"bonjour-service": "^1.3.0",
|
|
21
|
-
"commander": "^
|
|
22
|
-
"express": "^
|
|
23
|
-
"node-pty": "^1.0.0",
|
|
21
|
+
"commander": "^14.0.3",
|
|
22
|
+
"express": "^5.2.1",
|
|
24
23
|
"qrcode": "^1.5.4",
|
|
25
|
-
"strip-ansi": "^7.
|
|
26
|
-
"ws": "^8.
|
|
27
|
-
"@agentdeck/shared": "0.
|
|
24
|
+
"strip-ansi": "^7.2.0",
|
|
25
|
+
"ws": "^8.20.0",
|
|
26
|
+
"@agentdeck/shared": "0.2.0"
|
|
28
27
|
},
|
|
28
|
+
"optionalDependencies": {
|
|
29
|
+
"@picovoice/porcupine-node": "^4.0.2",
|
|
30
|
+
"@picovoice/pvrecorder-node": "^1.2.8",
|
|
31
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
32
|
+
"better-sqlite3": "^12.9.0",
|
|
33
|
+
"node-hid": "^3.3.0",
|
|
34
|
+
"node-pty": "^1.1.0"
|
|
35
|
+
},
|
|
36
|
+
"compatibleClaudeCode": ">=2.1.50",
|
|
29
37
|
"devDependencies": {
|
|
30
|
-
"@types/express": "^
|
|
31
|
-
"@types/node": "^
|
|
38
|
+
"@types/express": "^5.0.6",
|
|
39
|
+
"@types/node": "^25.6.0",
|
|
32
40
|
"@types/qrcode": "^1.5.6",
|
|
33
|
-
"@types/ws": "^8.
|
|
34
|
-
"typescript": "^
|
|
41
|
+
"@types/ws": "^8.18.1",
|
|
42
|
+
"typescript": "^6.0.3"
|
|
35
43
|
},
|
|
36
44
|
"scripts": {
|
|
37
45
|
"build": "tsc",
|
|
38
46
|
"dev": "tsc --watch",
|
|
39
47
|
"clean": "rm -rf dist",
|
|
40
48
|
"typecheck": "tsc --noEmit",
|
|
41
|
-
"start": "node dist/
|
|
49
|
+
"start": "node dist/cli.js claude"
|
|
42
50
|
}
|
|
43
51
|
}
|