local-operator-ui 0.34.11 → 0.34.13

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 (69) hide show
  1. package/out/main/index.js +400 -6
  2. package/out/preload/index.js +20 -0
  3. package/out/renderer/assets/{_basePickBy-0FuZakDO.js → _basePickBy-CuMaQXnE.js} +1 -1
  4. package/out/renderer/assets/{_baseUniq-DF-R-zk_.js → _baseUniq-DKeCGkCd.js} +1 -1
  5. package/out/renderer/assets/{agent-details-page-Cpmz3DTx.js → agent-details-page-DNymI5K7.js} +1 -1
  6. package/out/renderer/assets/{agent-hub-page-BjdZHs7N.js → agent-hub-page-Ckv_jCjf.js} +1 -1
  7. package/out/renderer/assets/{agents-page-CFI7y-mh.js → agents-page-CzWn74Vs.js} +3 -3
  8. package/out/renderer/assets/{arc-hMevLt8i.js → arc-CnvhNTGl.js} +1 -1
  9. package/out/renderer/assets/{architectureDiagram-IEHRJDOE-B5fNwTBg.js → architectureDiagram-IEHRJDOE-D87FdX-H.js} +1 -1
  10. package/out/renderer/assets/{blockDiagram-JOT3LUYC-C0eifn71.js → blockDiagram-JOT3LUYC-pWG0SYM0.js} +1 -1
  11. package/out/renderer/assets/{browser-page-DOvqhWYH.js → browser-page-C90b-h7d.js} +1 -1
  12. package/out/renderer/assets/{browser-webauthn-prompt-BInNSrH7.js → browser-webauthn-prompt-D9pJNnAE.js} +1 -1
  13. package/out/renderer/assets/{c4Diagram-VJAJSXHY-B7AqGR0S.js → c4Diagram-VJAJSXHY-n9oZXPrb.js} +1 -1
  14. package/out/renderer/assets/channel-D7v5czrG.js +1 -0
  15. package/out/renderer/assets/{chunk-4BMEZGHF-DRgWg1wB.js → chunk-4BMEZGHF-DUVNV3px.js} +1 -1
  16. package/out/renderer/assets/{chunk-A2AXSNBT-QkYdfOR_.js → chunk-A2AXSNBT-D69ozLLm.js} +1 -1
  17. package/out/renderer/assets/{chunk-AEK57VVT-CCQ--tm8.js → chunk-AEK57VVT-DojzsKw7.js} +1 -1
  18. package/out/renderer/assets/{chunk-D6G4REZN-Czu2dN7h.js → chunk-D6G4REZN-CXPThrUO.js} +1 -1
  19. package/out/renderer/assets/{chunk-RZ5BOZE2-DYG4fw8w.js → chunk-RZ5BOZE2-Tpm4iz0-.js} +1 -1
  20. package/out/renderer/assets/{chunk-XZIHB7SX-CrsWczXN.js → chunk-XZIHB7SX-CM94sy6v.js} +1 -1
  21. package/out/renderer/assets/classDiagram-GIVACNV2-D8dzeJBj.js +1 -0
  22. package/out/renderer/assets/classDiagram-v2-COTLJTTW-D8dzeJBj.js +1 -0
  23. package/out/renderer/assets/clone-BY0fK-il.js +1 -0
  24. package/out/renderer/assets/{conversation-input-sync-jHBqtt9M.js → conversation-input-sync-BvSb6a8F.js} +245 -245
  25. package/out/renderer/assets/{dagre-OKDRZEBW-V_2TdXms.js → dagre-OKDRZEBW-CNxZp61j.js} +1 -1
  26. package/out/renderer/assets/{diagram-SSKATNLV-DmHiewpC.js → diagram-SSKATNLV-aLMzXyK5.js} +1 -1
  27. package/out/renderer/assets/{diagram-VNBRO52H-BBaLkKUI.js → diagram-VNBRO52H-Bg2DhWCA.js} +1 -1
  28. package/out/renderer/assets/{erDiagram-Q7BY3M3F-gzrT0OQq.js → erDiagram-Q7BY3M3F-j_TMas8g.js} +1 -1
  29. package/out/renderer/assets/{flowDiagram-4HSFHLVR-WtEIG1SZ.js → flowDiagram-4HSFHLVR-DwfE01r0.js} +1 -1
  30. package/out/renderer/assets/{ganttDiagram-APWFNJXF-B1jWM42b.js → ganttDiagram-APWFNJXF-o_J5Q4qE.js} +1 -1
  31. package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-_mbC-N8Q.js → gitGraphDiagram-7IBYFJ6S-8AYyb2q7.js} +1 -1
  32. package/out/renderer/assets/{graph--j_bjGDp.js → graph-KSlxkPtr.js} +1 -1
  33. package/out/renderer/assets/{index-SDz2HLAt.js → index-Bxh_DMkN.js} +1 -1
  34. package/out/renderer/assets/{index-78Pu8oX4.js → index-CBio7uVX.js} +1 -1
  35. package/out/renderer/assets/{index-BXFAcfHW.js → index-Wfo25fxR.js} +189 -189
  36. package/out/renderer/assets/{infoDiagram-PH2N3AL5-ZAxI5P-K.js → infoDiagram-PH2N3AL5-Dgx0WJ8T.js} +1 -1
  37. package/out/renderer/assets/{journeyDiagram-U35MCT3I-DZ4RyZqB.js → journeyDiagram-U35MCT3I-De_U2_fi.js} +1 -1
  38. package/out/renderer/assets/{kanban-definition-NDS4AKOZ-kW-9JUyI.js → kanban-definition-NDS4AKOZ-DUuYeORq.js} +1 -1
  39. package/out/renderer/assets/{layout-hBM56uFl.js → layout-Y7ReWUo5.js} +1 -1
  40. package/out/renderer/assets/{legacy-agents-page-lsbEk2J1.js → legacy-agents-page-B9mXqb4D.js} +1 -1
  41. package/out/renderer/assets/{mermaid.core-DUwwjyuA.js → mermaid.core-DNS50-NS.js} +5 -5
  42. package/out/renderer/assets/{mesh-page-R-moWtJ_.js → mesh-page-fWdbRlK8.js} +1 -1
  43. package/out/renderer/assets/{mindmap-definition-ALO5MXBD-CabAvvHv.js → mindmap-definition-ALO5MXBD-D3_S2COi.js} +1 -1
  44. package/out/renderer/assets/{mini-Bk-Elwan.js → mini-Co_TXCJ3.js} +1 -1
  45. package/out/renderer/assets/{org-surface-gate-BblILKma.js → org-surface-gate-ik1uMiLe.js} +1 -1
  46. package/out/renderer/assets/{pieDiagram-IB7DONF6-DfPuydQj.js → pieDiagram-IB7DONF6-C8yur6Ac.js} +1 -1
  47. package/out/renderer/assets/{projects-page-vD-RuTFH.js → projects-page-XYebxBb4.js} +1 -1
  48. package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-miOaNOa0.js → quadrantDiagram-7GDLP6J5-B04MajkG.js} +1 -1
  49. package/out/renderer/assets/{radar-MK3ICKWK-6uN5Oz3u.js → radar-MK3ICKWK-CLCEq4mP.js} +1 -1
  50. package/out/renderer/assets/{radient-auth-buttons-COiSnA2S.js → radient-auth-buttons-D7TF55K4.js} +1 -1
  51. package/out/renderer/assets/{requirementDiagram-KVF5MWMF-ZcBG_T3L.js → requirementDiagram-KVF5MWMF-zeGik6Fv.js} +1 -1
  52. package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-B0yXArdY.js → sankeyDiagram-QLVOVGJD-BZmVH-PV.js} +1 -1
  53. package/out/renderer/assets/{schedules-page-BNxF_SHU.js → schedules-page-tkQ09Qzt.js} +1 -1
  54. package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-Cy6KDW6o.js → sequenceDiagram-X6HHIX6F-UUGTprRZ.js} +1 -1
  55. package/out/renderer/assets/{settings-page-478PcsAW.js → settings-page-kJ4v4696.js} +1 -1
  56. package/out/renderer/assets/{stateDiagram-DGXRK772-SpJc3S_A.js → stateDiagram-DGXRK772-DpuddJOQ.js} +1 -1
  57. package/out/renderer/assets/{stateDiagram-v2-YXO3MK2T-CBW1IyeW.js → stateDiagram-v2-YXO3MK2T-DBnjJOPU.js} +1 -1
  58. package/out/renderer/assets/{timeline-definition-BDJGKUSR-BSbru3ra.js → timeline-definition-BDJGKUSR-mHNW2fr3.js} +1 -1
  59. package/out/renderer/assets/{use-download-agent-mutation-CfvFFmrZ.js → use-download-agent-mutation-CgAZq5FK.js} +1 -1
  60. package/out/renderer/assets/{use-memberships-query-B__m4YCP.js → use-memberships-query-CVbNGH7n.js} +1 -1
  61. package/out/renderer/assets/{use-session-snapshot-CF9Y72Da.js → use-session-snapshot-D3DsMux6.js} +1 -1
  62. package/out/renderer/assets/{xychartDiagram-VJFVF3MP-6d774UsI.js → xychartDiagram-VJFVF3MP-D4S76BDC.js} +1 -1
  63. package/out/renderer/index.html +2 -2
  64. package/out/renderer/mini.html +3 -3
  65. package/package.json +2 -2
  66. package/out/renderer/assets/channel-JotcBz3R.js +0 -1
  67. package/out/renderer/assets/classDiagram-GIVACNV2-CksS_rYL.js +0 -1
  68. package/out/renderer/assets/classDiagram-v2-COTLJTTW-CksS_rYL.js +0 -1
  69. package/out/renderer/assets/clone-BzHauEn5.js +0 -1
package/out/main/index.js CHANGED
@@ -2088,6 +2088,26 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2088
2088
  */
2089
2089
  keys: zod.z.array(zod.z.string().min(1).max(512)).max(256).optional(),
2090
2090
  force: zod.z.boolean().optional()
2091
+ }).strict(),
2092
+ /*
2093
+ * THE PREVIEWS' SIGNED STATIC URLS (file-serving RFC § 4, Phase A adoption).
2094
+ * The renderer cannot read the core's serve record (no filesystem, no record
2095
+ * store), so the previews ask MAIN - which already holds the desktop bearer -
2096
+ * to mint a short-lived signed URL for one static route + path. The route is
2097
+ * public in Phase A; this op is what lets the previews keep working when a
2098
+ * later core phase gates it, and a core that predates the route answers 404,
2099
+ * which the previews read as their fallback signal, not an error.
2100
+ *
2101
+ * `route` is the backend's own signed-string vocabulary (the four static
2102
+ * family ids), held here so a route the signature cannot cover fails at this
2103
+ * boundary. `ttlS` stays within the backend's documented cap (600 default,
2104
+ * 3600 max) - a bound, not a preference.
2105
+ */
2106
+ zod.z.object({
2107
+ op: zod.z.literal("static.sign"),
2108
+ route: zod.z.enum(["images", "videos", "audio", "html"]),
2109
+ path: zod.z.string().min(1),
2110
+ ttlS: zod.z.number().int().min(1).max(3600).optional()
2091
2111
  }).strict()
2092
2112
  ]);
2093
2113
  const desktopRequestSchema = desktopRequestUnion.superRefine(
@@ -3648,6 +3668,23 @@ function desktopEndpoint(request) {
3648
3668
  ...request.force !== void 0 ? { force: request.force } : {}
3649
3669
  }
3650
3670
  };
3671
+ /*
3672
+ * The previews' signed static URLs: NOT under `/v1/desktop/` - the core's
3673
+ * sign route accepts the desktop bearer OR its local access token - so an
3674
+ * answer here never counts as pairing evidence (`desktopAnswerProvesPairing`
3675
+ * reads the prefix, deliberately). `ttl_s` is omitted unless asked for, so
3676
+ * the core's own default (600 s) is the one number for "unspecified".
3677
+ */
3678
+ case "static.sign":
3679
+ return {
3680
+ path: "/v1/static/sign",
3681
+ method: "POST",
3682
+ body: {
3683
+ route: request.route,
3684
+ path: request.path,
3685
+ ttl_s: request.ttlS
3686
+ }
3687
+ };
3651
3688
  }
3652
3689
  }
3653
3690
  const MAX_PROBE_PATHS = 64;
@@ -4484,6 +4521,9 @@ const SHIPIT_RELATIVE_PATH = path$1.join(
4484
4521
  const INSTALLER_TOKEN = "local-operator-update-installer";
4485
4522
  const UPDATE_STAGING_DIR = "update-staging";
4486
4523
  const INSTALLER_POLL_SECONDS = "0.2";
4524
+ const INSTALLER_FIRST_GRACE_SECONDS = 60;
4525
+ const INSTALLER_SECOND_GRACE_SECONDS = 20;
4526
+ const INSTALLER_KILL_SETTLE_SECONDS = "0.5";
4487
4527
  const EXTRACTION_TIMEOUT_MS = 10 * 6e4;
4488
4528
  function shipItPathInBundle(bundlePath) {
4489
4529
  if (!bundlePath) return null;
@@ -4563,6 +4603,8 @@ function shipItStatePlist(input) {
4563
4603
  };
4564
4604
  }
4565
4605
  function buildInstallerSpawn(input) {
4606
+ const firstGrace = input.graceSeconds?.first ?? INSTALLER_FIRST_GRACE_SECONDS;
4607
+ const secondGrace = input.graceSeconds?.second ?? INSTALLER_SECOND_GRACE_SECONDS;
4566
4608
  const script = `#!/bin/sh
4567
4609
  # ${INSTALLER_TOKEN}
4568
4610
  #
@@ -4573,10 +4615,74 @@ function buildInstallerSpawn(input) {
4573
4615
  # (SQRLInstallerErrorDomain Code=-9, the 2026-09-18 09:37 install). So this waits
4574
4616
  # for the app's pid to go, and then replaces itself with the installer: one
4575
4617
  # process, one pid for the app to record, and no shell left in the way.
4576
- while kill -0 "$1" 2>/dev/null; do
4618
+ #
4619
+ # THE WAIT IS BOUNDED AND LOGGED (2026-10-11): the unbounded shape waited 26 m
4620
+ # 49 s while the app sat alive with no window, and logged nothing anywhere. Each
4621
+ # stage below is bounded and writes one timestamped line to the installer's log;
4622
+ # the last stage starts the installer regardless, because a pid that survives
4623
+ # SIGKILL is a zombie and nothing more exists to wait for.
4624
+ app_pid=$1
4625
+ started=$(date +%s)
4626
+ log_stage() {
4627
+ printf '%s ${INSTALLER_TOKEN}: %s\\n' "$(date '+%Y-%m-%dT%H:%M:%S')" "$1" >>"$LO_UPDATE_INSTALLER_LOG"
4628
+ }
4629
+ elapsed() {
4630
+ printf '%d' "$(( $(date +%s) - started ))"
4631
+ }
4632
+ # A recycled pid is never signalled: before any kill, the target's command line
4633
+ # must still name the app's own executable ($LO_UPDATE_INSTALLER_APP_EXEC,
4634
+ # environment only - see the args comment at the callers).
4635
+ target_is_app() {
4636
+ [ -n "$LO_UPDATE_INSTALLER_APP_EXEC" ] || return 1
4637
+ _line=$(ps -o command= -p "$app_pid" 2>/dev/null) || return 1
4638
+ case "$_line" in
4639
+ *"$LO_UPDATE_INSTALLER_APP_EXEC"*) return 0 ;;
4640
+ esac
4641
+ return 1
4642
+ }
4643
+ start_installer() {
4644
+ log_stage "starting the installer ($(elapsed)s in)"
4645
+ exec "$LO_UPDATE_INSTALLER_SHIPIT" "$LO_UPDATE_INSTALLER_LABEL" "$LO_UPDATE_INSTALLER_STATE" >>"$LO_UPDATE_INSTALLER_LOG" 2>&1
4646
+ }
4647
+ log_stage "waiting up to ${firstGrace}s for the app to exit on its own"
4648
+ _end=$((started + ${firstGrace}))
4649
+ while kill -0 "$app_pid" 2>/dev/null; do
4650
+ if [ "$(date +%s)" -ge "$_end" ]; then break; fi
4577
4651
  sleep ${INSTALLER_POLL_SECONDS}
4578
4652
  done
4579
- exec "$LO_UPDATE_INSTALLER_SHIPIT" "$LO_UPDATE_INSTALLER_LABEL" "$LO_UPDATE_INSTALLER_STATE" >>"$LO_UPDATE_INSTALLER_LOG" 2>&1
4653
+ if ! kill -0 "$app_pid" 2>/dev/null; then
4654
+ log_stage "the app exited on its own ($(elapsed)s in)"
4655
+ start_installer
4656
+ fi
4657
+ log_stage "the first grace expired with the app still there"
4658
+ if target_is_app; then
4659
+ log_stage "asking the app to stop (SIGTERM)"
4660
+ kill -TERM "$app_pid" 2>/dev/null
4661
+ _end=$(( $(date +%s) + ${secondGrace} ))
4662
+ while kill -0 "$app_pid" 2>/dev/null; do
4663
+ if [ "$(date +%s)" -ge "$_end" ]; then break; fi
4664
+ sleep ${INSTALLER_POLL_SECONDS}
4665
+ done
4666
+ if ! kill -0 "$app_pid" 2>/dev/null; then
4667
+ log_stage "the app exited after SIGTERM ($(elapsed)s in)"
4668
+ start_installer
4669
+ fi
4670
+ if target_is_app; then
4671
+ log_stage "the second grace expired; forcing the pid gone (SIGKILL)"
4672
+ kill -KILL "$app_pid" 2>/dev/null
4673
+ sleep ${INSTALLER_KILL_SETTLE_SECONDS}
4674
+ if kill -0 "$app_pid" 2>/dev/null; then
4675
+ log_stage "the pid survived SIGKILL (a zombie or unkillable); nothing left to wait for"
4676
+ else
4677
+ log_stage "the app is gone after SIGKILL ($(elapsed)s in)"
4678
+ fi
4679
+ else
4680
+ log_stage "target is not the app after SIGTERM; starting the installer"
4681
+ fi
4682
+ start_installer
4683
+ fi
4684
+ log_stage "target is not the app; starting the installer without signalling"
4685
+ start_installer
4580
4686
  `;
4581
4687
  return {
4582
4688
  script,
@@ -4584,7 +4690,8 @@ exec "$LO_UPDATE_INSTALLER_SHIPIT" "$LO_UPDATE_INSTALLER_LABEL" "$LO_UPDATE_INST
4584
4690
  LO_UPDATE_INSTALLER_SHIPIT: input.shipItPath,
4585
4691
  LO_UPDATE_INSTALLER_LABEL: input.label,
4586
4692
  LO_UPDATE_INSTALLER_STATE: input.statePath,
4587
- LO_UPDATE_INSTALLER_LOG: input.logPath
4693
+ LO_UPDATE_INSTALLER_LOG: input.logPath,
4694
+ LO_UPDATE_INSTALLER_APP_EXEC: input.appExecPath
4588
4695
  },
4589
4696
  // `sh -c <script> <name> <pid>`: the name is $0 and the pid is $1, so the
4590
4697
  // script text carries no path and no number that a process listing of it
@@ -4611,6 +4718,8 @@ const INSTALL_DISK_SLACK_BYTES = 256 * 1024 * 1024;
4611
4718
  const DOWNLOAD_PAGE_URL = "https://local-operator.com/download";
4612
4719
  const WATCHDOG_TIMEOUT_SECONDS = 600;
4613
4720
  const WATCHDOG_HARD_TIMEOUT_SECONDS = 1800;
4721
+ const WATCHDOG_APP_WAIT_NOTICE_SECONDS = 15;
4722
+ const WATCHDOG_APP_WAIT_FALLBACK_SECONDS = 2 * (INSTALLER_FIRST_GRACE_SECONDS + INSTALLER_SECOND_GRACE_SECONDS);
4614
4723
  const PENDING_INSTALL_RECENCY_MARGIN_SECONDS = 300;
4615
4724
  const PENDING_INSTALL_RECENCY_SECONDS = WATCHDOG_HARD_TIMEOUT_SECONDS + PENDING_INSTALL_RECENCY_MARGIN_SECONDS;
4616
4725
  const LAUNCH_HOLD_END_MARGIN_SECONDS = 60;
@@ -5346,13 +5455,15 @@ function watchdogSignals(platform) {
5346
5455
  return { jobProbe: "launchctl", plistReader: "/usr/bin/plutil" };
5347
5456
  }
5348
5457
  function buildWatchdogPlan(input) {
5349
- const signals = input.signals ?? watchdogSignals(input.platform);
5458
+ const signals = input.signals ?? watchdogSignals(input.platform ?? "darwin");
5350
5459
  const timeoutSeconds = input.timeoutSeconds ?? WATCHDOG_TIMEOUT_SECONDS;
5351
5460
  const hardTimeoutSeconds = input.hardTimeoutSeconds ?? WATCHDOG_HARD_TIMEOUT_SECONDS;
5352
5461
  const intervalSeconds = input.intervalSeconds ?? 3;
5353
5462
  const settleSeconds = input.settleSeconds ?? 5;
5354
5463
  const appearSeconds = input.appearSeconds ?? 30;
5355
5464
  const announceSeconds = input.announceSeconds ?? 5;
5465
+ const appWaitNoticeSeconds = input.appWaitNoticeSeconds ?? WATCHDOG_APP_WAIT_NOTICE_SECONDS;
5466
+ const appWaitFallbackSeconds = input.appWaitFallbackSeconds ?? WATCHDOG_APP_WAIT_FALLBACK_SECONDS;
5356
5467
  const plistTimeoutSeconds = input.plistReadTimeoutSeconds ?? PLIST_READ_TIMEOUT_SECONDS;
5357
5468
  const script = `#!/bin/sh
5358
5469
  # ${WATCHDOG_TOKEN}
@@ -5450,6 +5561,27 @@ if [ -z "$APP_PID" ] || [ -z "$BUNDLE" ]; then
5450
5561
  fi
5451
5562
  now() { date +%s; }
5452
5563
  app_running() { kill -0 "$APP_PID" 2>/dev/null; }
5564
+ # THE WAIT'S OWN CLOCK (2026-10-11). The script is spawned as the quit begins, so
5565
+ # its own start IS the wait's start - elapsed is measured from here rather than
5566
+ # from the marker's startedAt, which is written before the quit and would need a
5567
+ # new seam through two collaborators for a difference of seconds.
5568
+ started=$(now)
5569
+ # "waiting 15 s" / "waiting 2 min 30 s": elapsed in the units a person reads,
5570
+ # with the seconds term dropped at an exact minute ("waiting 30 min") - "30 min
5571
+ # 0 s" reads like a clock fault rather than a wait (round-1 D2).
5572
+ elapsed_text() {
5573
+ _seconds=$(( $(now) - started ))
5574
+ if [ "$_seconds" -lt 0 ]; then _seconds=0; fi
5575
+ if [ "$_seconds" -ge 60 ]; then
5576
+ if [ $((_seconds % 60)) -eq 0 ]; then
5577
+ printf '%d min' "$((_seconds / 60))"
5578
+ else
5579
+ printf '%d min %d s' "$((_seconds / 60))" "$((_seconds % 60))"
5580
+ fi
5581
+ else
5582
+ printf '%d s' "$_seconds"
5583
+ fi
5584
+ }
5453
5585
  # Whether ANY process is this install's ShipIt, for the pid that stopped being it.
5454
5586
  #
5455
5587
  # The same two facts installerElsewhere requires of a line in its listing: this
@@ -5676,8 +5808,31 @@ decided() {
5676
5808
  deadline=$(( $(now) + ${timeoutSeconds} ))
5677
5809
  hard_deadline=$(( $(now) + ${hardTimeoutSeconds} ))
5678
5810
  # 1. The install only starts once the old app has exited.
5811
+ #
5812
+ # AND THE WAIT SPEAKS, INSTEAD OF LEAVING THE PERSON IN SILENCE (2026-10-11).
5813
+ # The incident's app sat alive with no window for 26 m 49 s; this script was
5814
+ # the only process left that could say anything, and its first step was
5815
+ # silent until the soft bound - the person watched nothing happen and
5816
+ # resolved it by hand ('kill -TERM', which is what let ShipIt exec). So the
5817
+ # wait now says what it is waiting for and for how long, well before the
5818
+ # installer's own escalation signals the app
5819
+ # (WATCHDOG_APP_WAIT_NOTICE_SECONDS), and after the escalation has
5820
+ # provably failed it hands over the action that works
5821
+ # (WATCHDOG_APP_WAIT_FALLBACK_SECONDS). Each fires at most once; the
5822
+ # kill switch silences both like every other notice (notify's own guard).
5823
+ app_wait_notice=0
5824
+ app_wait_fallback=0
5679
5825
  while app_running; do
5680
5826
  if [ "$(now)" -ge "$deadline" ]; then break; fi
5827
+ _waited=$(( $(now) - started ))
5828
+ if [ "$app_wait_notice" -eq 0 ] && [ "$_waited" -ge ${appWaitNoticeSeconds} ]; then
5829
+ app_wait_notice=1
5830
+ notify "Waiting for Local Operator to close so the update can install (waiting $(elapsed_text)). No action is needed yet."
5831
+ fi
5832
+ if [ "$app_wait_fallback" -eq 0 ] && [ "$_waited" -ge ${appWaitFallbackSeconds} ]; then
5833
+ app_wait_fallback=1
5834
+ notify "The update is still waiting for Local Operator to close (waiting $(elapsed_text)). If nothing happens, quit Local Operator (Force Quit if it does not respond) and leave it closed until it opens again by itself."
5835
+ fi
5681
5836
  sleep ${intervalSeconds}
5682
5837
  done
5683
5838
  # 1b. The app is gone and an install is at work, so the window that just
@@ -5752,7 +5907,16 @@ while :; do
5752
5907
  if [ "$(now)" -ge "$deadline" ]; then
5753
5908
  if [ "$signal_known" -eq 1 ] && install_live; then
5754
5909
  holding=1
5755
- notify "The update is still installing. Keep Local Operator closed; it will open again when the install finishes."
5910
+ # THE SOFT BOUND BRANCHES TOO (round-1 UX U4): it fires while the app
5911
+ # may still be RUNNING, where "keep it closed" describes a state the
5912
+ # person is not in. App running -> the wait/fallback copy with a fresh
5913
+ # elapsed reading; app gone -> the stay-closed copy, which is true there
5914
+ # (an install this app spawned is live and the swap still needs quiet).
5915
+ if app_running; then
5916
+ notify "The update is still waiting for Local Operator to close (waiting $(elapsed_text)). If nothing happens, quit Local Operator (Force Quit if it does not respond) and leave it closed until it opens again by itself."
5917
+ else
5918
+ notify "The update is still installing. Keep Local Operator closed; it will open again when the install finishes."
5919
+ fi
5756
5920
  fi
5757
5921
  break
5758
5922
  fi
@@ -5780,7 +5944,20 @@ if [ "$holding" -eq 1 ]; then
5780
5944
  while :; do
5781
5945
  if decided; then break; fi
5782
5946
  if [ "$(now)" -ge "$hard_deadline" ]; then
5783
- notify "The update is taking longer than expected. Local Operator is opening again so you are not left without it — if it says the update is still installing, quit it and leave it closed until the install finishes."
5947
+ # TRUTHFUL ON BOTH ARMS (2026-10-11). The notice that used to stand
5948
+ # here promised "Local Operator is opening again" unconditionally, and
5949
+ # the path below with the app STILL RUNNING ('if app_running; then
5950
+ # exit 0') is exactly where that promise is false - the watchdog
5951
+ # exits without launching, because launching into a running app is
5952
+ # what aborts a swap. So the app-still-running arm now says the true
5953
+ # thing and hands over the action that resolves it, the same fallback
5954
+ # the wait's own notices use; the app-gone arm keeps the notice the
5955
+ # panel's copy expects (UX U10).
5956
+ if app_running; then
5957
+ notify "The update is still waiting for Local Operator to close (waiting $(elapsed_text)). If nothing happens, quit Local Operator (Force Quit if it does not respond) and leave it closed until it opens again by itself."
5958
+ else
5959
+ notify "The update is taking longer than expected. Local Operator is opening again so you are not left without it — if it says the update is still installing, quit it and leave it closed until the install finishes."
5960
+ fi
5784
5961
  break
5785
5962
  fi
5786
5963
  sleep ${intervalSeconds}
@@ -35442,6 +35619,32 @@ function rememberPickedDirectory(kind, filePaths, directoryPicked = false) {
35442
35619
  if (!first) return;
35443
35620
  lastPickedDirectory.set(kind, directoryPicked ? first : path$1.dirname(first));
35444
35621
  }
35622
+ const QUIT_EXIT_DEADLINE_MARGIN_MS = 5e3;
35623
+ function quitExitDeadlineMs(input) {
35624
+ return SESSION_COOKIE_QUIT_BUDGET_MS + input.quitCleanupFailsafeMs + QUIT_EXIT_DEADLINE_MARGIN_MS;
35625
+ }
35626
+ function createQuitExitDeadline(input) {
35627
+ let timer = null;
35628
+ let stage = "";
35629
+ return {
35630
+ arm(next) {
35631
+ if (timer) return;
35632
+ stage = next;
35633
+ timer = setTimeout(() => {
35634
+ timer = null;
35635
+ input.onFire(stage);
35636
+ }, input.timeoutMs);
35637
+ timer.unref();
35638
+ },
35639
+ phase(next) {
35640
+ stage = next;
35641
+ },
35642
+ release() {
35643
+ if (timer) clearTimeout(timer);
35644
+ timer = null;
35645
+ }
35646
+ };
35647
+ }
35445
35648
  function createQuitState() {
35446
35649
  let quitting = false;
35447
35650
  return {
@@ -36440,6 +36643,9 @@ const GLOBAL_UPDATE_TIMEOUT_MS = 15 * 60 * 1e3;
36440
36643
  const SOURCE_REBUILD_TIMEOUT_MS = 30 * 60 * 1e3;
36441
36644
  const UPDATE_RESTART_STOP_GRACE_MS = 5e3;
36442
36645
  const BUNDLE_ID_REGEX = /^[\w.-]+$/;
36646
+ const APP_UPDATE_CACHE_DIR_NAME_REGEX = /^updaterCacheDirName:[ \t]*(\S+)[ \t]*$/m;
36647
+ const CACHE_DIR_NAME_OK_REGEX = /^[A-Za-z0-9._-]+$/;
36648
+ const UPDATER_CACHE_PENDING_FILE_REGEX = /\.zip$/i;
36443
36649
  const INSTALL_IN_FLIGHT_RECHECK_MS = 1e4;
36444
36650
  const LAUNCHCTL_NOT_LOADED_REGEX = /could not find|no such process/i;
36445
36651
  const APP_OWNED_PUBLISH_HEADROOM_BYTES = 450 * 1024 * 1024;
@@ -37446,6 +37652,7 @@ class UpdateService {
37446
37652
  );
37447
37653
  this.reapWatchdog(outcome.marker, true);
37448
37654
  this.reapStagedUpdateTrees();
37655
+ this.reapUpdaterCache();
37449
37656
  clearPendingInstallMarker(this.markerDir());
37450
37657
  this.retireSupersededInstallRecord();
37451
37658
  this.pendingInstallSucceeded = {
@@ -37460,6 +37667,7 @@ class UpdateService {
37460
37667
  );
37461
37668
  this.reapWatchdog(outcome.marker, true);
37462
37669
  this.reapStagedUpdateTrees();
37670
+ this.reapUpdaterCache();
37463
37671
  clearPendingInstallMarker(this.markerDir());
37464
37672
  this.retireSupersededInstallRecord();
37465
37673
  return;
@@ -37512,6 +37720,7 @@ class UpdateService {
37512
37720
  this.reapWatchdog(outcome.marker, false);
37513
37721
  this.reapFailedInstallLeftovers();
37514
37722
  this.reapStagedUpdateTrees();
37723
+ this.reapUpdaterCache();
37515
37724
  this.schedulePendingInstallFailureDelivery();
37516
37725
  }
37517
37726
  }
@@ -38643,6 +38852,16 @@ ${heal.removed.join("\n")}`,
38643
38852
  startInstaller(handoff) {
38644
38853
  const plan = buildInstallerSpawn({
38645
38854
  appPid: process.pid,
38855
+ /*
38856
+ * The path the spawner's identity check matches before it signals
38857
+ * anything: this process's own executable. `process.execPath` is
38858
+ * `/Applications/Local Operator.app/Contents/MacOS/Local Operator`
38859
+ * in the packaged app, and the running main process's command line
38860
+ * starts with exactly that path - which is the question
38861
+ * `ps -o command= -p <pid>` answers. It travels in the environment,
38862
+ * never in the script text (see the callee's own note).
38863
+ */
38864
+ appExecPath: process.execPath,
38646
38865
  shipItPath: handoff.shipItPath,
38647
38866
  label: handoff.label,
38648
38867
  statePath: handoff.statePath,
@@ -38728,6 +38947,146 @@ ${heal.removed.join("\n")}`,
38728
38947
  }
38729
38948
  }
38730
38949
  }
38950
+ /**
38951
+ * The updater's own cache directory for this app, or null when it cannot be
38952
+ * resolved.
38953
+ *
38954
+ * WHY THE APP NEEDS THIS PATH AT ALL (2026-10-11 cache hygiene): nothing ever
38955
+ * clears `~/Library/Caches/<updater cache dir>/` - measured residue after one
38956
+ * successful install: `update.zip` (~180 MB), `pending/<artifact>.zip` (~180
38957
+ * MB, the SAME bytes) and `pending/update-info.json`, all three left behind by
38958
+ * a download that has already been used or replaced. electron-updater clears
38959
+ * `pending/` on a failed DOWNLOAD and never clears `update.zip` - by design,
38960
+ * because `update.zip` is the differential base its next download patches
38961
+ * against (`MacUpdater`'s `canDifferentialDownload`), so deleting it buys disk
38962
+ * at the cost of a full ~180 MB re-download. `reapUpdaterCache` below is the
38963
+ * bounded-retention answer; this resolver is how it finds the directory.
38964
+ *
38965
+ * TWO SOURCES, in order. The download helper is authoritative for a download
38966
+ * THIS run performed (the same private surface `ensureStagedArtifactVerified`
38967
+ * already reads). It does not survive a restart, and the reap runs at
38968
+ * start-up, so the fallback reads the name electron-updater itself would
38969
+ * read: `updaterCacheDirName` from `app-update.yml` beside the packaged app,
38970
+ * under the base cache path its own adapter computes (`~/Library/Caches` on
38971
+ * macOS). ONE key on ONE line is parsed rather than adding a YAML dependency
38972
+ * on a package that is a transitive dependency of the updater rather than
38973
+ * ours.
38974
+ *
38975
+ * A DELETION ROOT IS NEVER TAKEN FROM THE MARKER or any other mutable record:
38976
+ * a corrupted record would then choose what gets deleted. Null means
38977
+ * "declined to reap", never a guess.
38978
+ */
38979
+ updaterCacheRoot() {
38980
+ const helper = this.downloadHelper();
38981
+ if (helper?.cacheDirForPendingUpdate) {
38982
+ return path$1.dirname(helper.cacheDirForPendingUpdate);
38983
+ }
38984
+ try {
38985
+ const config = fs.readFileSync(
38986
+ path$1.join(process.resourcesPath, "app-update.yml"),
38987
+ "utf8"
38988
+ );
38989
+ const name = config.match(APP_UPDATE_CACHE_DIR_NAME_REGEX)?.[1];
38990
+ if (!name || !CACHE_DIR_NAME_OK_REGEX.test(name)) return null;
38991
+ return path$1.join(electron.app.getPath("home"), "Library", "Caches", name);
38992
+ } catch {
38993
+ return null;
38994
+ }
38995
+ }
38996
+ /**
38997
+ * Reduce the updater's cache to at most ONE artifact's worth, once an install
38998
+ * is settled (2026-10-11).
38999
+ *
39000
+ * THE RETENTION RULE, and its reasoning. After every settled verdict the cache
39001
+ * is DEDUPED, not emptied: `update.zip` and `pending/<artifact>.zip` are the
39002
+ * same bytes, and only one of them has future value - `update.zip`, the
39003
+ * differential base the next download patches against (`MacUpdater` copies
39004
+ * every download to it, and falls back to a FULL download without it). So:
39005
+ * when `update.zip` exists, the pending artifact and the `update-info.json`
39006
+ * that describes it go (the bytes survive in the base), and when it does not,
39007
+ * nothing is deleted - there is nothing to dedupe, and the pending artifact is
39008
+ * the only copy. The retention window is bounded by the next download, which
39009
+ * overwrites the base in place; there is deliberately NO day-count constant,
39010
+ * because a clock cannot tell a live delta base from a dead one and would
39011
+ * either delete the base the next update needs or count forever on an idle
39012
+ * machine. ROLLBACK STORY: nothing here is a rollback artifact - `update.zip`
39013
+ * cannot be installed by itself, and the app's reinstall and recovery paths
39014
+ * re-fetch from the feed; the retained copy exists for the next update's
39015
+ * DELTA (worth ~180 MB of transfer), not for restoring anything older.
39016
+ *
39017
+ * SAFETY RAILS, re-asked at the point of deletion rather than trusted from the
39018
+ * caller: the three branches that call this have already decided the install
39019
+ * is not in flight, but the machine is asked ONCE more - a live marker, a
39020
+ * running installer, or a relaunch watchdog that is still OURS all mean
39021
+ * something else may still be reading this cache, and the reap stands down
39022
+ * with a log line. A registered-but-idle ShipIt job is NOT one of those
39023
+ * signals (the 0.17.0 lessons: the job outlives finished installs by design),
39024
+ * and the in-flight branch above NEVER calls here.
39025
+ */
39026
+ reapUpdaterCache() {
39027
+ const note = (message) => logger.info(message, LogFileType.UPDATE_SERVICE);
39028
+ const marker = readPendingInstallMarker(this.markerDir());
39029
+ const liveness = this.installLiveness(marker);
39030
+ if (liveness.installerRunning || marker !== null && isInstallInFlight({
39031
+ marker,
39032
+ jobState: liveness.jobState,
39033
+ installerRunning: liveness.installerRunning
39034
+ })) {
39035
+ note(
39036
+ "Not reaping the updater cache: the machine still reports an install in flight."
39037
+ );
39038
+ return;
39039
+ }
39040
+ const watchdogPid = marker?.watchdogPid ?? null;
39041
+ if (watchdogPid != null) {
39042
+ const commandLine = readCommandOutput("/bin/ps", [
39043
+ "-o",
39044
+ "command=",
39045
+ "-p",
39046
+ String(watchdogPid)
39047
+ ]);
39048
+ if (watchdogIsOurs({
39049
+ alive: commandLine != null,
39050
+ commandLine,
39051
+ installSucceeded: true
39052
+ })) {
39053
+ note(
39054
+ `Not reaping the updater cache while relaunch watchdog ${watchdogPid} is still running.`
39055
+ );
39056
+ return;
39057
+ }
39058
+ }
39059
+ const root = this.updaterCacheRoot();
39060
+ if (!root) {
39061
+ note("Updater cache not reaped: its directory could not be resolved.");
39062
+ return;
39063
+ }
39064
+ const base = path$1.join(root, "update.zip");
39065
+ if (!fs.existsSync(base)) {
39066
+ note(
39067
+ "Updater cache left alone: no differential base to dedupe the pending artifact against."
39068
+ );
39069
+ return;
39070
+ }
39071
+ const pendingDir = path$1.join(root, "pending");
39072
+ if (!fs.existsSync(pendingDir)) return;
39073
+ for (const entry of fs.readdirSync(pendingDir)) {
39074
+ if (!UPDATER_CACHE_PENDING_FILE_REGEX.test(entry) && entry !== "update-info.json")
39075
+ continue;
39076
+ const target2 = path$1.join(pendingDir, entry);
39077
+ try {
39078
+ fs.rmSync(target2, { force: true });
39079
+ note(
39080
+ `Reaped the updater cache's duplicate of the differential base: ${target2}.`
39081
+ );
39082
+ } catch (error) {
39083
+ logger.warn(
39084
+ `Could not reap ${target2}: ${String(error)}`,
39085
+ LogFileType.UPDATE_SERVICE
39086
+ );
39087
+ }
39088
+ }
39089
+ }
38731
39090
  /**
38732
39091
  * Both of the machine's liveness answers for this marker.
38733
39092
  *
@@ -43859,6 +44218,7 @@ const backendInstaller = new BackendInstaller({
43859
44218
  // (`./relaunch-pending` owns why scheduling happens only at the terminal).
43860
44219
  onQuitCancelled: () => {
43861
44220
  quitState.cancel();
44221
+ quitExitDeadline.release();
43862
44222
  relaunchPending.clear();
43863
44223
  }
43864
44224
  });
@@ -44178,6 +44538,22 @@ electron.app.whenReady().then(async () => {
44178
44538
  process.on(signal, () => endHeadlessRun(`received ${signal}`));
44179
44539
  }
44180
44540
  }
44541
+ if (windowLaunch.mode !== "headless") {
44542
+ const onSigtermDuringQuit = () => {
44543
+ if (!quitState.isQuitting()) {
44544
+ process.removeListener("SIGTERM", onSigtermDuringQuit);
44545
+ process.kill(process.pid, "SIGTERM");
44546
+ return;
44547
+ }
44548
+ logger.info(
44549
+ "Received SIGTERM during a quit; exiting so the quit reaches its terminal (an update installer may be waiting on this pid).",
44550
+ LogFileType.BACKEND
44551
+ );
44552
+ scheduleReopenAtQuitTerminal();
44553
+ electron.app.exit(0);
44554
+ };
44555
+ process.on("SIGTERM", onSigtermDuringQuit);
44556
+ }
44181
44557
  electron.app.on("browser-window-created", (_, window) => {
44182
44558
  utils.optimizer.watchWindowShortcuts(window);
44183
44559
  });
@@ -45184,7 +45560,22 @@ const scheduleReopenAtQuitTerminal = () => {
45184
45560
  }
45185
45561
  });
45186
45562
  };
45563
+ const QUIT_EXIT_DEADLINE_MS = quitExitDeadlineMs({
45564
+ quitCleanupFailsafeMs: QUIT_CLEANUP_FAILSAFE_MS
45565
+ });
45566
+ const quitExitDeadline = createQuitExitDeadline({
45567
+ timeoutMs: QUIT_EXIT_DEADLINE_MS,
45568
+ onFire: (firedInStage) => {
45569
+ logger.error(
45570
+ `The quit did not finish within ${QUIT_EXIT_DEADLINE_MS} ms (stalled ${firedInStage}); exiting with failure so the process cannot sit alive with no window`,
45571
+ LogFileType.BACKEND
45572
+ );
45573
+ scheduleReopenAtQuitTerminal();
45574
+ electron.app.exit(1);
45575
+ }
45576
+ });
45187
45577
  electron.app.on("will-quit", (event) => {
45578
+ quitExitDeadline.phase("will-quit");
45188
45579
  viewerEndpoint?.close();
45189
45580
  viewerRecord?.stop();
45190
45581
  scheduleReopenAtQuitTerminal();
@@ -45224,6 +45615,7 @@ const holdQuitForSessionCookieSnapshot = createSessionCookieQuitHold({
45224
45615
  });
45225
45616
  electron.app.on("before-quit", async (event) => {
45226
45617
  quitState.begin();
45618
+ quitExitDeadline.arm("before the session-cookie hold");
45227
45619
  electron.globalShortcut.unregisterAll();
45228
45620
  miniViewRegistrar?.dispose();
45229
45621
  quickSendWatcher?.stop();
@@ -45233,6 +45625,7 @@ electron.app.on("before-quit", async (event) => {
45233
45625
  armHeadlessExitDeadline("the app is quitting");
45234
45626
  }
45235
45627
  if (await holdQuitForSessionCookieSnapshot(event)) return;
45628
+ quitExitDeadline.phase("after the session-cookie hold");
45236
45629
  logger.info("App is about to quit", LogFileType.BACKEND);
45237
45630
  if (!backendService.isOwnedCleanupComplete()) {
45238
45631
  try {
@@ -45253,6 +45646,7 @@ electron.app.on("before-quit", async (event) => {
45253
45646
  }
45254
45647
  activeUpdateService?.quitForInFlightInstall("app quit");
45255
45648
  void stopBrowserHost();
45649
+ quitExitDeadline.phase("awaiting the window close");
45256
45650
  });
45257
45651
  process.on("exit", () => {
45258
45652
  try {
@@ -2113,6 +2113,26 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2113
2113
  */
2114
2114
  keys: zod.z.array(zod.z.string().min(1).max(512)).max(256).optional(),
2115
2115
  force: zod.z.boolean().optional()
2116
+ }).strict(),
2117
+ /*
2118
+ * THE PREVIEWS' SIGNED STATIC URLS (file-serving RFC § 4, Phase A adoption).
2119
+ * The renderer cannot read the core's serve record (no filesystem, no record
2120
+ * store), so the previews ask MAIN - which already holds the desktop bearer -
2121
+ * to mint a short-lived signed URL for one static route + path. The route is
2122
+ * public in Phase A; this op is what lets the previews keep working when a
2123
+ * later core phase gates it, and a core that predates the route answers 404,
2124
+ * which the previews read as their fallback signal, not an error.
2125
+ *
2126
+ * `route` is the backend's own signed-string vocabulary (the four static
2127
+ * family ids), held here so a route the signature cannot cover fails at this
2128
+ * boundary. `ttlS` stays within the backend's documented cap (600 default,
2129
+ * 3600 max) - a bound, not a preference.
2130
+ */
2131
+ zod.z.object({
2132
+ op: zod.z.literal("static.sign"),
2133
+ route: zod.z.enum(["images", "videos", "audio", "html"]),
2134
+ path: zod.z.string().min(1),
2135
+ ttlS: zod.z.number().int().min(1).max(3600).optional()
2116
2136
  }).strict()
2117
2137
  ]);
2118
2138
  desktopRequestUnion.superRefine(
@@ -1 +1 @@
1
- import{e as o,c as b,g as v,k as O,h as P,j as p,l as w,m as A,n as x,t as c,o as N}from"./_baseUniq-DF-R-zk_.js";import{as as g,aa as y,at as E,au as F,av as M,aw as I,ax as _,ay as $,az as B,aA as T}from"./mermaid.core-DUwwjyuA.js";var S=/\s/;function z(n){for(var r=n.length;r--&&S.test(n.charAt(r)););return r}var G=/^\s+/;function H(n){return n&&n.slice(0,z(n)+1).replace(G,"")}var m=NaN,L=/^[-+]0x[0-9a-f]+$/i,R=/^0b[01]+$/i,q=/^0o[0-7]+$/i,C=parseInt;function K(n){if(typeof n=="number")return n;if(o(n))return m;if(g(n)){var r=typeof n.valueOf=="function"?n.valueOf():n;n=g(r)?r+"":r}if(typeof n!="string")return n===0?n:+n;n=H(n);var t=R.test(n);return t||q.test(n)?C(n.slice(2),t?2:8):L.test(n)?m:+n}var W=1/0,X=17976931348623157e292;function Y(n){if(!n)return n===0?n:0;if(n=K(n),n===W||n===-1/0){var r=n<0?-1:1;return r*X}return n===n?n:0}function D(n){var r=Y(n),t=r%1;return r===r?t?r-t:r:0}function fn(n){var r=n==null?0:n.length;return r?b(n):[]}var l=Object.prototype,J=l.hasOwnProperty,dn=y(function(n,r){n=Object(n);var t=-1,e=r.length,a=e>2?r[2]:void 0;for(a&&E(r[0],r[1],a)&&(e=1);++t<e;)for(var f=r[t],i=F(f),s=-1,d=i.length;++s<d;){var u=i[s],h=n[u];(h===void 0||M(h,l[u])&&!J.call(n,u))&&(n[u]=f[u])}return n});function un(n){var r=n==null?0:n.length;return r?n[r-1]:void 0}function Q(n){return function(r,t,e){var a=Object(r);if(!I(r)){var f=v(t);r=O(r),t=function(s){return f(a[s],s,a)}}var i=n(r,t,e);return i>-1?a[f?r[i]:i]:void 0}}var U=Math.max;function Z(n,r,t){var e=n==null?0:n.length;if(!e)return-1;var a=t==null?0:D(t);return a<0&&(a=U(e+a,0)),P(n,v(r),a)}var hn=Q(Z);function V(n,r){var t=-1,e=I(n)?Array(n.length):[];return p(n,function(a,f,i){e[++t]=r(a,f,i)}),e}function gn(n,r){var t=_(n)?w:V;return t(n,v(r))}var j=Object.prototype,k=j.hasOwnProperty;function nn(n,r){return n!=null&&k.call(n,r)}function vn(n,r){return n!=null&&A(n,r,nn)}function rn(n,r){return n<r}function tn(n,r,t){for(var e=-1,a=n.length;++e<a;){var f=n[e],i=r(f);if(i!=null&&(s===void 0?i===i&&!o(i):t(i,s)))var s=i,d=f}return d}function mn(n){return n&&n.length?tn(n,$,rn):void 0}function an(n,r,t,e){if(!g(n))return n;r=x(r,n);for(var a=-1,f=r.length,i=f-1,s=n;s!=null&&++a<f;){var d=c(r[a]),u=t;if(d==="__proto__"||d==="constructor"||d==="prototype")return n;if(a!=i){var h=s[d];u=void 0,u===void 0&&(u=g(h)?h:B(r[a+1])?[]:{})}T(s,d,u),s=s[d]}return n}function on(n,r,t){for(var e=-1,a=r.length,f={};++e<a;){var i=r[e],s=N(n,i);t(s,i)&&an(f,x(i,n),s)}return f}export{rn as a,tn as b,V as c,on as d,mn as e,fn as f,hn as g,vn as h,dn as i,D as j,un as l,gn as m,Y as t};
1
+ import{e as o,c as b,g as v,k as O,h as P,j as p,l as w,m as A,n as x,t as c,o as N}from"./_baseUniq-DKeCGkCd.js";import{as as g,aa as y,at as E,au as F,av as M,aw as I,ax as _,ay as $,az as B,aA as T}from"./mermaid.core-DNS50-NS.js";var S=/\s/;function z(n){for(var r=n.length;r--&&S.test(n.charAt(r)););return r}var G=/^\s+/;function H(n){return n&&n.slice(0,z(n)+1).replace(G,"")}var m=NaN,L=/^[-+]0x[0-9a-f]+$/i,R=/^0b[01]+$/i,q=/^0o[0-7]+$/i,C=parseInt;function K(n){if(typeof n=="number")return n;if(o(n))return m;if(g(n)){var r=typeof n.valueOf=="function"?n.valueOf():n;n=g(r)?r+"":r}if(typeof n!="string")return n===0?n:+n;n=H(n);var t=R.test(n);return t||q.test(n)?C(n.slice(2),t?2:8):L.test(n)?m:+n}var W=1/0,X=17976931348623157e292;function Y(n){if(!n)return n===0?n:0;if(n=K(n),n===W||n===-1/0){var r=n<0?-1:1;return r*X}return n===n?n:0}function D(n){var r=Y(n),t=r%1;return r===r?t?r-t:r:0}function fn(n){var r=n==null?0:n.length;return r?b(n):[]}var l=Object.prototype,J=l.hasOwnProperty,dn=y(function(n,r){n=Object(n);var t=-1,e=r.length,a=e>2?r[2]:void 0;for(a&&E(r[0],r[1],a)&&(e=1);++t<e;)for(var f=r[t],i=F(f),s=-1,d=i.length;++s<d;){var u=i[s],h=n[u];(h===void 0||M(h,l[u])&&!J.call(n,u))&&(n[u]=f[u])}return n});function un(n){var r=n==null?0:n.length;return r?n[r-1]:void 0}function Q(n){return function(r,t,e){var a=Object(r);if(!I(r)){var f=v(t);r=O(r),t=function(s){return f(a[s],s,a)}}var i=n(r,t,e);return i>-1?a[f?r[i]:i]:void 0}}var U=Math.max;function Z(n,r,t){var e=n==null?0:n.length;if(!e)return-1;var a=t==null?0:D(t);return a<0&&(a=U(e+a,0)),P(n,v(r),a)}var hn=Q(Z);function V(n,r){var t=-1,e=I(n)?Array(n.length):[];return p(n,function(a,f,i){e[++t]=r(a,f,i)}),e}function gn(n,r){var t=_(n)?w:V;return t(n,v(r))}var j=Object.prototype,k=j.hasOwnProperty;function nn(n,r){return n!=null&&k.call(n,r)}function vn(n,r){return n!=null&&A(n,r,nn)}function rn(n,r){return n<r}function tn(n,r,t){for(var e=-1,a=n.length;++e<a;){var f=n[e],i=r(f);if(i!=null&&(s===void 0?i===i&&!o(i):t(i,s)))var s=i,d=f}return d}function mn(n){return n&&n.length?tn(n,$,rn):void 0}function an(n,r,t,e){if(!g(n))return n;r=x(r,n);for(var a=-1,f=r.length,i=f-1,s=n;s!=null&&++a<f;){var d=c(r[a]),u=t;if(d==="__proto__"||d==="constructor"||d==="prototype")return n;if(a!=i){var h=s[d];u=void 0,u===void 0&&(u=g(h)?h:B(r[a+1])?[]:{})}T(s,d,u),s=s[d]}return n}function on(n,r,t){for(var e=-1,a=r.length,f={};++e<a;){var i=r[e],s=N(n,i);t(s,i)&&an(f,x(i,n),s)}return f}export{rn as a,tn as b,V as c,on as d,mn as e,fn as f,hn as g,vn as h,dn as i,D as j,un as l,gn as m,Y as t};