@agentdeck/bridge 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/adapters/claude-code.d.ts +38 -0
  2. package/dist/adapters/claude-code.d.ts.map +1 -0
  3. package/dist/adapters/claude-code.js +184 -0
  4. package/dist/adapters/claude-code.js.map +1 -0
  5. package/dist/adapters/index.d.ts +8 -0
  6. package/dist/adapters/index.d.ts.map +1 -0
  7. package/dist/adapters/index.js +18 -0
  8. package/dist/adapters/index.js.map +1 -0
  9. package/dist/adapters/openclaw.d.ts +70 -0
  10. package/dist/adapters/openclaw.d.ts.map +1 -0
  11. package/dist/adapters/openclaw.js +664 -0
  12. package/dist/adapters/openclaw.js.map +1 -0
  13. package/dist/auth.d.ts +9 -0
  14. package/dist/auth.d.ts.map +1 -0
  15. package/dist/auth.js +64 -0
  16. package/dist/auth.js.map +1 -0
  17. package/dist/check-deps.d.ts +5 -0
  18. package/dist/check-deps.d.ts.map +1 -0
  19. package/dist/check-deps.js +47 -0
  20. package/dist/check-deps.js.map +1 -0
  21. package/dist/diag-analyzer.d.ts +29 -0
  22. package/dist/diag-analyzer.d.ts.map +1 -0
  23. package/dist/diag-analyzer.js +145 -0
  24. package/dist/diag-analyzer.js.map +1 -0
  25. package/dist/event-journal.d.ts +22 -0
  26. package/dist/event-journal.d.ts.map +1 -0
  27. package/dist/event-journal.js +117 -0
  28. package/dist/event-journal.js.map +1 -0
  29. package/dist/hook-server.d.ts +31 -0
  30. package/dist/hook-server.d.ts.map +1 -0
  31. package/dist/hook-server.js +260 -0
  32. package/dist/hook-server.js.map +1 -0
  33. package/dist/index.d.ts +3 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +796 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/logger.d.ts +11 -0
  38. package/dist/logger.d.ts.map +1 -0
  39. package/dist/logger.js +27 -0
  40. package/dist/logger.js.map +1 -0
  41. package/dist/mdns.d.ts +9 -0
  42. package/dist/mdns.d.ts.map +1 -0
  43. package/dist/mdns.js +44 -0
  44. package/dist/mdns.js.map +1 -0
  45. package/dist/model-catalog.d.ts +29 -0
  46. package/dist/model-catalog.d.ts.map +1 -0
  47. package/dist/model-catalog.js +91 -0
  48. package/dist/model-catalog.js.map +1 -0
  49. package/dist/output-parser.d.ts +65 -0
  50. package/dist/output-parser.d.ts.map +1 -0
  51. package/dist/output-parser.js +1089 -0
  52. package/dist/output-parser.js.map +1 -0
  53. package/dist/pty-manager.d.ts +14 -0
  54. package/dist/pty-manager.d.ts.map +1 -0
  55. package/dist/pty-manager.js +93 -0
  56. package/dist/pty-manager.js.map +1 -0
  57. package/dist/pty-ringbuffer.d.ts +23 -0
  58. package/dist/pty-ringbuffer.d.ts.map +1 -0
  59. package/dist/pty-ringbuffer.js +65 -0
  60. package/dist/pty-ringbuffer.js.map +1 -0
  61. package/dist/session-registry.d.ts +17 -0
  62. package/dist/session-registry.d.ts.map +1 -0
  63. package/dist/session-registry.js +107 -0
  64. package/dist/session-registry.js.map +1 -0
  65. package/dist/state-machine.d.ts +48 -0
  66. package/dist/state-machine.d.ts.map +1 -0
  67. package/dist/state-machine.js +470 -0
  68. package/dist/state-machine.js.map +1 -0
  69. package/dist/types.d.ts +28 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +4 -0
  72. package/dist/types.js.map +1 -0
  73. package/dist/usage-api.d.ts +16 -0
  74. package/dist/usage-api.d.ts.map +1 -0
  75. package/dist/usage-api.js +84 -0
  76. package/dist/usage-api.js.map +1 -0
  77. package/dist/usage-tracker.d.ts +24 -0
  78. package/dist/usage-tracker.d.ts.map +1 -0
  79. package/dist/usage-tracker.js +89 -0
  80. package/dist/usage-tracker.js.map +1 -0
  81. package/dist/voice.d.ts +27 -0
  82. package/dist/voice.d.ts.map +1 -0
  83. package/dist/voice.js +412 -0
  84. package/dist/voice.js.map +1 -0
  85. package/dist/whisper-server-manager.d.ts +19 -0
  86. package/dist/whisper-server-manager.d.ts.map +1 -0
  87. package/dist/whisper-server-manager.js +171 -0
  88. package/dist/whisper-server-manager.js.map +1 -0
  89. package/dist/ws-server.d.ts +18 -0
  90. package/dist/ws-server.d.ts.map +1 -0
  91. package/dist/ws-server.js +86 -0
  92. package/dist/ws-server.js.map +1 -0
  93. package/package.json +43 -0
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Whisper-server singleton manager.
3
+ *
4
+ * Fixed port 9100 — one server shared across all sdc sessions.
5
+ * Info file at ~/.agentdeck/whisper-server.json for discovery.
6
+ * Last session to exit kills the server.
7
+ */
8
+ import { spawn } from 'child_process';
9
+ import { readFileSync, writeFileSync, renameSync, unlinkSync, mkdirSync, existsSync, } from 'fs';
10
+ import { join } from 'path';
11
+ import { homedir } from 'os';
12
+ import { randomUUID } from 'crypto';
13
+ import { listActive } from './session-registry.js';
14
+ import { debug } from './logger.js';
15
+ export const WHISPER_SERVER_PORT = 9100;
16
+ const INFO_DIR = join(homedir(), '.agentdeck');
17
+ const INFO_FILE = join(INFO_DIR, 'whisper-server.json');
18
+ function ensureDir() {
19
+ if (!existsSync(INFO_DIR)) {
20
+ mkdirSync(INFO_DIR, { recursive: true });
21
+ }
22
+ }
23
+ function readInfo() {
24
+ try {
25
+ return JSON.parse(readFileSync(INFO_FILE, 'utf-8'));
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ function writeInfo(info) {
32
+ ensureDir();
33
+ const tmp = join(INFO_DIR, `.whisper-server.${randomUUID()}.tmp`);
34
+ writeFileSync(tmp, JSON.stringify(info, null, 2), 'utf-8');
35
+ renameSync(tmp, INFO_FILE);
36
+ }
37
+ function removeInfo() {
38
+ try {
39
+ unlinkSync(INFO_FILE);
40
+ }
41
+ catch { /* already gone */ }
42
+ }
43
+ function isProcessAlive(pid) {
44
+ try {
45
+ process.kill(pid, 0);
46
+ return true;
47
+ }
48
+ catch {
49
+ return false;
50
+ }
51
+ }
52
+ async function isServerResponding(port) {
53
+ try {
54
+ await fetch(`http://127.0.0.1:${port}`, { signal: AbortSignal.timeout(1000) });
55
+ return true;
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }
61
+ async function pollUntilReady(port, maxMs) {
62
+ const start = Date.now();
63
+ while (Date.now() - start < maxMs) {
64
+ if (await isServerResponding(port))
65
+ return true;
66
+ await new Promise((r) => setTimeout(r, 500));
67
+ }
68
+ return false;
69
+ }
70
+ /**
71
+ * Ensure a whisper-server is running on the singleton port.
72
+ * Returns port on success, null if unavailable (binary missing, model missing, etc).
73
+ */
74
+ export async function ensureWhisperServer(serverBin, modelPath) {
75
+ if (!existsSync(serverBin)) {
76
+ debug('WhisperMgr', `whisper-server not found at ${serverBin}, skipping`);
77
+ return null;
78
+ }
79
+ // 1. Check existing info file
80
+ const info = readInfo();
81
+ if (info) {
82
+ if (isProcessAlive(info.pid)) {
83
+ // PID alive — check if server is responding
84
+ if (await isServerResponding(info.port)) {
85
+ debug('WhisperMgr', `Reusing existing server (pid=${info.pid}, port=${info.port})`);
86
+ return info.port;
87
+ }
88
+ // PID alive but not responding — model may still be loading, poll 30s
89
+ debug('WhisperMgr', `Server pid=${info.pid} alive but not responding, waiting for model load...`);
90
+ if (await pollUntilReady(info.port, 30_000)) {
91
+ debug('WhisperMgr', `Server became ready (pid=${info.pid}, port=${info.port})`);
92
+ return info.port;
93
+ }
94
+ // Still not responding after 30s — stale
95
+ debug('WhisperMgr', `Server pid=${info.pid} never responded, treating as stale`);
96
+ }
97
+ // PID dead or stale — clean up
98
+ removeInfo();
99
+ }
100
+ // 2. Spawn new server (detached so it survives parent exit)
101
+ debug('WhisperMgr', `Starting whisper-server on port ${WHISPER_SERVER_PORT}...`);
102
+ const args = [
103
+ '--model', modelPath,
104
+ '--port', String(WHISPER_SERVER_PORT),
105
+ '--host', '127.0.0.1',
106
+ '-l', 'auto',
107
+ '--no-timestamps',
108
+ '--convert',
109
+ '--prompt', 'coding, programming, Claude, terminal, git, function, component, API',
110
+ ];
111
+ const proc = spawn(serverBin, args, {
112
+ stdio: 'ignore',
113
+ detached: true,
114
+ });
115
+ proc.unref();
116
+ const pid = proc.pid;
117
+ if (!pid) {
118
+ debug('WhisperMgr', 'Failed to spawn whisper-server (no pid)');
119
+ return null;
120
+ }
121
+ // 3. Brief wait to detect immediate crash (e.g. port conflict)
122
+ await new Promise((r) => setTimeout(r, 200));
123
+ if (!isProcessAlive(pid)) {
124
+ debug('WhisperMgr', `whisper-server died immediately (pid=${pid}), checking for existing server...`);
125
+ // Another process may have won the port race — re-check info file
126
+ const otherInfo = readInfo();
127
+ if (otherInfo && isProcessAlive(otherInfo.pid) && await isServerResponding(otherInfo.port)) {
128
+ debug('WhisperMgr', `Found winner server (pid=${otherInfo.pid}, port=${otherInfo.port})`);
129
+ return otherInfo.port;
130
+ }
131
+ removeInfo();
132
+ return null;
133
+ }
134
+ // 4. Write info file
135
+ writeInfo({ pid, port: WHISPER_SERVER_PORT, modelPath, startedAt: new Date().toISOString() });
136
+ // 5. Poll until ready (up to 30s for model loading)
137
+ if (await pollUntilReady(WHISPER_SERVER_PORT, 30_000)) {
138
+ debug('WhisperMgr', `whisper-server ready on port ${WHISPER_SERVER_PORT} (pid=${pid})`);
139
+ return WHISPER_SERVER_PORT;
140
+ }
141
+ debug('WhisperMgr', 'whisper-server failed to become ready within 30s');
142
+ return null;
143
+ }
144
+ /**
145
+ * Release the whisper-server if no other sessions remain.
146
+ * Call AFTER deregisterSession() so the count is already decremented.
147
+ */
148
+ export function releaseWhisperServer() {
149
+ const activeSessions = listActive();
150
+ if (activeSessions.length > 0) {
151
+ debug('WhisperMgr', `Keeping whisper-server alive (${activeSessions.length} session(s) remain)`);
152
+ return;
153
+ }
154
+ const info = readInfo();
155
+ if (!info)
156
+ return;
157
+ debug('WhisperMgr', `Killing whisper-server (pid=${info.pid})`);
158
+ try {
159
+ process.kill(info.pid, 'SIGTERM');
160
+ }
161
+ catch { /* already dead */ }
162
+ // Force kill after 3s
163
+ setTimeout(() => {
164
+ try {
165
+ process.kill(info.pid, 'SIGKILL');
166
+ }
167
+ catch { /* already dead */ }
168
+ }, 3000);
169
+ removeInfo();
170
+ }
171
+ //# sourceMappingURL=whisper-server-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-server-manager.js","sourceRoot":"","sources":["../src/whisper-server-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { WebSocket } from 'ws';
2
+ import type { Server } from 'http';
3
+ import type { BridgeEvent, PluginCommand } from './types.js';
4
+ export declare class WsServer {
5
+ private wss;
6
+ private commandCallback;
7
+ private onConnectCallback;
8
+ private onDisconnectCallback;
9
+ constructor(server: Server);
10
+ broadcast(event: BridgeEvent): void;
11
+ onCommand(callback: (cmd: PluginCommand) => void): void;
12
+ onClientConnect(callback: (ws: WebSocket) => void): void;
13
+ onClientDisconnect(callback: () => void): void;
14
+ sendTo(ws: WebSocket, event: BridgeEvent): void;
15
+ getClientCount(): number;
16
+ close(): void;
17
+ }
18
+ //# sourceMappingURL=ws-server.d.ts.map
@@ -0,0 +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;AAI7D,qBAAa,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,iBAAiB,CAA0C;IACnE,OAAO,CAAC,oBAAoB,CAA6B;gBAE7C,MAAM,EAAE,MAAM;IAiD1B,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAWnC,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,IAAI,GAAG,IAAI;IAIvD,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;CAMd"}
@@ -0,0 +1,86 @@
1
+ import { WebSocketServer, WebSocket } from 'ws';
2
+ import { isLocalConnection, validateToken } from './auth.js';
3
+ import { debug } from './logger.js';
4
+ export class WsServer {
5
+ wss;
6
+ commandCallback = null;
7
+ onConnectCallback = null;
8
+ onDisconnectCallback = null;
9
+ constructor(server) {
10
+ this.wss = new WebSocketServer({ server });
11
+ this.wss.on('connection', (ws, req) => {
12
+ // Token auth for remote connections
13
+ const remoteIp = req.socket.remoteAddress || '';
14
+ if (!isLocalConnection(remoteIp)) {
15
+ const url = new URL(req.url || '/', `http://${req.headers.host || 'localhost'}`);
16
+ const token = url.searchParams.get('token') || '';
17
+ if (!validateToken(token)) {
18
+ debug('WS', `Rejected remote connection from ${remoteIp} (invalid token)`);
19
+ ws.close(4001, 'Unauthorized');
20
+ return;
21
+ }
22
+ debug('WS', `Remote client authenticated from ${remoteIp}`);
23
+ }
24
+ debug('WS', 'Plugin connected');
25
+ // Send current state to newly connected client
26
+ if (this.onConnectCallback) {
27
+ this.onConnectCallback(ws);
28
+ }
29
+ ws.on('message', (data) => {
30
+ try {
31
+ const msg = JSON.parse(data.toString());
32
+ debug('WS', `recv cmd: ${msg.type}`);
33
+ if (this.commandCallback) {
34
+ this.commandCallback(msg);
35
+ }
36
+ }
37
+ catch (err) {
38
+ debug('WS', `Failed to parse message: ${err}`);
39
+ }
40
+ });
41
+ ws.on('close', () => {
42
+ debug('WS', 'Plugin disconnected');
43
+ if (this.onDisconnectCallback) {
44
+ this.onDisconnectCallback();
45
+ }
46
+ });
47
+ ws.on('error', (err) => {
48
+ debug('WS', `WebSocket error: ${err}`);
49
+ });
50
+ });
51
+ }
52
+ broadcast(event) {
53
+ const payload = JSON.stringify(event);
54
+ const clientCount = this.wss.clients.size;
55
+ debug('WS', `broadcast(${event.type}) to ${clientCount} clients`);
56
+ for (const client of this.wss.clients) {
57
+ if (client.readyState === WebSocket.OPEN) {
58
+ client.send(payload);
59
+ }
60
+ }
61
+ }
62
+ onCommand(callback) {
63
+ this.commandCallback = callback;
64
+ }
65
+ onClientConnect(callback) {
66
+ this.onConnectCallback = callback;
67
+ }
68
+ onClientDisconnect(callback) {
69
+ this.onDisconnectCallback = callback;
70
+ }
71
+ sendTo(ws, event) {
72
+ if (ws.readyState === WebSocket.OPEN) {
73
+ ws.send(JSON.stringify(event));
74
+ }
75
+ }
76
+ getClientCount() {
77
+ return this.wss.clients.size;
78
+ }
79
+ close() {
80
+ for (const client of this.wss.clients) {
81
+ client.close();
82
+ }
83
+ this.wss.close();
84
+ }
85
+ }
86
+ //# sourceMappingURL=ws-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ws-server.js","sourceRoot":"","sources":["../src/ws-server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@agentdeck/bridge",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/puritysb/AgentDeck.git",
9
+ "directory": "bridge"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "!dist/__tests__"
14
+ ],
15
+ "main": "./dist/index.js",
16
+ "bin": {
17
+ "sdc": "./dist/index.js"
18
+ },
19
+ "dependencies": {
20
+ "bonjour-service": "^1.3.0",
21
+ "commander": "^12.0.0",
22
+ "express": "^4.21.0",
23
+ "node-pty": "^1.0.0",
24
+ "qrcode": "^1.5.4",
25
+ "strip-ansi": "^7.1.0",
26
+ "ws": "^8.18.0",
27
+ "@agentdeck/shared": "0.1.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/express": "^4.17.21",
31
+ "@types/node": "^20.14.0",
32
+ "@types/qrcode": "^1.5.6",
33
+ "@types/ws": "^8.5.12",
34
+ "typescript": "^5.5.0"
35
+ },
36
+ "scripts": {
37
+ "build": "tsc",
38
+ "dev": "tsc --watch",
39
+ "clean": "rm -rf dist",
40
+ "typecheck": "tsc --noEmit",
41
+ "start": "node dist/index.js"
42
+ }
43
+ }