@openclaw/facetime 2026.9.6 → 2026.9.7
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/assets/icon.png +0 -0
- package/dist/.setup/{setup-DUgC9yE7.mjs → setup-CoxvlB5L.mjs} +91 -128
- package/dist/doctor-contract-api.js +189 -7
- package/dist/index.js +1 -1
- package/dist/runtime-api.js +197 -238
- package/node_modules/typebox/build/compile/code.mjs +1 -2
- package/node_modules/typebox/build/compile/validator.mjs +5 -1
- package/node_modules/typebox/build/format/iri.mjs +16 -9
- package/node_modules/typebox/build/guard/emit.mjs +2 -2
- package/node_modules/typebox/build/guard/guard.d.mts +7 -5
- package/node_modules/typebox/build/guard/guard.mjs +14 -9
- package/node_modules/typebox/build/guard/index.mjs +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
- package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/node_modules/typebox/build/schema/build.mjs +2 -3
- package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
- package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
- package/node_modules/typebox/build/schema/parse.mjs +3 -0
- package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
- package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
- package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
- package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
- package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
- package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
- package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
- package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
- package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
- package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +3 -1
- package/package.json +5 -5
- package/src/audio-pump.ts +9 -16
- package/src/call-events.ts +12 -26
- package/src/call-lifecycle.ts +3 -19
- package/src/runtime-call-control.ts +3 -12
- package/src/runtime-call-events.ts +4 -9
- package/src/runtime-state.ts +0 -10
- package/src/setup.ts +96 -173
- package/src/talk-driver.ts +217 -242
- /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
package/assets/icon.png
CHANGED
|
Binary file
|
|
@@ -218,67 +218,117 @@ async function ensureHelperArtifacts(params) {
|
|
|
218
218
|
const XCODE_APP = "/Applications/Xcode.app";
|
|
219
219
|
const XCODE_CLANG = `${XCODE_APP}/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang`;
|
|
220
220
|
const XCODE_MACOS_SDK = `${XCODE_APP}/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk`;
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
kind: "command",
|
|
224
|
-
label: "Install or reinstall the FaceTime native package with Homebrew",
|
|
225
|
-
command: "if brew list --versions openclaw-facetime >/dev/null 2>&1; then brew reinstall openclaw/tap/openclaw-facetime; else brew install openclaw/tap/openclaw-facetime; fi"
|
|
226
|
-
};
|
|
227
|
-
const PRECHECK_ACTIONS = {
|
|
228
|
-
"capture-binary": {
|
|
229
|
-
id: NATIVE_PACKAGE_ACTION.id,
|
|
221
|
+
const SETUP_ACTIONS = {
|
|
222
|
+
"install-native-package": {
|
|
230
223
|
kind: "command",
|
|
231
|
-
label:
|
|
232
|
-
command:
|
|
224
|
+
label: "Install or reinstall the FaceTime native package with Homebrew",
|
|
225
|
+
command: "if brew list --versions openclaw-facetime >/dev/null 2>&1; then brew reinstall openclaw/tap/openclaw-facetime; else brew install openclaw/tap/openclaw-facetime; fi"
|
|
233
226
|
},
|
|
234
|
-
"
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
227
|
+
"install-xcode-tools": {
|
|
228
|
+
kind: "command",
|
|
229
|
+
label: "Install full Xcode in /Applications",
|
|
230
|
+
command: "open 'https://apps.apple.com/us/app/xcode/id497799835'"
|
|
231
|
+
},
|
|
232
|
+
"enable-developer-tools": {
|
|
233
|
+
kind: "command",
|
|
234
|
+
label: "Enable developer tools access",
|
|
235
|
+
command: "sudo /usr/sbin/DevToolsSecurity -enable"
|
|
236
|
+
},
|
|
237
|
+
"disable-sip-debugging": {
|
|
238
|
+
kind: "recovery",
|
|
239
|
+
label: "Disable SIP debugging restrictions from macOS Recovery, then reboot and rerun setup",
|
|
240
|
+
command: "csrutil enable --without debug",
|
|
241
|
+
settingsPath: "macOS Recovery > Utilities > Terminal"
|
|
242
|
+
},
|
|
243
|
+
"verify-sip-status": {
|
|
244
|
+
kind: "command",
|
|
245
|
+
label: "Verify SIP status, then rerun setup",
|
|
246
|
+
command: "/usr/bin/csrutil status"
|
|
247
|
+
},
|
|
248
|
+
"configure-owner-handles": {
|
|
249
|
+
kind: "command",
|
|
250
|
+
label: "Configure ownerHandles",
|
|
251
|
+
command: "openclaw configure"
|
|
252
|
+
},
|
|
253
|
+
"restart-gateway": {
|
|
254
|
+
kind: "command",
|
|
255
|
+
label: "Stop the stale gateway process, then restart OpenClaw",
|
|
256
|
+
command: "openclaw gateway restart"
|
|
257
|
+
},
|
|
258
|
+
"wait-for-helper": {
|
|
259
|
+
kind: "automatic",
|
|
260
|
+
label: "Wait for automatic helper injection to finish"
|
|
239
261
|
},
|
|
240
|
-
"
|
|
241
|
-
|
|
262
|
+
"restart-call-apps": {
|
|
263
|
+
kind: "manual-test",
|
|
264
|
+
label: "Quit and reopen FaceTime and Phone, then let OpenClaw reinject the helper"
|
|
265
|
+
},
|
|
266
|
+
"install-driver": {
|
|
242
267
|
kind: "gateway",
|
|
243
268
|
label: "Install or update the paired FaceTime audio driver",
|
|
244
269
|
gatewayMethod: "facetime.installDriver"
|
|
245
270
|
},
|
|
246
|
-
"physical-output": {
|
|
247
|
-
id: "select-physical-output",
|
|
271
|
+
"select-physical-output": {
|
|
248
272
|
kind: "system-settings",
|
|
249
273
|
label: "Select MacBook Speakers or another physical output",
|
|
250
274
|
settingsPath: "System Settings > Sound > Output"
|
|
251
275
|
},
|
|
252
|
-
"
|
|
253
|
-
id: "grant-system-audio",
|
|
276
|
+
"grant-system-audio": {
|
|
254
277
|
kind: "system-settings",
|
|
255
278
|
label: "Allow OpenClaw to capture FaceTime app audio",
|
|
256
279
|
settingsPath: "System Settings > Privacy & Security > Screen & System Audio Recording"
|
|
257
280
|
},
|
|
258
|
-
"realtime-provider": {
|
|
259
|
-
id: "configure-realtime-provider",
|
|
281
|
+
"configure-realtime-provider": {
|
|
260
282
|
kind: "command",
|
|
261
283
|
label: "Configure authentication for a registered realtime voice provider",
|
|
262
284
|
command: "openclaw configure"
|
|
285
|
+
},
|
|
286
|
+
"verify-focus": {
|
|
287
|
+
kind: "system-settings",
|
|
288
|
+
label: "Verify Focus is off or allows the expected caller",
|
|
289
|
+
settingsPath: "Control Center > Focus"
|
|
290
|
+
},
|
|
291
|
+
"allow-sharing-notifications": {
|
|
292
|
+
kind: "system-settings",
|
|
293
|
+
label: "Allow notifications while mirroring or sharing the display",
|
|
294
|
+
settingsPath: "System Settings > Notifications"
|
|
295
|
+
},
|
|
296
|
+
"live-outbound-test": {
|
|
297
|
+
kind: "manual-test",
|
|
298
|
+
label: "Place one outbound FaceTime audio call with facetime.dial",
|
|
299
|
+
gatewayMethod: "facetime.dial"
|
|
300
|
+
},
|
|
301
|
+
"live-audio-test": {
|
|
302
|
+
kind: "manual-test",
|
|
303
|
+
label: "Run one inbound and one outbound FaceTime audio call"
|
|
304
|
+
},
|
|
305
|
+
"review-live-voicemail": {
|
|
306
|
+
kind: "system-settings",
|
|
307
|
+
label: "Review Live Voicemail if inbound audio calls are screened",
|
|
308
|
+
settingsPath: "Phone > Settings > Live Voicemail"
|
|
263
309
|
}
|
|
264
310
|
};
|
|
311
|
+
const PRECHECK_ACTIONS = {
|
|
312
|
+
"capture-binary": "install-native-package",
|
|
313
|
+
"paired-driver-mic": "install-driver",
|
|
314
|
+
"paired-driver-feed": "install-driver",
|
|
315
|
+
"physical-output": "select-physical-output",
|
|
316
|
+
"process-tap": "grant-system-audio",
|
|
317
|
+
"realtime-provider": "configure-realtime-provider"
|
|
318
|
+
};
|
|
265
319
|
function firstLine(value) {
|
|
266
320
|
return typeof value === "string" ? value.trim().split(/\r?\n/u)[0] || void 0 : void 0;
|
|
267
321
|
}
|
|
268
|
-
function
|
|
269
|
-
if (!actions.some((candidate) => candidate.id === action.id)) actions.push(action);
|
|
270
|
-
}
|
|
271
|
-
function addPreflightCheck(checks, actions, check) {
|
|
322
|
+
function addPreflightCheck(checks, check) {
|
|
272
323
|
if (check.id === "call-app-running") return;
|
|
273
|
-
const
|
|
274
|
-
if (!check.ok && action) addAction(actions, action);
|
|
324
|
+
const actionId = PRECHECK_ACTIONS[check.id];
|
|
275
325
|
checks.push({
|
|
276
326
|
id: check.id,
|
|
277
327
|
label: check.label,
|
|
278
328
|
status: check.ok ? "ready" : check.required ? "action-required" : "recommended",
|
|
279
329
|
required: check.required,
|
|
280
330
|
message: check.message ?? (check.ok ? "ready" : "not ready"),
|
|
281
|
-
...!check.ok &&
|
|
331
|
+
...!check.ok && actionId ? { actionId } : {}
|
|
282
332
|
});
|
|
283
333
|
}
|
|
284
334
|
function hasActiveFocusAssertion(raw) {
|
|
@@ -379,7 +429,6 @@ async function inspectDriver(params) {
|
|
|
379
429
|
}
|
|
380
430
|
async function runFaceTimeSetup(params) {
|
|
381
431
|
const checks = [];
|
|
382
|
-
const actions = [];
|
|
383
432
|
const [xcodeCompiler, xcodeSdk] = await Promise.all([checkCommand(params.runCommandWithTimeout, [
|
|
384
433
|
"/bin/test",
|
|
385
434
|
"-x",
|
|
@@ -400,12 +449,6 @@ async function runFaceTimeSetup(params) {
|
|
|
400
449
|
message: xcodeReady ? `Full Xcode compiler and macOS SDK are available at ${XCODE_APP}` : `Full Xcode is required at ${XCODE_APP}; Command Line Tools alone cannot perform protected-app injection or build the local audio driver`,
|
|
401
450
|
...!xcodeReady ? { actionId: "install-xcode-tools" } : {}
|
|
402
451
|
});
|
|
403
|
-
if (!xcodeReady) addAction(actions, {
|
|
404
|
-
id: "install-xcode-tools",
|
|
405
|
-
kind: "command",
|
|
406
|
-
label: "Install full Xcode in /Applications",
|
|
407
|
-
command: "open 'https://apps.apple.com/us/app/xcode/id497799835'"
|
|
408
|
-
});
|
|
409
452
|
const developerSecurity = await checkCommand(params.runCommandWithTimeout, ["/usr/sbin/DevToolsSecurity", "-status"], (stdout) => firstLine(stdout) ?? "Developer tools access enabled");
|
|
410
453
|
const developerSecurityEnabled = developerSecurity.ok && /enabled/iu.test(developerSecurity.message);
|
|
411
454
|
checks.push({
|
|
@@ -416,12 +459,6 @@ async function runFaceTimeSetup(params) {
|
|
|
416
459
|
message: developerSecurityEnabled ? developerSecurity.message : "Developer tools access is disabled; helper injection cannot attach to FaceTime or Phone",
|
|
417
460
|
...!developerSecurityEnabled ? { actionId: "enable-developer-tools" } : {}
|
|
418
461
|
});
|
|
419
|
-
if (!developerSecurityEnabled) addAction(actions, {
|
|
420
|
-
id: "enable-developer-tools",
|
|
421
|
-
kind: "command",
|
|
422
|
-
label: "Enable developer tools access",
|
|
423
|
-
command: "sudo /usr/sbin/DevToolsSecurity -enable"
|
|
424
|
-
});
|
|
425
462
|
const sip = await checkCommand(params.runCommandWithTimeout, ["/usr/bin/csrutil", "status"], (stdout) => stdout.trim());
|
|
426
463
|
const debuggingRestrictionsDisabled = sip.ok && /^[\t ]*(?:System Integrity Protection status:|Debugging Restrictions:)[\t ]*disabled\.?[\t ]*\r?$/imu.test(sip.message);
|
|
427
464
|
const debuggingRestrictionsEnabled = sip.ok && /^[\t ]*(?:System Integrity Protection status:|Debugging Restrictions:)[\t ]*enabled\.?[\t ]*\r?$/imu.test(sip.message);
|
|
@@ -434,19 +471,6 @@ async function runFaceTimeSetup(params) {
|
|
|
434
471
|
message: debuggingRestrictionsDisabled ? "SIP permits debugger attachment to FaceTime and Phone; a connected helper must still be verified separately" : debuggingRestrictionsEnabled ? "SIP debugging restrictions block LLDB helper injection into protected Apple apps" : "Could not verify SIP debugging restrictions; run csrutil status before changing protection settings",
|
|
435
472
|
...!debuggingRestrictionsDisabled ? { actionId: sipActionId } : {}
|
|
436
473
|
});
|
|
437
|
-
if (!debuggingRestrictionsDisabled && debuggingRestrictionsEnabled) addAction(actions, {
|
|
438
|
-
id: "disable-sip-debugging",
|
|
439
|
-
kind: "recovery",
|
|
440
|
-
label: "Disable SIP debugging restrictions from macOS Recovery, then reboot and rerun setup",
|
|
441
|
-
command: "csrutil enable --without debug",
|
|
442
|
-
settingsPath: "macOS Recovery > Utilities > Terminal"
|
|
443
|
-
});
|
|
444
|
-
else if (!debuggingRestrictionsDisabled) addAction(actions, {
|
|
445
|
-
id: "verify-sip-status",
|
|
446
|
-
kind: "command",
|
|
447
|
-
label: "Verify SIP status, then rerun setup",
|
|
448
|
-
command: "/usr/bin/csrutil status"
|
|
449
|
-
});
|
|
450
474
|
checks.push({
|
|
451
475
|
id: "owner-handles",
|
|
452
476
|
label: "Owner FaceTime handles",
|
|
@@ -455,21 +479,14 @@ async function runFaceTimeSetup(params) {
|
|
|
455
479
|
message: params.config.ownerHandles.length > 0 ? `${params.config.ownerHandles.length} owner handle${params.config.ownerHandles.length === 1 ? "" : "s"} configured` : "Configure at least one owner email address or phone number",
|
|
456
480
|
...params.config.ownerHandles.length === 0 ? { actionId: "configure-owner-handles" } : {}
|
|
457
481
|
});
|
|
458
|
-
if (params.config.ownerHandles.length === 0) addAction(actions, {
|
|
459
|
-
id: "configure-owner-handles",
|
|
460
|
-
kind: "command",
|
|
461
|
-
label: "Configure ownerHandles",
|
|
462
|
-
command: "openclaw configure"
|
|
463
|
-
});
|
|
464
482
|
checks.push({
|
|
465
483
|
id: "native-package",
|
|
466
484
|
label: "FaceTime native package",
|
|
467
485
|
status: params.nativePackageReady ? "ready" : "action-required",
|
|
468
486
|
required: true,
|
|
469
487
|
message: params.nativePackageReady ? "Compatible FaceTime capture and helper artifacts are installed" : "Compatible FaceTime native helpers are not installed",
|
|
470
|
-
...!params.nativePackageReady ? { actionId:
|
|
488
|
+
...!params.nativePackageReady ? { actionId: "install-native-package" } : {}
|
|
471
489
|
});
|
|
472
|
-
if (!params.nativePackageReady) addAction(actions, NATIVE_PACKAGE_ACTION);
|
|
473
490
|
const runtimeStatus = params.nativePackageReady && params.runtimeStatus ? await params.runtimeStatus : void 0;
|
|
474
491
|
checks.push({
|
|
475
492
|
id: "runtime",
|
|
@@ -477,13 +494,7 @@ async function runFaceTimeSetup(params) {
|
|
|
477
494
|
status: runtimeStatus ? "ready" : "action-required",
|
|
478
495
|
required: true,
|
|
479
496
|
message: runtimeStatus ? "Runtime activated on the local UID-derived helper endpoint" : params.runtimeError ?? "FaceTime runtime is not running",
|
|
480
|
-
...!runtimeStatus ? { actionId: params.nativePackageReady ? "restart-gateway" :
|
|
481
|
-
});
|
|
482
|
-
if (!runtimeStatus && params.nativePackageReady) addAction(actions, {
|
|
483
|
-
id: "restart-gateway",
|
|
484
|
-
kind: "command",
|
|
485
|
-
label: "Stop the stale gateway process, then restart OpenClaw",
|
|
486
|
-
command: "openclaw gateway restart"
|
|
497
|
+
...!runtimeStatus ? { actionId: params.nativePackageReady ? "restart-gateway" : "install-native-package" } : {}
|
|
487
498
|
});
|
|
488
499
|
if (runtimeStatus) for (const target of runtimeStatus.helperTargets) {
|
|
489
500
|
const status = target.connected ? "ready" : target.stale ? "action-required" : target.injecting || target.queued || target.retryScheduled ? "repairing" : "action-required";
|
|
@@ -495,16 +506,6 @@ async function runFaceTimeSetup(params) {
|
|
|
495
506
|
message: target.connected ? "Authenticated helper connected" : target.stale ? `Restart ${target.target} so it can load the current helper` : status === "repairing" && target.lastError ? `Automatic retry scheduled after: ${target.lastError}` : target.lastError ? target.lastError : "OpenClaw is launching the app and injecting the helper",
|
|
496
507
|
...status === "repairing" ? { actionId: "wait-for-helper" } : status === "action-required" ? { actionId: "restart-call-apps" } : {}
|
|
497
508
|
});
|
|
498
|
-
if (status === "repairing") addAction(actions, {
|
|
499
|
-
id: "wait-for-helper",
|
|
500
|
-
kind: "automatic",
|
|
501
|
-
label: "Wait for automatic helper injection to finish"
|
|
502
|
-
});
|
|
503
|
-
else if (status === "action-required") addAction(actions, {
|
|
504
|
-
id: "restart-call-apps",
|
|
505
|
-
kind: "manual-test",
|
|
506
|
-
label: "Quit and reopen FaceTime and Phone, then let OpenClaw reinject the helper"
|
|
507
|
-
});
|
|
508
509
|
}
|
|
509
510
|
const driver = params.nativePackageReady ? await inspectDriver(params) : {};
|
|
510
511
|
const driverReady = driver.status === "current";
|
|
@@ -514,37 +515,17 @@ async function runFaceTimeSetup(params) {
|
|
|
514
515
|
status: driverReady ? "ready" : "action-required",
|
|
515
516
|
required: true,
|
|
516
517
|
message: driverReady ? "OpenClaw-Mic and OpenClaw-Feed driver is current" : !params.nativePackageReady ? "Install the FaceTime native package before setting up the audio driver" : driver.error ? `Could not inspect driver: ${driver.error}` : `Driver status: ${driver.status ?? "unknown"}`,
|
|
517
|
-
...!driverReady ? { actionId: params.nativePackageReady ? "install-driver" :
|
|
518
|
-
});
|
|
519
|
-
if (!driverReady && params.nativePackageReady) addAction(actions, {
|
|
520
|
-
id: "install-driver",
|
|
521
|
-
kind: "gateway",
|
|
522
|
-
label: "Install or update the paired FaceTime audio driver",
|
|
523
|
-
gatewayMethod: "facetime.installDriver"
|
|
518
|
+
...!driverReady ? { actionId: params.nativePackageReady ? "install-driver" : "install-native-package" } : {}
|
|
524
519
|
});
|
|
525
520
|
if (params.preflight) {
|
|
526
521
|
const preflight = await params.preflight;
|
|
527
522
|
for (const check of preflight.checks) {
|
|
528
523
|
if (check.id === "helper-connected" && runtimeStatus?.helperTargets.length) continue;
|
|
529
|
-
addPreflightCheck(checks,
|
|
524
|
+
addPreflightCheck(checks, check);
|
|
530
525
|
}
|
|
531
526
|
}
|
|
532
|
-
|
|
533
|
-
checks.push(
|
|
534
|
-
if (focus.status === "verify-on-call") addAction(actions, {
|
|
535
|
-
id: "verify-focus",
|
|
536
|
-
kind: "system-settings",
|
|
537
|
-
label: "Verify Focus is off or allows the expected caller",
|
|
538
|
-
settingsPath: "Control Center > Focus"
|
|
539
|
-
});
|
|
540
|
-
const sharingNotifications = await checkNotificationsDuringSharing(params.runCommandWithTimeout);
|
|
541
|
-
checks.push(sharingNotifications);
|
|
542
|
-
if (sharingNotifications.status === "action-required") addAction(actions, {
|
|
543
|
-
id: "allow-sharing-notifications",
|
|
544
|
-
kind: "system-settings",
|
|
545
|
-
label: "Allow notifications while mirroring or sharing the display",
|
|
546
|
-
settingsPath: "System Settings > Notifications"
|
|
547
|
-
});
|
|
527
|
+
checks.push(await checkFocusMode(params));
|
|
528
|
+
checks.push(await checkNotificationsDuringSharing(params.runCommandWithTimeout));
|
|
548
529
|
checks.push({
|
|
549
530
|
id: "facetime-sign-in",
|
|
550
531
|
label: "FaceTime account",
|
|
@@ -553,12 +534,6 @@ async function runFaceTimeSetup(params) {
|
|
|
553
534
|
message: "macOS does not expose a supported sign-in readiness API; verify with one outbound call",
|
|
554
535
|
actionId: "live-outbound-test"
|
|
555
536
|
});
|
|
556
|
-
addAction(actions, {
|
|
557
|
-
id: "live-outbound-test",
|
|
558
|
-
kind: "manual-test",
|
|
559
|
-
label: "Place one outbound FaceTime audio call with facetime.dial",
|
|
560
|
-
gatewayMethod: "facetime.dial"
|
|
561
|
-
});
|
|
562
537
|
const internalMediaStage = runtimeStatus?.calls.find((call) => call.audioReady && call.realtimeActive && call.audioTransport?.processInputVerified === true && call.audioTransport.processOutputSuppressed);
|
|
563
538
|
checks.push({
|
|
564
539
|
id: "internal-media-stage",
|
|
@@ -568,11 +543,6 @@ async function runFaceTimeSetup(params) {
|
|
|
568
543
|
message: internalMediaStage ? "Process capture, model session, SoX playback, and local suppression reached the internal media stage; remote audibility is not proven" : "Internal media stages require an active call; remote audibility still needs a separate live check",
|
|
569
544
|
...!internalMediaStage ? { actionId: "live-audio-test" } : {}
|
|
570
545
|
});
|
|
571
|
-
if (!internalMediaStage) addAction(actions, {
|
|
572
|
-
id: "live-audio-test",
|
|
573
|
-
kind: "manual-test",
|
|
574
|
-
label: "Run one inbound and one outbound FaceTime audio call"
|
|
575
|
-
});
|
|
576
546
|
checks.push({
|
|
577
547
|
id: "live-voicemail",
|
|
578
548
|
label: "Live Voicemail call screening",
|
|
@@ -581,20 +551,13 @@ async function runFaceTimeSetup(params) {
|
|
|
581
551
|
message: "If incoming FaceTime Audio rings are intercepted, turn off Live Voicemail on this unattended Mac",
|
|
582
552
|
actionId: "review-live-voicemail"
|
|
583
553
|
});
|
|
584
|
-
|
|
585
|
-
id: "review-live-voicemail",
|
|
586
|
-
kind: "system-settings",
|
|
587
|
-
label: "Review Live Voicemail if inbound audio calls are screened",
|
|
588
|
-
settingsPath: "Phone > Settings > Live Voicemail"
|
|
589
|
-
});
|
|
590
|
-
const requiredReady = checks.every((check) => !check.required || check.status === "ready" || check.status === "repairing");
|
|
591
|
-
const repairsPending = checks.some((check) => check.required && check.status === "repairing");
|
|
554
|
+
const ready = checks.every((check) => !check.required || check.status === "ready");
|
|
592
555
|
return {
|
|
593
|
-
ok:
|
|
594
|
-
readyForTest:
|
|
556
|
+
ok: ready,
|
|
557
|
+
readyForTest: ready,
|
|
595
558
|
liveCallProofRequired: true,
|
|
596
559
|
checks,
|
|
597
|
-
actions
|
|
560
|
+
actions: [...new Set(checks.flatMap((check) => check.actionId ? [check.actionId] : []))].map((id) => Object.assign({ id }, SETUP_ACTIONS[id]))
|
|
598
561
|
};
|
|
599
562
|
}
|
|
600
563
|
//#endregion
|
|
@@ -1,5 +1,187 @@
|
|
|
1
1
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
|
-
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __exportAll = (all, no_symbols) => {
|
|
8
|
+
let target = {};
|
|
9
|
+
for (var name in all) __defProp(target, name, {
|
|
10
|
+
get: all[name],
|
|
11
|
+
enumerable: true
|
|
12
|
+
});
|
|
13
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
14
|
+
return target;
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
18
|
+
key = keys[i];
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
20
|
+
get: ((k) => from[k]).bind(null, key),
|
|
21
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region packages/normalization-core/src/record-coerce.ts
|
|
29
|
+
/** Type guard for non-array object records at browser-safe boundaries. */
|
|
30
|
+
function isRecord(value) {
|
|
31
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
32
|
+
}
|
|
33
|
+
/** Returns a non-array record or null. */
|
|
34
|
+
function asNullableRecord(value) {
|
|
35
|
+
return isRecord(value) ? value : null;
|
|
36
|
+
}
|
|
37
|
+
//#endregion
|
|
38
|
+
//#region src/config/channel-config-normalization.ts
|
|
39
|
+
/** Applies one channel-specific doctor migration to every object-shaped account. */
|
|
40
|
+
function normalizeChannelAccounts(params) {
|
|
41
|
+
const rawAccounts = asNullableRecord(params.entry.accounts);
|
|
42
|
+
if (!rawAccounts) return {
|
|
43
|
+
entry: params.entry,
|
|
44
|
+
changed: false
|
|
45
|
+
};
|
|
46
|
+
let changed = false;
|
|
47
|
+
const accounts = { ...rawAccounts };
|
|
48
|
+
for (const [accountId, value] of Object.entries(rawAccounts)) {
|
|
49
|
+
const account = asNullableRecord(value);
|
|
50
|
+
if (!account) continue;
|
|
51
|
+
const normalized = params.normalizeAccount({
|
|
52
|
+
account,
|
|
53
|
+
accountId,
|
|
54
|
+
pathPrefix: `${params.pathPrefix}.accounts.${accountId}`,
|
|
55
|
+
changes: params.changes
|
|
56
|
+
});
|
|
57
|
+
if (normalized.changed) {
|
|
58
|
+
accounts[accountId] = normalized.entry;
|
|
59
|
+
changed = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return changed ? {
|
|
63
|
+
entry: {
|
|
64
|
+
...params.entry,
|
|
65
|
+
accounts
|
|
66
|
+
},
|
|
67
|
+
changed: true
|
|
68
|
+
} : {
|
|
69
|
+
entry: params.entry,
|
|
70
|
+
changed: false
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/** Applies the same channel-specific doctor migration at root and account scope. */
|
|
74
|
+
function normalizeChannelConfigEntries(params) {
|
|
75
|
+
const changes = params.changes ?? [];
|
|
76
|
+
const channels = params.cfg.channels;
|
|
77
|
+
const entry = asNullableRecord(channels?.[params.channelId]);
|
|
78
|
+
if (!entry) return {
|
|
79
|
+
config: params.cfg,
|
|
80
|
+
changes
|
|
81
|
+
};
|
|
82
|
+
const channelPath = `channels.${params.channelId}`;
|
|
83
|
+
const root = params.normalizeEntry({
|
|
84
|
+
entry,
|
|
85
|
+
pathPrefix: channelPath,
|
|
86
|
+
changes
|
|
87
|
+
});
|
|
88
|
+
const accounts = normalizeChannelAccounts({
|
|
89
|
+
entry: root.entry,
|
|
90
|
+
pathPrefix: channelPath,
|
|
91
|
+
changes,
|
|
92
|
+
normalizeAccount: (accountParams) => params.normalizeEntry({
|
|
93
|
+
entry: accountParams.account,
|
|
94
|
+
accountId: accountParams.accountId,
|
|
95
|
+
pathPrefix: accountParams.pathPrefix,
|
|
96
|
+
changes: accountParams.changes
|
|
97
|
+
})
|
|
98
|
+
});
|
|
99
|
+
if (!root.changed && !accounts.changed) return {
|
|
100
|
+
config: params.cfg,
|
|
101
|
+
changes
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
config: {
|
|
105
|
+
...params.cfg,
|
|
106
|
+
channels: {
|
|
107
|
+
...channels,
|
|
108
|
+
[params.channelId]: accounts.entry
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
changes
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
//#region src/plugin-sdk/legacy-webhook-listener-migration.ts
|
|
116
|
+
/** Preserve explicitly configured webhook listeners while moving ingress onto Gateway routes. */
|
|
117
|
+
function createLegacyWebhookListenerDoctorContract(params) {
|
|
118
|
+
const portKey = params.portKey ?? "webhookPort";
|
|
119
|
+
const hostKey = params.hostKey === void 0 ? "webhookHost" : params.hostKey;
|
|
120
|
+
const source = (entry) => params.webhookKey ? asNullableRecord(entry[params.webhookKey]) : entry;
|
|
121
|
+
const hasLegacy = (value) => {
|
|
122
|
+
const entry = asNullableRecord(value);
|
|
123
|
+
const listener = entry && source(entry);
|
|
124
|
+
return Boolean(listener && (Object.hasOwn(listener, portKey) || hostKey && Object.hasOwn(listener, hostKey)));
|
|
125
|
+
};
|
|
126
|
+
const prefix = `channels.${params.channelKey}`;
|
|
127
|
+
return {
|
|
128
|
+
legacyConfigRules: [{
|
|
129
|
+
path: ["channels", params.channelKey],
|
|
130
|
+
message: `${prefix} webhook listeners moved to Gateway routes. Run "openclaw doctor --fix" to preserve explicitly configured listener settings as legacyWebhook.`,
|
|
131
|
+
match: (value) => {
|
|
132
|
+
const accounts = asNullableRecord(asNullableRecord(value)?.accounts);
|
|
133
|
+
return hasLegacy(value) || Object.values(accounts ?? {}).some(hasLegacy);
|
|
134
|
+
}
|
|
135
|
+
}],
|
|
136
|
+
normalizeCompatibilityConfig: ({ cfg }) => {
|
|
137
|
+
const root = asNullableRecord(asNullableRecord(cfg.channels)?.[params.channelKey]);
|
|
138
|
+
const inherited = root && source(root);
|
|
139
|
+
const canonicalRoot = asNullableRecord(root?.legacyWebhook);
|
|
140
|
+
return normalizeChannelConfigEntries({
|
|
141
|
+
cfg,
|
|
142
|
+
channelId: params.channelKey,
|
|
143
|
+
normalizeEntry: ({ entry, accountId, pathPrefix, changes }) => {
|
|
144
|
+
const listener = source(entry);
|
|
145
|
+
if (!listener || !hasLegacy(entry)) return {
|
|
146
|
+
entry,
|
|
147
|
+
changed: false
|
|
148
|
+
};
|
|
149
|
+
const next = { ...entry };
|
|
150
|
+
const port = Object.hasOwn(listener, portKey) ? listener[portKey] : (accountId ? canonicalRoot?.port ?? inherited?.[portKey] : void 0) ?? params.defaultPort;
|
|
151
|
+
const inheritedHost = accountId ? canonicalRoot ? canonicalRoot.host : (hostKey ? inherited?.[hostKey] : void 0) ?? params.defaultHost : params.defaultHost;
|
|
152
|
+
const host = hostKey ? listener[hostKey] ?? inheritedHost : inheritedHost;
|
|
153
|
+
const legacyPath = [pathPrefix, params.webhookKey].filter(Boolean).join(".");
|
|
154
|
+
if (Object.hasOwn(entry, "legacyWebhook")) changes.push(`Removed ${legacyPath} legacy listener keys; ${pathPrefix}.legacyWebhook is already configured.`);
|
|
155
|
+
else if (accountId && root?.legacyWebhook === false) changes.push(`Removed ${legacyPath} legacy listener keys; ${prefix}.legacyWebhook: false keeps this account's inherited listener disabled.`);
|
|
156
|
+
else {
|
|
157
|
+
next.legacyWebhook = {
|
|
158
|
+
port,
|
|
159
|
+
...host !== void 0 ? { host } : {}
|
|
160
|
+
};
|
|
161
|
+
changes.push(`Moved ${legacyPath} listener settings to ${pathPrefix}.legacyWebhook. Point the external callback or reverse proxy at the Gateway port and webhook path, verify delivery, then set legacyWebhook: false to disable legacy forwarding.`);
|
|
162
|
+
}
|
|
163
|
+
const updated = params.webhookKey ? { ...listener } : next;
|
|
164
|
+
delete updated[portKey];
|
|
165
|
+
if (hostKey) delete updated[hostKey];
|
|
166
|
+
if (params.webhookKey) {
|
|
167
|
+
if (Object.keys(updated).length) next[params.webhookKey] = updated;
|
|
168
|
+
else delete next[params.webhookKey];
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
entry: next,
|
|
172
|
+
changed: true
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/runtime-doctor-migrations
|
|
181
|
+
var runtime_doctor_migrations_exports = /* @__PURE__ */ __exportAll({ createLegacyWebhookListenerDoctorContract: () => createLegacyWebhookListenerDoctorContract });
|
|
182
|
+
import * as import_openclaw_plugin_sdk_runtime_doctor_migrations from "openclaw/plugin-sdk/runtime-doctor-migrations";
|
|
183
|
+
__reExport(runtime_doctor_migrations_exports, import_openclaw_plugin_sdk_runtime_doctor_migrations);
|
|
184
|
+
//#endregion
|
|
3
185
|
//#region extensions/facetime/doctor-contract-api.ts
|
|
4
186
|
const CONFIG_PATH = [
|
|
5
187
|
"plugins",
|
|
@@ -32,23 +214,23 @@ function normalizeLegacyOwnerHandles(value) {
|
|
|
32
214
|
}
|
|
33
215
|
/** Moves or removes retired prototype keys so runtime sees only the canonical config shape. */
|
|
34
216
|
function normalizeCompatibilityConfig({ cfg }) {
|
|
35
|
-
const entry = asObjectRecord(cfg.plugins?.entries?.facetime);
|
|
36
|
-
const pluginConfig = asObjectRecord(entry?.config);
|
|
217
|
+
const entry = (0, runtime_doctor_migrations_exports.asObjectRecord)(cfg.plugins?.entries?.facetime);
|
|
218
|
+
const pluginConfig = (0, runtime_doctor_migrations_exports.asObjectRecord)(entry?.config);
|
|
37
219
|
if (!pluginConfig) return {
|
|
38
220
|
config: cfg,
|
|
39
221
|
changes: []
|
|
40
222
|
};
|
|
41
223
|
const hasLegacyOwnerHandles = Object.hasOwn(pluginConfig, "whitelistHandles");
|
|
42
224
|
const retiredKeys = RETIRED_CONFIG_KEYS.filter((key) => Object.hasOwn(pluginConfig, key));
|
|
43
|
-
const realtime = asObjectRecord(pluginConfig.realtime);
|
|
225
|
+
const realtime = (0, runtime_doctor_migrations_exports.asObjectRecord)(pluginConfig.realtime);
|
|
44
226
|
const hasRetiredBrain = Boolean(realtime && Object.hasOwn(realtime, "brain"));
|
|
45
227
|
if (!hasLegacyOwnerHandles && retiredKeys.length === 0 && !hasRetiredBrain) return {
|
|
46
228
|
config: cfg,
|
|
47
229
|
changes: []
|
|
48
230
|
};
|
|
49
231
|
const nextConfig = structuredClone(cfg);
|
|
50
|
-
const nextEntry = asObjectRecord(nextConfig.plugins?.entries?.facetime);
|
|
51
|
-
const nextPluginConfig = asObjectRecord(nextEntry?.config);
|
|
232
|
+
const nextEntry = (0, runtime_doctor_migrations_exports.asObjectRecord)(nextConfig.plugins?.entries?.facetime);
|
|
233
|
+
const nextPluginConfig = (0, runtime_doctor_migrations_exports.asObjectRecord)(nextEntry?.config);
|
|
52
234
|
if (!nextPluginConfig) return {
|
|
53
235
|
config: cfg,
|
|
54
236
|
changes: []
|
|
@@ -71,7 +253,7 @@ function normalizeCompatibilityConfig({ cfg }) {
|
|
|
71
253
|
delete nextPluginConfig[key];
|
|
72
254
|
changes.push(`Removed retired ${[...CONFIG_PATH, key].join(".")}.`);
|
|
73
255
|
}
|
|
74
|
-
const nextRealtime = asObjectRecord(nextPluginConfig.realtime);
|
|
256
|
+
const nextRealtime = (0, runtime_doctor_migrations_exports.asObjectRecord)(nextPluginConfig.realtime);
|
|
75
257
|
if (hasRetiredBrain && nextRealtime) {
|
|
76
258
|
delete nextRealtime.brain;
|
|
77
259
|
changes.push(`Removed retired ${[
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as inspectFaceTimeNativePackage, c as uninstallFaceTimeDriver, i as inspectFaceTimeArtifacts, l as resolveFaceTimeConfig, o as inspectFaceTimeDriver, t as runFaceTimeSetup, u as validateFaceTimeConfig } from "./.setup/setup-
|
|
1
|
+
import { a as inspectFaceTimeNativePackage, c as uninstallFaceTimeDriver, i as inspectFaceTimeArtifacts, l as resolveFaceTimeConfig, o as inspectFaceTimeDriver, t as runFaceTimeSetup, u as validateFaceTimeConfig } from "./.setup/setup-CoxvlB5L.mjs";
|
|
2
2
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
3
3
|
import { ErrorCodes, errorShape } from "openclaw/plugin-sdk/gateway-runtime";
|
|
4
4
|
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
|