@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.
Files changed (57) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{setup-DUgC9yE7.mjs → setup-CoxvlB5L.mjs} +91 -128
  3. package/dist/doctor-contract-api.js +189 -7
  4. package/dist/index.js +1 -1
  5. package/dist/runtime-api.js +197 -238
  6. package/node_modules/typebox/build/compile/code.mjs +1 -2
  7. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  8. package/node_modules/typebox/build/format/iri.mjs +16 -9
  9. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  10. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  11. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  12. package/node_modules/typebox/build/guard/index.mjs +6 -0
  13. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  14. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  15. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  16. package/node_modules/typebox/build/schema/build.mjs +2 -3
  17. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  18. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  19. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  20. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  21. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  22. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  23. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  24. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  25. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  26. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  27. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  28. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  29. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  30. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  31. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  32. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  33. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  34. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  35. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  36. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  37. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  38. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  39. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  40. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  41. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  42. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  43. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  44. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  45. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  46. package/node_modules/typebox/package.json +1 -1
  47. package/node_modules/typebox/readme.md +3 -1
  48. package/package.json +5 -5
  49. package/src/audio-pump.ts +9 -16
  50. package/src/call-events.ts +12 -26
  51. package/src/call-lifecycle.ts +3 -19
  52. package/src/runtime-call-control.ts +3 -12
  53. package/src/runtime-call-events.ts +4 -9
  54. package/src/runtime-state.ts +0 -10
  55. package/src/setup.ts +96 -173
  56. package/src/talk-driver.ts +217 -242
  57. /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 NATIVE_PACKAGE_ACTION = {
222
- id: "install-native-package",
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: NATIVE_PACKAGE_ACTION.label,
232
- command: NATIVE_PACKAGE_ACTION.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
- "paired-driver-mic": {
235
- id: "install-driver",
236
- kind: "gateway",
237
- label: "Install or update the paired FaceTime audio driver",
238
- gatewayMethod: "facetime.installDriver"
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
- "paired-driver-feed": {
241
- id: "install-driver",
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
- "process-tap": {
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 addAction(actions, action) {
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 action = PRECHECK_ACTIONS[check.id];
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 && action ? { actionId: action.id } : {}
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: NATIVE_PACKAGE_ACTION.id } : {}
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" : NATIVE_PACKAGE_ACTION.id } : {}
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" : NATIVE_PACKAGE_ACTION.id } : {}
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, actions, check);
524
+ addPreflightCheck(checks, check);
530
525
  }
531
526
  }
532
- const focus = await checkFocusMode(params);
533
- checks.push(focus);
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
- addAction(actions, {
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: requiredReady && !repairsPending,
594
- readyForTest: requiredReady && !repairsPending,
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
- import { asObjectRecord } from "openclaw/plugin-sdk/runtime-doctor-migrations";
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-DUgC9yE7.mjs";
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";