claude-phone-local 2.0.10 → 2.0.12
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/cli/lib/network.js
CHANGED
|
@@ -120,7 +120,7 @@ export async function checkClaudeApiServer(url) {
|
|
|
120
120
|
* @param {number} [opts.intervalMs=1000] - Poll interval
|
|
121
121
|
* @returns {Promise<{ready: boolean, timedOut: boolean}>}
|
|
122
122
|
*/
|
|
123
|
-
export async function waitForVoiceAppReady(url, { timeoutMs =
|
|
123
|
+
export async function waitForVoiceAppReady(url, { timeoutMs = 60000, intervalMs = 1000 } = {}) {
|
|
124
124
|
const deadline = Date.now() + timeoutMs;
|
|
125
125
|
|
|
126
126
|
while (Date.now() < deadline) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-phone-local",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.12",
|
|
4
4
|
"description": "Local/offline fork of NetworkChuck's claude-phone: talk to Claude Code over 3CX/SIP with faster-whisper STT + Piper TTS in one Docker container.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@ const AUDIO_WS_HOST = new URL(AUDIO_BASE_URL).hostname;
|
|
|
22
22
|
// Audio cue URLs
|
|
23
23
|
const READY_BEEP_URL = `${AUDIO_BASE_URL}/static/ready-beep.wav`;
|
|
24
24
|
const GOTIT_BEEP_URL = `${AUDIO_BASE_URL}/static/gotit-beep.wav`;
|
|
25
|
-
const HOLD_MUSIC_URL = `${AUDIO_BASE_URL}/static/hold-music.
|
|
25
|
+
const HOLD_MUSIC_URL = `${AUDIO_BASE_URL}/static/hold-music.wav`;
|
|
26
26
|
|
|
27
27
|
// Claude Code-style thinking phrases
|
|
28
28
|
const THINKING_PHRASES = [
|
|
@@ -131,7 +131,12 @@ router.post('/outbound-call', async function(req, res) {
|
|
|
131
131
|
var timeoutSeconds = req.body.timeoutSeconds || 30;
|
|
132
132
|
var webhookUrl = req.body.webhookUrl;
|
|
133
133
|
|
|
134
|
-
// Look up device configuration
|
|
134
|
+
// Look up device configuration. This also decides the outbound SIP
|
|
135
|
+
// identity/credentials (see initiateOutboundCall) - without a device, the
|
|
136
|
+
// call goes out as a hardcoded placeholder caller ID that 3CX has never
|
|
137
|
+
// provisioned and rejects with 403. Default to the registered device
|
|
138
|
+
// (Maya) rather than leaving deviceConfig null, since it's the only
|
|
139
|
+
// identity actually authorized to place calls on this SBC.
|
|
135
140
|
var deviceConfig = null;
|
|
136
141
|
if (deviceParam && deviceRegistry) {
|
|
137
142
|
// Use get() which tries extension first, then name (case-insensitive)
|
|
@@ -148,6 +153,23 @@ router.post('/outbound-call', async function(req, res) {
|
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
|
156
|
+
if (!deviceConfig && deviceRegistry) {
|
|
157
|
+
// getDefault() returns a hardcoded placeholder (fake ext 9000, fake
|
|
158
|
+
// creds) left over from the upstream fork - using it here would trade
|
|
159
|
+
// one unauthorized SIP identity for another. Use the first actually
|
|
160
|
+
// configured device instead, since that's a real registered identity
|
|
161
|
+
// this SBC will accept.
|
|
162
|
+
var allDevices = deviceRegistry.getAllDevices ? deviceRegistry.getAllDevices() : {};
|
|
163
|
+
var firstConfiguredDevice = Object.values(allDevices)[0] || null;
|
|
164
|
+
if (firstConfiguredDevice) {
|
|
165
|
+
deviceConfig = firstConfiguredDevice;
|
|
166
|
+
logger.info('No device specified, using first configured device for outbound identity', {
|
|
167
|
+
device: deviceConfig.name,
|
|
168
|
+
extension: deviceConfig.extension
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
151
173
|
// Check if infrastructure is available
|
|
152
174
|
if (!srf || !mediaServer) {
|
|
153
175
|
logger.error('Infrastructure not ready', {
|