@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,24 @@
1
+ import type { UsageSnapshot } from './types.js';
2
+ export declare class UsageTracker {
3
+ private startTime;
4
+ private inputTokens;
5
+ private outputTokens;
6
+ private toolCalls;
7
+ private sessionPercent;
8
+ private costSpent;
9
+ private costLimit;
10
+ private resetTime;
11
+ private resetDate;
12
+ private ptyDurationSec;
13
+ start(): void;
14
+ addToolCall(data: Record<string, unknown>): void;
15
+ addTokens(input: number, output: number): void;
16
+ setDuration(seconds: number): void;
17
+ setOutputTokens(tokens: number): void;
18
+ incrementToolCalls(): void;
19
+ /** Update plan-level usage from /usage command output */
20
+ setUsageInfo(info: Record<string, unknown>): void;
21
+ getSnapshot(): UsageSnapshot;
22
+ reset(): void;
23
+ }
24
+ //# sourceMappingURL=usage-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-tracker.d.ts","sourceRoot":"","sources":["../src/usage-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,qBAAa,YAAY;IACvB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAAK;IAGtB,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,SAAS,CAAuB;IAGxC,OAAO,CAAC,cAAc,CAAuB;IAE7C,KAAK,IAAI,IAAI;IAIb,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAWhD,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAK9C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIlC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIrC,kBAAkB,IAAI,IAAI;IAI1B,yDAAyD;IACzD,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAmBjD,WAAW,IAAI,aAAa;IAkB5B,KAAK,IAAI,IAAI;CAYd"}
@@ -0,0 +1,89 @@
1
+ import { debug } from './logger.js';
2
+ export class UsageTracker {
3
+ startTime = 0;
4
+ inputTokens = 0;
5
+ outputTokens = 0;
6
+ toolCalls = 0;
7
+ // Plan-level usage from /usage command
8
+ sessionPercent = null;
9
+ costSpent = null;
10
+ costLimit = null;
11
+ resetTime = null;
12
+ resetDate = null;
13
+ // PTY-reported duration (overrides timer)
14
+ ptyDurationSec = null;
15
+ start() {
16
+ this.startTime = Date.now();
17
+ }
18
+ addToolCall(data) {
19
+ this.toolCalls++;
20
+ if (typeof data.input_tokens === 'number') {
21
+ this.inputTokens += data.input_tokens;
22
+ }
23
+ if (typeof data.output_tokens === 'number') {
24
+ this.outputTokens += data.output_tokens;
25
+ }
26
+ debug('Usage', `toolCall #${this.toolCalls}: in=${this.inputTokens} out=${this.outputTokens}`);
27
+ }
28
+ addTokens(input, output) {
29
+ this.inputTokens += input;
30
+ this.outputTokens += output;
31
+ }
32
+ setDuration(seconds) {
33
+ this.ptyDurationSec = seconds;
34
+ }
35
+ setOutputTokens(tokens) {
36
+ this.outputTokens = Math.max(this.outputTokens, tokens);
37
+ }
38
+ incrementToolCalls() {
39
+ this.toolCalls++;
40
+ }
41
+ /** Update plan-level usage from /usage command output */
42
+ setUsageInfo(info) {
43
+ debug('Usage', `setUsageInfo: ${JSON.stringify(info).slice(0, 120)}`);
44
+ if (typeof info.sessionPercent === 'number') {
45
+ this.sessionPercent = info.sessionPercent;
46
+ }
47
+ if (typeof info.costSpent === 'number') {
48
+ this.costSpent = info.costSpent;
49
+ }
50
+ if (typeof info.costLimit === 'number') {
51
+ this.costLimit = info.costLimit;
52
+ }
53
+ if (typeof info.resetTime === 'string') {
54
+ this.resetTime = info.resetTime;
55
+ }
56
+ if (typeof info.resetDate === 'string') {
57
+ this.resetDate = info.resetDate;
58
+ }
59
+ }
60
+ getSnapshot() {
61
+ const durationMs = this.startTime > 0 ? Date.now() - this.startTime : 0;
62
+ const durationSec = this.ptyDurationSec ?? Math.floor(durationMs / 1000);
63
+ return {
64
+ sessionDurationSec: durationSec,
65
+ inputTokens: this.inputTokens,
66
+ outputTokens: this.outputTokens,
67
+ toolCalls: this.toolCalls,
68
+ estimatedCostUsd: this.costSpent,
69
+ sessionPercent: this.sessionPercent,
70
+ costSpent: this.costSpent,
71
+ costLimit: this.costLimit,
72
+ resetTime: this.resetTime,
73
+ resetDate: this.resetDate,
74
+ };
75
+ }
76
+ reset() {
77
+ this.startTime = Date.now();
78
+ this.inputTokens = 0;
79
+ this.outputTokens = 0;
80
+ this.toolCalls = 0;
81
+ this.sessionPercent = null;
82
+ this.costSpent = null;
83
+ this.costLimit = null;
84
+ this.resetTime = null;
85
+ this.resetDate = null;
86
+ this.ptyDurationSec = null;
87
+ }
88
+ }
89
+ //# sourceMappingURL=usage-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-tracker.js","sourceRoot":"","sources":["../src/usage-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { EventEmitter } from 'events';
2
+ export declare class VoiceManager extends EventEmitter {
3
+ private recording;
4
+ private audioProcess;
5
+ private audioFile;
6
+ private whisperBin;
7
+ private whisperModel;
8
+ private recBin;
9
+ private soxBin;
10
+ private hasMetal;
11
+ private whisperServerBin;
12
+ private serverPort;
13
+ private useServer;
14
+ constructor();
15
+ connectToServer(): Promise<void>;
16
+ disconnectFromServer(): void;
17
+ startRecording(): void;
18
+ stopRecording(): Promise<string>;
19
+ cancel(): void;
20
+ isRecording(): boolean;
21
+ private transcribeViaServer;
22
+ private transcribeWithCli;
23
+ private resample;
24
+ private transcribe;
25
+ private cleanup;
26
+ }
27
+ //# sourceMappingURL=voice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAkFtC,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,SAAS,CAAM;IACvB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,SAAS,CAAS;;IAiBpB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtC,oBAAoB,IAAI,IAAI;IAM5B,cAAc,IAAI,IAAI;IA0ChB,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAwEtC,MAAM,IAAI,IAAI;IAUd,WAAW,IAAI,OAAO;YAIR,mBAAmB;YAkCnB,iBAAiB;IAyC/B,OAAO,CAAC,QAAQ;IA6BhB,OAAO,CAAC,UAAU;IA+ElB,OAAO,CAAC,OAAO;CAMhB"}
package/dist/voice.js ADDED
@@ -0,0 +1,412 @@
1
+ import { EventEmitter } from 'events';
2
+ import { spawn, execSync } from 'child_process';
3
+ import { tmpdir } from 'os';
4
+ import { join } from 'path';
5
+ import { unlinkSync, existsSync, statSync, readFileSync } from 'fs';
6
+ import { debug } from './logger.js';
7
+ import { ensureWhisperServer, releaseWhisperServer } from './whisper-server-manager.js';
8
+ import { MODEL_SEARCH_DIRS, MODELS_WITH_METAL, MODELS_WITHOUT_METAL, WHISPER_CANDIDATES, REC_CANDIDATES, SOX_CANDIDATES, WHISPER_SERVER_CANDIDATES, } from '@agentdeck/shared';
9
+ // Dynamic timeout: base + multiplier × audio duration
10
+ // Metal GPU: fast inference; Rosetta/CPU: ~3-4x slower
11
+ const TIMEOUT_BASE_MS = 15_000;
12
+ const TIMEOUT_MULTIPLIER_METAL = 1; // 15s + 1× audio duration
13
+ const TIMEOUT_MULTIPLIER_ROSETTA = 4; // 15s + 4× audio duration
14
+ function findBinary(candidates, fallback) {
15
+ for (const path of candidates) {
16
+ if (existsSync(path))
17
+ return path;
18
+ }
19
+ return fallback;
20
+ }
21
+ /** Check if a whisper-cli binary has Metal GPU support (native arm64 + libggml-metal). */
22
+ function detectMetal(whisperPath) {
23
+ try {
24
+ const otoolOut = execSync(`otool -L "${whisperPath}"`, { encoding: 'utf8' });
25
+ const hasMetal = otoolOut.includes('libggml-metal');
26
+ const fileOut = execSync(`file "${whisperPath}"`, { encoding: 'utf8' });
27
+ const isArm64 = fileOut.includes('arm64');
28
+ debug('Voice', `whisper-cli: arm64=${isArm64}, metal=${hasMetal} (${whisperPath})`);
29
+ return hasMetal && isArm64;
30
+ }
31
+ catch {
32
+ debug('Voice', `Could not detect capabilities: ${whisperPath}`);
33
+ return false;
34
+ }
35
+ }
36
+ function findWhisperModel(preference) {
37
+ for (const model of preference) {
38
+ for (const dir of MODEL_SEARCH_DIRS) {
39
+ const path = join(dir, model);
40
+ if (existsSync(path)) {
41
+ debug('Voice', `Selected whisper model: ${path}`);
42
+ return path;
43
+ }
44
+ }
45
+ }
46
+ debug('Voice', `No whisper model found in: ${MODEL_SEARCH_DIRS.join(', ')}`);
47
+ return join(MODEL_SEARCH_DIRS[0], preference[0]);
48
+ }
49
+ function findFallbackModel(currentModel) {
50
+ const all = [...MODELS_WITH_METAL];
51
+ const currentName = currentModel.split('/').pop() ?? '';
52
+ const idx = all.indexOf(currentName);
53
+ // Find a smaller model than current
54
+ for (let i = idx + 1; i < all.length; i++) {
55
+ for (const dir of MODEL_SEARCH_DIRS) {
56
+ const path = join(dir, all[i]);
57
+ if (existsSync(path))
58
+ return path;
59
+ }
60
+ }
61
+ return null;
62
+ }
63
+ /** Compute RMS energy of a 16-bit PCM WAV file (skip 44-byte header). */
64
+ function computeRms(wavFile) {
65
+ const buf = readFileSync(wavFile);
66
+ const headerSize = 44;
67
+ if (buf.length <= headerSize + 2)
68
+ return 0;
69
+ const samples = (buf.length - headerSize) / 2;
70
+ let sumSq = 0;
71
+ for (let i = headerSize; i + 1 < buf.length; i += 2) {
72
+ const sample = buf.readInt16LE(i) / 32768;
73
+ sumSq += sample * sample;
74
+ }
75
+ return Math.sqrt(sumSq / samples);
76
+ }
77
+ export class VoiceManager extends EventEmitter {
78
+ recording = false;
79
+ audioProcess = null;
80
+ audioFile = '';
81
+ whisperBin;
82
+ whisperModel;
83
+ recBin;
84
+ soxBin;
85
+ hasMetal;
86
+ whisperServerBin;
87
+ serverPort = null;
88
+ useServer = false;
89
+ constructor() {
90
+ super();
91
+ this.whisperBin = findBinary(WHISPER_CANDIDATES, 'whisper-cli');
92
+ this.recBin = findBinary(REC_CANDIDATES, 'rec');
93
+ this.soxBin = findBinary(SOX_CANDIDATES, 'sox');
94
+ this.whisperServerBin = findBinary(WHISPER_SERVER_CANDIDATES, 'whisper-server');
95
+ this.hasMetal = detectMetal(this.whisperBin);
96
+ const preference = this.hasMetal ? MODELS_WITH_METAL : MODELS_WITHOUT_METAL;
97
+ this.whisperModel = findWhisperModel(preference);
98
+ if (!this.hasMetal) {
99
+ debug('Voice', 'WARNING: whisper-cli has no Metal GPU support (x86/Rosetta). Using smaller model for speed. Install arm64 Homebrew for best quality.');
100
+ }
101
+ debug('Voice', `Binaries: whisper=${this.whisperBin}, rec=${this.recBin}, sox=${this.soxBin}, server=${this.whisperServerBin}`);
102
+ }
103
+ async connectToServer() {
104
+ const port = await ensureWhisperServer(this.whisperServerBin, this.whisperModel);
105
+ if (port) {
106
+ this.serverPort = port;
107
+ this.useServer = true;
108
+ }
109
+ }
110
+ disconnectFromServer() {
111
+ this.useServer = false;
112
+ this.serverPort = null;
113
+ releaseWhisperServer();
114
+ }
115
+ startRecording() {
116
+ if (this.recording)
117
+ return;
118
+ this.audioFile = join(tmpdir(), `sdc-voice-${Date.now()}.wav`);
119
+ this.recording = true;
120
+ // rec (sox) — record raw WAV. We request 16kHz mono 16-bit.
121
+ // macOS coreaudio may record at native rate (24/48kHz); resample step normalizes.
122
+ // No sox effects during recording — they can interfere with real-time capture.
123
+ this.audioProcess = spawn(this.recBin, [
124
+ '-r', '16000',
125
+ '-c', '1',
126
+ '-b', '16',
127
+ this.audioFile,
128
+ ], {
129
+ stdio: ['ignore', 'ignore', 'pipe'],
130
+ });
131
+ this.audioProcess.stderr?.on('data', (data) => {
132
+ const line = data.toString().trim();
133
+ // Only log non-progress lines
134
+ if (line && !line.startsWith('In:') && !line.startsWith('Out:')) {
135
+ debug('Voice', `rec: ${line}`);
136
+ }
137
+ });
138
+ this.audioProcess.on('error', (err) => {
139
+ debug('Voice', `rec spawn error: ${err.message}`);
140
+ this.recording = false;
141
+ this.audioProcess = null;
142
+ this.emit('error', new Error(`Failed to start recording: ${err.message}`));
143
+ });
144
+ this.audioProcess.on('exit', (code) => {
145
+ debug('Voice', `rec exited with code ${code}`);
146
+ this.audioProcess = null;
147
+ });
148
+ this.emit('recording_start');
149
+ debug('Voice', `Recording started → ${this.audioFile}`);
150
+ }
151
+ async stopRecording() {
152
+ if (!this.recording || !this.audioProcess) {
153
+ throw new Error('Not currently recording');
154
+ }
155
+ const proc = this.audioProcess;
156
+ this.recording = false;
157
+ this.emit('recording_stop');
158
+ proc.kill('SIGINT');
159
+ debug('Voice', 'Sent SIGINT to rec');
160
+ // Wait for exit (up to 3s)
161
+ await new Promise((resolve) => {
162
+ let done = false;
163
+ const finish = () => { if (!done) {
164
+ done = true;
165
+ resolve();
166
+ } };
167
+ proc.on('exit', finish);
168
+ setTimeout(finish, 3000);
169
+ });
170
+ // Verify file
171
+ if (!existsSync(this.audioFile)) {
172
+ const path = this.audioFile;
173
+ this.cleanup();
174
+ throw new Error(`Recording file not created: ${path}`);
175
+ }
176
+ const sz = statSync(this.audioFile).size;
177
+ debug('Voice', `Recording file: ${sz} bytes`);
178
+ if (sz < 100) {
179
+ this.cleanup();
180
+ throw new Error('Recording too short or empty');
181
+ }
182
+ // Check audio RMS to detect silence (whisper hallucinates on silent audio)
183
+ const rms = computeRms(this.audioFile);
184
+ debug('Voice', `Audio RMS: ${rms.toFixed(4)}`);
185
+ if (rms < 0.001) {
186
+ this.cleanup();
187
+ throw new Error('No audio detected — check microphone permission');
188
+ }
189
+ // --- Transcription: prefer whisper-server, fallback to whisper-cli ---
190
+ try {
191
+ let text;
192
+ if (this.useServer && this.serverPort) {
193
+ // Server mode: skip resample, whisper-server handles format conversion (--convert)
194
+ debug('Voice', 'Server mode: skipping sox resample');
195
+ try {
196
+ text = await this.transcribeViaServer(this.audioFile);
197
+ }
198
+ catch (serverErr) {
199
+ debug('Voice', `Server transcription failed, falling back to whisper-cli: ${serverErr}`);
200
+ this.useServer = false;
201
+ text = await this.transcribeWithCli(this.audioFile);
202
+ }
203
+ }
204
+ else {
205
+ text = await this.transcribeWithCli(this.audioFile);
206
+ }
207
+ debug('Voice', `Transcription result: "${text.slice(0, 80)}"`);
208
+ this.emit('transcription', text);
209
+ this.cleanup();
210
+ return text;
211
+ }
212
+ catch (err) {
213
+ this.cleanup();
214
+ const error = err instanceof Error ? err : new Error(String(err));
215
+ debug('Voice', `Transcription error: ${error.message}`);
216
+ this.emit('error', error);
217
+ throw error;
218
+ }
219
+ }
220
+ cancel() {
221
+ if (this.audioProcess) {
222
+ this.audioProcess.kill('SIGKILL');
223
+ this.audioProcess = null;
224
+ }
225
+ this.recording = false;
226
+ this.cleanup();
227
+ this.emit('recording_stop');
228
+ }
229
+ isRecording() {
230
+ return this.recording;
231
+ }
232
+ async transcribeViaServer(audioFile) {
233
+ const fileData = readFileSync(audioFile);
234
+ const boundary = `----whisper${Date.now()}`;
235
+ const filename = audioFile.split('/').pop() || 'audio.wav';
236
+ // Build multipart form-data manually (no external deps)
237
+ const header = Buffer.from(`--${boundary}\r\n` +
238
+ `Content-Disposition: form-data; name="file"; filename="${filename}"\r\n` +
239
+ `Content-Type: audio/wav\r\n\r\n`);
240
+ const footer = Buffer.from(`\r\n--${boundary}--\r\n`);
241
+ const body = Buffer.concat([header, fileData, footer]);
242
+ const url = `http://127.0.0.1:${this.serverPort}/inference`;
243
+ debug('Voice', `POST ${url} (${fileData.length} bytes audio)`);
244
+ const res = await fetch(url, {
245
+ method: 'POST',
246
+ headers: { 'Content-Type': `multipart/form-data; boundary=${boundary}` },
247
+ body,
248
+ signal: AbortSignal.timeout(15_000),
249
+ });
250
+ if (!res.ok) {
251
+ throw new Error(`whisper-server returned ${res.status}: ${await res.text()}`);
252
+ }
253
+ const json = await res.json();
254
+ const text = (json.text ?? '').trim();
255
+ debug('Voice', `whisper-server response: "${text.slice(0, 80)}"`);
256
+ return text;
257
+ }
258
+ async transcribeWithCli(audioFile) {
259
+ // Resample to 16kHz/16-bit mono WAV (macOS coreaudio may record at 48kHz/32-bit)
260
+ const resampledFile = audioFile.replace('.wav', '_16k.wav');
261
+ debug('Voice', `Resampling ${audioFile} → ${resampledFile}`);
262
+ try {
263
+ await this.resample(audioFile, resampledFile);
264
+ }
265
+ catch (err) {
266
+ debug('Voice', `Resample failed, using original: ${err}`);
267
+ }
268
+ const whisperInput = existsSync(resampledFile) ? resampledFile : audioFile;
269
+ debug('Voice', `Whisper input: ${whisperInput}`);
270
+ // Calculate dynamic timeout based on audio duration and Metal support
271
+ const audioDurationSec = (statSync(whisperInput).size - 44) / 32000; // 16kHz × 16-bit
272
+ const multiplier = this.hasMetal ? TIMEOUT_MULTIPLIER_METAL : TIMEOUT_MULTIPLIER_ROSETTA;
273
+ const timeoutMs = TIMEOUT_BASE_MS + Math.ceil(audioDurationSec * 1000 * multiplier);
274
+ debug('Voice', `Starting whisper-cli transcription (${audioDurationSec.toFixed(1)}s audio, timeout ${(timeoutMs / 1000).toFixed(0)}s, metal=${this.hasMetal})...`);
275
+ try {
276
+ let text;
277
+ try {
278
+ text = await this.transcribe(whisperInput, this.whisperModel, timeoutMs);
279
+ }
280
+ catch (err) {
281
+ const isTimeout = err instanceof Error && err.message.includes('timed out');
282
+ const fallback = isTimeout ? findFallbackModel(this.whisperModel) : null;
283
+ if (fallback) {
284
+ debug('Voice', `Timeout with current model, retrying with fallback: ${fallback}`);
285
+ this.whisperModel = fallback; // persist for future calls
286
+ text = await this.transcribe(whisperInput, fallback, timeoutMs);
287
+ }
288
+ else {
289
+ throw err;
290
+ }
291
+ }
292
+ if (existsSync(resampledFile))
293
+ try {
294
+ unlinkSync(resampledFile);
295
+ }
296
+ catch { /* */ }
297
+ return text;
298
+ }
299
+ catch (err) {
300
+ if (existsSync(resampledFile))
301
+ try {
302
+ unlinkSync(resampledFile);
303
+ }
304
+ catch { /* */ }
305
+ throw err;
306
+ }
307
+ }
308
+ resample(inputFile, outputFile) {
309
+ return new Promise((resolve, reject) => {
310
+ // Resample to 16kHz/16-bit mono + gentle highpass (80Hz removes rumble, preserves voice)
311
+ // + normalize volume for consistent whisper input
312
+ const sox = spawn(this.soxBin, [
313
+ inputFile,
314
+ '-r', '16000',
315
+ '-c', '1',
316
+ '-b', '16',
317
+ outputFile,
318
+ 'highpass', '80',
319
+ 'norm',
320
+ ]);
321
+ let stderr = '';
322
+ sox.stderr?.on('data', (data) => { stderr += data.toString(); });
323
+ sox.on('error', (err) => reject(new Error(`sox spawn error: ${err.message}`)));
324
+ sox.on('close', (code) => {
325
+ if (code !== 0) {
326
+ reject(new Error(`sox exited with code ${code}: ${stderr.slice(-200)}`));
327
+ }
328
+ else {
329
+ debug('Voice', `Resampled OK (${statSync(outputFile).size} bytes)`);
330
+ resolve();
331
+ }
332
+ });
333
+ });
334
+ }
335
+ transcribe(audioFile, modelPath, timeoutMs) {
336
+ return new Promise((resolve, reject) => {
337
+ const args = [
338
+ '-m', modelPath,
339
+ '-l', 'auto', // auto-detect language (supports Korean, English, etc.)
340
+ '-f', audioFile,
341
+ '--no-timestamps',
342
+ '-np', // suppress whisper's own progress output
343
+ '--prompt', 'coding, programming, Claude, terminal, git, function, component, API',
344
+ ];
345
+ debug('Voice', `${this.whisperBin} ${args.join(' ')}`);
346
+ const whisper = spawn(this.whisperBin, args);
347
+ let stdout = '';
348
+ let stderr = '';
349
+ let settled = false;
350
+ // Timeout guard (dynamic based on audio length + Metal support)
351
+ const timer = setTimeout(() => {
352
+ if (!settled) {
353
+ settled = true;
354
+ debug('Voice', `whisper-cli timed out after ${(timeoutMs / 1000).toFixed(0)}s, killing`);
355
+ whisper.kill('SIGKILL');
356
+ reject(new Error(`whisper-cli timed out after ${(timeoutMs / 1000).toFixed(0)}s`));
357
+ }
358
+ }, timeoutMs);
359
+ whisper.stdout.on('data', (data) => {
360
+ stdout += data.toString();
361
+ });
362
+ whisper.stderr.on('data', (data) => {
363
+ stderr += data.toString();
364
+ });
365
+ whisper.on('error', (err) => {
366
+ if (!settled) {
367
+ settled = true;
368
+ clearTimeout(timer);
369
+ debug('Voice', `whisper-cli spawn error: ${err.message}`);
370
+ reject(new Error(`Failed to run whisper-cli: ${err.message}`));
371
+ }
372
+ });
373
+ whisper.on('close', (code) => {
374
+ if (settled)
375
+ return;
376
+ settled = true;
377
+ clearTimeout(timer);
378
+ debug('Voice', `whisper-cli exited with code ${code}`);
379
+ if (stderr.length > 0) {
380
+ debug('Voice', `whisper stderr (last 200): ${stderr.slice(-200)}`);
381
+ }
382
+ if (code !== 0) {
383
+ reject(new Error(`whisper-cli exited with code ${code}: ${stderr.slice(-300)}`));
384
+ return;
385
+ }
386
+ const text = stdout
387
+ .split('\n')
388
+ .map((line) => line.trim())
389
+ .filter((line) => line.length > 0 &&
390
+ !line.startsWith('[') && // skip timestamp lines
391
+ line !== '(blank audio)' && // skip blank audio markers
392
+ !line.startsWith('(') && // skip other whisper annotations
393
+ !/^\[BLANK_AUDIO\]$/i.test(line) // skip blank audio tags
394
+ )
395
+ .join(' ')
396
+ .trim();
397
+ debug('Voice', `whisper stdout raw (${stdout.length} chars): "${stdout.slice(0, 100)}"`);
398
+ resolve(text);
399
+ });
400
+ });
401
+ }
402
+ cleanup() {
403
+ if (this.audioFile && existsSync(this.audioFile)) {
404
+ try {
405
+ unlinkSync(this.audioFile);
406
+ }
407
+ catch { /* */ }
408
+ }
409
+ this.audioFile = '';
410
+ }
411
+ }
412
+ //# sourceMappingURL=voice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.js","sourceRoot":"","sources":["../src/voice.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
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
+ export declare const WHISPER_SERVER_PORT = 9100;
9
+ /**
10
+ * Ensure a whisper-server is running on the singleton port.
11
+ * Returns port on success, null if unavailable (binary missing, model missing, etc).
12
+ */
13
+ export declare function ensureWhisperServer(serverBin: string, modelPath: string): Promise<number | null>;
14
+ /**
15
+ * Release the whisper-server if no other sessions remain.
16
+ * Call AFTER deregisterSession() so the count is already decremented.
17
+ */
18
+ export declare function releaseWhisperServer(): void;
19
+ //# sourceMappingURL=whisper-server-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whisper-server-manager.d.ts","sourceRoot":"","sources":["../src/whisper-server-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,eAAO,MAAM,mBAAmB,OAAO,CAAC;AA2DxC;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6ExB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAiB3C"}