claude-phone-local 2.0.9 → 2.0.11
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.
|
@@ -233,11 +233,34 @@ async function setupInstallationType(installationType, existingConfig, isPi, opt
|
|
|
233
233
|
// than in postinstall because only now do we know which extension to ring.
|
|
234
234
|
if (installationType !== 'api-server') {
|
|
235
235
|
console.log(chalk.bold('\nMCP server (lets Claude call you)'));
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
|
|
237
|
+
const answeringExtension = config.devices?.[0]?.extension;
|
|
238
|
+
const { callbackNumber } = await inquirer.prompt([
|
|
239
|
+
{
|
|
240
|
+
type: 'input',
|
|
241
|
+
name: 'callbackNumber',
|
|
242
|
+
message: 'Number/extension for Claude to call YOU on (must be different ' +
|
|
243
|
+
`from ${answeringExtension || 'the device extension'} above - 3CX rejects ` +
|
|
244
|
+
'a device calling itself):',
|
|
245
|
+
default: config.sip?.callbackNumber || '',
|
|
246
|
+
validate: (input) => {
|
|
247
|
+
if (!input || input.trim() === '') {
|
|
248
|
+
return 'A callback number is required for Claude to call you';
|
|
249
|
+
}
|
|
250
|
+
if (answeringExtension && input.trim() === answeringExtension) {
|
|
251
|
+
return `Must differ from ${answeringExtension} - that number answers as ` +
|
|
252
|
+
'Maya, so calling it from itself is rejected by 3CX as a self-call.';
|
|
253
|
+
}
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
]);
|
|
258
|
+
|
|
259
|
+
config.sip.callbackNumber = callbackNumber.trim();
|
|
260
|
+
await saveConfig(config);
|
|
261
|
+
|
|
239
262
|
registerMcpServerWithOutput({
|
|
240
|
-
defaultTo: config.sip
|
|
263
|
+
defaultTo: config.sip.callbackNumber,
|
|
241
264
|
httpPort: config.server?.httpPort || 3000,
|
|
242
265
|
});
|
|
243
266
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-phone-local",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
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": {
|
|
@@ -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', {
|