local-operator-ui 0.38.1 → 0.39.0

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 (95) hide show
  1. package/out/main/index.js +1014 -58
  2. package/out/preload/index.js +36 -1
  3. package/out/renderer/assets/{_basePickBy-DhcDqJuW.js → _basePickBy-CBn_dsaM.js} +1 -1
  4. package/out/renderer/assets/{_baseUniq-DlAVpNmp.js → _baseUniq-B-kmAdKj.js} +1 -1
  5. package/out/renderer/assets/{agent-details-page-A51rffCS.js → agent-details-page-CjksC_ZM.js} +2 -2
  6. package/out/renderer/assets/{agent-hub-page-DQ-tnD26.js → agent-hub-page-D3y5dujt.js} +2 -2
  7. package/out/renderer/assets/{agents-page-Bh6SGDaA.js → agents-page-vmm4VKcI.js} +3 -3
  8. package/out/renderer/assets/{arc-C-BSLMbh.js → arc-BSYPx6kR.js} +1 -1
  9. package/out/renderer/assets/{architectureDiagram-IEHRJDOE-nDfnCWAM.js → architectureDiagram-IEHRJDOE-C-dAuUYf.js} +1 -1
  10. package/out/renderer/assets/{arrow-up-JQ86w8h2.js → arrow-up-BaHSg-fV.js} +1 -1
  11. package/out/renderer/assets/{blockDiagram-JOT3LUYC-BJgd2uGT.js → blockDiagram-JOT3LUYC-Dw9X_Asu.js} +1 -1
  12. package/out/renderer/assets/{book-open-yjstLkVS.js → book-open-CwoTuMOa.js} +1 -1
  13. package/out/renderer/assets/browser-page-DmYAxbWu.js +1 -0
  14. package/out/renderer/assets/{browser-webauthn-prompt-CdHXLdwX.js → browser-webauthn-prompt-CFEuJXkX.js} +1 -1
  15. package/out/renderer/assets/{building-2-Cupv31tS.js → building-2-D06wTZQj.js} +1 -1
  16. package/out/renderer/assets/{c4Diagram-VJAJSXHY-lIXnBLZ5.js → c4Diagram-VJAJSXHY-Bz93LlZc.js} +1 -1
  17. package/out/renderer/assets/channel-BJdem-Qj.js +1 -0
  18. package/out/renderer/assets/{chunk-4BMEZGHF-DF2ktHZp.js → chunk-4BMEZGHF-H3mECOID.js} +1 -1
  19. package/out/renderer/assets/{chunk-A2AXSNBT-CNRON9Qy.js → chunk-A2AXSNBT-BNJGDJK2.js} +1 -1
  20. package/out/renderer/assets/{chunk-AEK57VVT-BGXI1SR5.js → chunk-AEK57VVT-Baj26p0I.js} +1 -1
  21. package/out/renderer/assets/{chunk-D6G4REZN-CW_SyuGg.js → chunk-D6G4REZN-B5inAuRK.js} +1 -1
  22. package/out/renderer/assets/{chunk-RZ5BOZE2-gU0oYsA6.js → chunk-RZ5BOZE2-BK_F-zoT.js} +1 -1
  23. package/out/renderer/assets/{chunk-XZIHB7SX-BrVtbfMc.js → chunk-XZIHB7SX-DipW3oXc.js} +1 -1
  24. package/out/renderer/assets/classDiagram-GIVACNV2-BQLeT9Qk.js +1 -0
  25. package/out/renderer/assets/classDiagram-v2-COTLJTTW-BQLeT9Qk.js +1 -0
  26. package/out/renderer/assets/clone-BaxJyMvd.js +1 -0
  27. package/out/renderer/assets/{console-mirror-CkCxHgcU.js → console-mirror-DB5yXAr9.js} +1 -1
  28. package/out/renderer/assets/{consoleCapture-EZYleEWx.js → consoleCapture-Bz69ju0Z.js} +1 -1
  29. package/out/renderer/assets/{conversation-input-sync-bgD4kyw3.js → conversation-input-sync-BVPZQjhD.js} +183 -183
  30. package/out/renderer/assets/{dagre-OKDRZEBW-BDR0956-.js → dagre-OKDRZEBW-3ECMKEeo.js} +1 -1
  31. package/out/renderer/assets/{diagram-SSKATNLV-DbCZDtm7.js → diagram-SSKATNLV-CmAf5Fvk.js} +1 -1
  32. package/out/renderer/assets/{diagram-VNBRO52H-BpXb_OjM.js → diagram-VNBRO52H-D_21NrT-.js} +1 -1
  33. package/out/renderer/assets/{erDiagram-Q7BY3M3F-CZukR1Y4.js → erDiagram-Q7BY3M3F-CaUQ9PtP.js} +1 -1
  34. package/out/renderer/assets/{error-boundary-DJAF_aYL.js → error-boundary-h9802RBt.js} +1 -1
  35. package/out/renderer/assets/{flowDiagram-4HSFHLVR-CqKOnXAd.js → flowDiagram-4HSFHLVR-CVLxJB7Y.js} +1 -1
  36. package/out/renderer/assets/{ganttDiagram-APWFNJXF-B9I0smi4.js → ganttDiagram-APWFNJXF-Dt6KPnJQ.js} +1 -1
  37. package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-Bj6-u-5w.js → gitGraphDiagram-7IBYFJ6S-D1BdvS2j.js} +1 -1
  38. package/out/renderer/assets/{graph-BsgoQZc2.js → graph-wsNGWWCD.js} +1 -1
  39. package/out/renderer/assets/{hash-BLfEUuGg.js → hash-C32vAdag.js} +1 -1
  40. package/out/renderer/assets/index-3RPijdn_.css +1 -0
  41. package/out/renderer/assets/{index-lMi7GI2V.js → index-6JB-jSFn.js} +1 -1
  42. package/out/renderer/assets/index-COgOH-4N.js +57 -0
  43. package/out/renderer/assets/index-CiOOz1tp.js +825 -0
  44. package/out/renderer/assets/{index-D7pJoOu_.js → index-CvofVM43.js} +1 -1
  45. package/out/renderer/assets/{infoDiagram-PH2N3AL5-DQ3aMjor.js → infoDiagram-PH2N3AL5-CWPf3FZn.js} +1 -1
  46. package/out/renderer/assets/{installer-Ch3nb3kq.js → installer-DKAnScPb.js} +1 -1
  47. package/out/renderer/assets/{journeyDiagram-U35MCT3I-B_RccO_x.js → journeyDiagram-U35MCT3I-B5eLtG46.js} +1 -1
  48. package/out/renderer/assets/{kanban-definition-NDS4AKOZ-BvVJZaiy.js → kanban-definition-NDS4AKOZ-BtJFd9zq.js} +1 -1
  49. package/out/renderer/assets/{layout-DCACUDHF.js → layout-B3W_M4xE.js} +1 -1
  50. package/out/renderer/assets/{legacy-agents-page-ccL-99ea.js → legacy-agents-page-aqbs_qcV.js} +4 -4
  51. package/out/renderer/assets/{library-page-C8ymyVUW.js → library-page-BIa8sD1w.js} +3 -3
  52. package/out/renderer/assets/{mermaid.core-BXcegHmP.js → mermaid.core-DzmjLSHb.js} +5 -5
  53. package/out/renderer/assets/{mesh-page-Dn77Ie1F.js → mesh-page-De8Abvyb.js} +1 -1
  54. package/out/renderer/assets/{mindmap-definition-ALO5MXBD-Bx_gU6ka.js → mindmap-definition-ALO5MXBD-C1aylJ0P.js} +1 -1
  55. package/out/renderer/assets/{mini-DRt4PdyG.js → mini-mPtvVJCT.js} +1 -1
  56. package/out/renderer/assets/{notebook-pen-CKr2WSrK.js → notebook-pen-CvyIerwZ.js} +1 -1
  57. package/out/renderer/assets/{org-access-CfGyU5hi.js → org-access-Cpt-vs-I.js} +1 -1
  58. package/out/renderer/assets/{org-surface-gate-C86b758Z.js → org-surface-gate-C8Gs3DNG.js} +1 -1
  59. package/out/renderer/assets/{page-header-CZcbRwLy.js → page-header-DBIgQcaM.js} +1 -1
  60. package/out/renderer/assets/{pieDiagram-IB7DONF6-jEzs31M9.js → pieDiagram-IB7DONF6-CjnobVYZ.js} +1 -1
  61. package/out/renderer/assets/{projects-page-xuLYnWBj.js → projects-page-041auzXW.js} +1 -1
  62. package/out/renderer/assets/{publication-validation-CCv7pQJH.js → publication-validation-JvAtW-AY.js} +1 -1
  63. package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-C07DLJe_.js → quadrantDiagram-7GDLP6J5-B0TLJJFL.js} +1 -1
  64. package/out/renderer/assets/{radar-MK3ICKWK-DFqDL3G4.js → radar-MK3ICKWK-D6MZmkB6.js} +1 -1
  65. package/out/renderer/assets/{radient-auth-buttons-Huoo_kFK.js → radient-auth-buttons-quggTTqK.js} +1 -1
  66. package/out/renderer/assets/{requirementDiagram-KVF5MWMF-DZVSGDrD.js → requirementDiagram-KVF5MWMF-BSAJQlo8.js} +1 -1
  67. package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-Efyu9UfS.js → sankeyDiagram-QLVOVGJD-CQqGLTr_.js} +1 -1
  68. package/out/renderer/assets/{schedules-page-vsfnEcLJ.js → schedules-page-B51F-ADQ.js} +1 -1
  69. package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-C5QQ4cH3.js → sequenceDiagram-X6HHIX6F-B0LPyEfC.js} +1 -1
  70. package/out/renderer/assets/{settings-page-CnBnFo-w.js → settings-page-BpTAK-RZ.js} +1 -1
  71. package/out/renderer/assets/{smartart-D5HiGUV-.js → smartart-B1Hg0uN6.js} +1 -1
  72. package/out/renderer/assets/{stateDiagram-DGXRK772-DlvSEVs4.js → stateDiagram-DGXRK772-hL4-Mzxx.js} +1 -1
  73. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-Bczp9bth.js +1 -0
  74. package/out/renderer/assets/{team-bridge-page-JRqkQ8jV.js → team-bridge-page-xhQelITo.js} +1 -1
  75. package/out/renderer/assets/{timeline-definition-BDJGKUSR-XgOjVv3O.js → timeline-definition-BDJGKUSR-BOE8E_XE.js} +1 -1
  76. package/out/renderer/assets/ui-preferences-store-Cws2cozv.js +1 -0
  77. package/out/renderer/assets/{use-download-agent-mutation-BZhcL_Dx.js → use-download-agent-mutation-HcVu2YgL.js} +1 -1
  78. package/out/renderer/assets/{use-session-snapshot-BiiULlsj.js → use-session-snapshot-CMQBHevf.js} +1 -1
  79. package/out/renderer/assets/{xychartDiagram-VJFVF3MP-B0CsPCbY.js → xychartDiagram-VJFVF3MP-D3cI5mnO.js} +1 -1
  80. package/out/renderer/browser-address-overlay.html +43 -0
  81. package/out/renderer/console-capture.html +5 -5
  82. package/out/renderer/index.html +7 -7
  83. package/out/renderer/installer.html +4 -4
  84. package/out/renderer/mini.html +7 -7
  85. package/package.json +2 -2
  86. package/out/renderer/assets/browser-page-Daga5nCP.js +0 -1
  87. package/out/renderer/assets/channel-BqEnrEwi.js +0 -1
  88. package/out/renderer/assets/classDiagram-GIVACNV2-DNUqXdeF.js +0 -1
  89. package/out/renderer/assets/classDiagram-v2-COTLJTTW-DNUqXdeF.js +0 -1
  90. package/out/renderer/assets/clone-_PvxPvQz.js +0 -1
  91. package/out/renderer/assets/index-BZYkm39z.js +0 -825
  92. package/out/renderer/assets/index-CL2MVLxd.css +0 -1
  93. package/out/renderer/assets/index-N0lyyVVo.js +0 -57
  94. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-CCLt0TcZ.js +0 -1
  95. package/out/renderer/assets/ui-preferences-store-C91RrpgH.js +0 -1
package/out/main/index.js CHANGED
@@ -190,6 +190,17 @@ zod.z.object({
190
190
  }).passthrough()
191
191
  }).passthrough()
192
192
  }).passthrough();
193
+ const SIDEBAR_DESTINATION_IDS = [
194
+ "aida",
195
+ "library",
196
+ "projects",
197
+ "agents",
198
+ "schedules",
199
+ "browser",
200
+ "team-bridge",
201
+ "agent-hub",
202
+ "mesh"
203
+ ];
193
204
  const JOURNAL_ORDER_QUERY_BYTES = 6 * 1024;
194
205
  const JOURNAL_ORDER_ID_LIMIT = 512;
195
206
  function appendJournalOrderIds(query, path2, ids) {
@@ -488,6 +499,11 @@ const PROJECTS_SEARCH_MAX_CHARS = 256;
488
499
  const PROJECTS_SEARCH_DEFAULT_LIMIT = 100;
489
500
  const PROJECTS_SEARCH_MAX_LIMIT = 200;
490
501
  const hubItemKind = zod.z.enum(["agent", "team", "skill"]);
502
+ const sidebarDestinationId = zod.z.enum(SIDEBAR_DESTINATION_IDS);
503
+ const sidebarLayoutSchema = zod.z.object({
504
+ visible: zod.z.array(sidebarDestinationId).max(SIDEBAR_DESTINATION_IDS.length),
505
+ more: zod.z.array(sidebarDestinationId).max(SIDEBAR_DESTINATION_IDS.length)
506
+ }).strict();
491
507
  const desktopRequestUnion = zod.z.discriminatedUnion("op", [
492
508
  zod.z.object({ op: zod.z.literal("capabilities") }).strict(),
493
509
  /*
@@ -2989,6 +3005,23 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2989
3005
  op: zod.z.literal("library.librarian"),
2990
3006
  /** `status` is the read's own op; the other four are the writes. */
2991
3007
  action: zod.z.enum(["status", "open", "pause", "resume", "run"]).optional()
3008
+ }).strict(),
3009
+ /*
3010
+ * THE SIDEBAR LAYOUT RESOURCE (design contract § 2, § 4). One read and one
3011
+ * write, mirroring the two HTTP verbs: the resource is a single document, and
3012
+ * a patch vocabulary over a nine-entry ordered list would have to invent
3013
+ * operations for moves the client already knows how to compute.
3014
+ *
3015
+ * The write carries the WHOLE layout rather than a delta because the route
3016
+ * normalises and persists a complete document (last writer wins, atomic file
3017
+ * replace). Sending the full list is also what makes an optimistic write
3018
+ * self-describing on the retry path: the body a retry replays is the layout
3019
+ * the user saw, not a move that could be applied twice.
3020
+ */
3021
+ zod.z.object({ op: zod.z.literal("sidebar_layout.get") }).strict(),
3022
+ zod.z.object({
3023
+ op: zod.z.literal("sidebar_layout.set"),
3024
+ layout: sidebarLayoutSchema
2992
3025
  }).strict()
2993
3026
  ]);
2994
3027
  const desktopRequestSchema = desktopRequestUnion.superRefine(
@@ -5387,6 +5420,22 @@ function desktopEndpoint(request) {
5387
5420
  ttl_s: request.ttlS
5388
5421
  }
5389
5422
  };
5423
+ /*
5424
+ * The sidebar customisation resource (design contract § 4). A GET/PUT pair
5425
+ * on one route, with the layout in an envelope rather than as the bare body:
5426
+ * the route answers `{layout}` and accepts `{layout}`, so a future field
5427
+ * beside it is additive instead of a breaking shape change. The PUT sends
5428
+ * the stored ids verbatim - the client owns the order, the route owns
5429
+ * validation and the default fill - so nothing is re-sorted in transit.
5430
+ */
5431
+ case "sidebar_layout.get":
5432
+ return { path: "/v1/desktop/sidebar-layout", method: "GET" };
5433
+ case "sidebar_layout.set":
5434
+ return {
5435
+ path: "/v1/desktop/sidebar-layout",
5436
+ method: "PUT",
5437
+ body: { layout: request.layout }
5438
+ };
5390
5439
  }
5391
5440
  }
5392
5441
  const MAX_PROBE_PATHS = 64;
@@ -28714,6 +28763,661 @@ function labelOf(account) {
28714
28763
  if (!account) return "an unnamed passkey";
28715
28764
  return account.displayName || account.name || "an unnamed passkey";
28716
28765
  }
28766
+ const ADDRESS_OVERLAY_S1_ENV = "LOCAL_OPERATOR_UI_BROWSER_ADDRESS_OVERLAY_S1";
28767
+ const ADDRESS_OVERLAY_DOCUMENT = "browser-address-overlay.html";
28768
+ const ADDRESS_OVERLAY_MAX_HEIGHT_DIP = 160;
28769
+ const ADDRESS_OVERLAY_READY_TIMEOUT_MS = 5e3;
28770
+ const DIP_INT32_MAX = 2 ** 31 - 1;
28771
+ const INDEX_DOCUMENT_SUFFIX$2 = /\/?index\.html(\?.*)?$/;
28772
+ const TRAILING_SLASH$1 = /\/$/;
28773
+ function addressOverlayDocumentUrlFor(rendererUrl) {
28774
+ return INDEX_DOCUMENT_SUFFIX$2.test(rendererUrl) ? rendererUrl.replace(INDEX_DOCUMENT_SUFFIX$2, `/${ADDRESS_OVERLAY_DOCUMENT}`) : `${rendererUrl.replace(TRAILING_SLASH$1, "")}/${ADDRESS_OVERLAY_DOCUMENT}`;
28775
+ }
28776
+ function resolveAddressOverlayGate(input) {
28777
+ const raw = input.env[ADDRESS_OVERLAY_S1_ENV];
28778
+ if (raw === void 0 || raw.trim() === "") {
28779
+ return { asked: false, enabled: false, reason: null };
28780
+ }
28781
+ const asked = true;
28782
+ if (raw.trim() !== "1") {
28783
+ return {
28784
+ asked,
28785
+ enabled: false,
28786
+ reason: `${ADDRESS_OVERLAY_S1_ENV}=${raw.trim()} is not an opt-in (accepted: 1); the address overlay stayed off`
28787
+ };
28788
+ }
28789
+ if (!input.devDriverArmed) {
28790
+ return {
28791
+ asked,
28792
+ enabled: false,
28793
+ reason: "the address overlay needs the armed renderer dev driver; it has no user-facing trigger in S1"
28794
+ };
28795
+ }
28796
+ if (input.windowMode !== "headless") {
28797
+ return {
28798
+ asked,
28799
+ enabled: false,
28800
+ reason: `the address overlay refused to arm in a "${input.windowMode}" window; S1 has no user-facing path, so use --window-mode=headless`
28801
+ };
28802
+ }
28803
+ return { asked, enabled: true, reason: null };
28804
+ }
28805
+ function int32(value) {
28806
+ if (typeof value !== "number" || !Number.isFinite(value)) return null;
28807
+ const rounded = Math.round(value);
28808
+ return Math.abs(rounded) > DIP_INT32_MAX ? null : rounded;
28809
+ }
28810
+ function overlayBoundsFor(contentRect, owner) {
28811
+ if (contentRect === null) return null;
28812
+ const x = int32(contentRect.x);
28813
+ const y = int32(contentRect.y);
28814
+ const width = int32(contentRect.width);
28815
+ const height = int32(contentRect.height);
28816
+ const ownerWidth = int32(owner.width);
28817
+ const ownerHeight = int32(owner.height);
28818
+ if (x === null || y === null || width === null || height === null || ownerWidth === null || ownerHeight === null)
28819
+ return null;
28820
+ if (width <= 0 || height <= 0 || ownerWidth <= 0 || ownerHeight <= 0) {
28821
+ return null;
28822
+ }
28823
+ const left = Math.max(0, x);
28824
+ const top = Math.max(0, y);
28825
+ const right = Math.min(ownerWidth, x + width);
28826
+ const bottom = Math.min(
28827
+ ownerHeight,
28828
+ y + Math.min(height, ADDRESS_OVERLAY_MAX_HEIGHT_DIP)
28829
+ );
28830
+ if (right <= left || bottom <= top) return null;
28831
+ return { x: left, y: top, width: right - left, height: bottom - top };
28832
+ }
28833
+ function copyLayout(snapshot2) {
28834
+ return {
28835
+ activeTabId: snapshot2.activeTabId,
28836
+ presented: snapshot2.presented,
28837
+ contentRect: snapshot2.contentRect ? {
28838
+ x: snapshot2.contentRect.x,
28839
+ y: snapshot2.contentRect.y,
28840
+ width: snapshot2.contentRect.width,
28841
+ height: snapshot2.contentRect.height
28842
+ } : null,
28843
+ revision: snapshot2.revision
28844
+ };
28845
+ }
28846
+ function layoutKeyOf(snapshot2) {
28847
+ const rect = snapshot2.contentRect;
28848
+ return `${snapshot2.activeTabId}:${snapshot2.presented ? 1 : 0}:${rect ? `${rect.x},${rect.y},${rect.width},${rect.height}` : "null"}`;
28849
+ }
28850
+ const OVERLAY_BACKGROUND = "#1b1f24";
28851
+ function createHardenedView() {
28852
+ const partition = `address-overlay-${node_crypto.randomUUID()}`;
28853
+ const childSession = electron.session.fromPartition(partition);
28854
+ childSession.setPermissionRequestHandler(
28855
+ (_contents, _permission, callback) => {
28856
+ callback(false);
28857
+ }
28858
+ );
28859
+ childSession.setPermissionCheckHandler(() => false);
28860
+ childSession.on("will-download", (event) => {
28861
+ event.preventDefault();
28862
+ });
28863
+ const view = new electron.WebContentsView({
28864
+ webPreferences: {
28865
+ partition,
28866
+ sandbox: true,
28867
+ contextIsolation: true,
28868
+ nodeIntegration: false,
28869
+ webSecurity: true,
28870
+ allowRunningInsecureContent: false,
28871
+ // No `preload`, and no script in the document: nothing can ask for a
28872
+ // bridge, and the renderer never runs JavaScript even if the document
28873
+ // changes by accident.
28874
+ javascript: false
28875
+ }
28876
+ });
28877
+ view.webContents.setWindowOpenHandler(() => ({ action: "deny" }));
28878
+ view.setBackgroundColor(OVERLAY_BACKGROUND);
28879
+ return view;
28880
+ }
28881
+ class AddressOverlayController {
28882
+ window;
28883
+ documentUrl;
28884
+ createView;
28885
+ readinessTimeoutMs;
28886
+ log;
28887
+ now;
28888
+ appMetrics;
28889
+ view;
28890
+ childWebContentsId;
28891
+ state;
28892
+ failedReason;
28893
+ hiddenReason;
28894
+ generation;
28895
+ childCreatedCount;
28896
+ shownCount;
28897
+ lastShow;
28898
+ layout;
28899
+ layoutKey;
28900
+ boundTabId;
28901
+ domReady;
28902
+ finished;
28903
+ loadStartedAt;
28904
+ loadMs;
28905
+ readyWaiter;
28906
+ readinessTimer;
28907
+ showInFlight;
28908
+ disposingChild;
28909
+ disposed;
28910
+ ownerListeners;
28911
+ childListeners;
28912
+ constructor(deps) {
28913
+ this.window = deps.window;
28914
+ this.documentUrl = deps.documentUrl;
28915
+ this.createView = deps.createView ?? createHardenedView;
28916
+ this.readinessTimeoutMs = deps.readinessTimeoutMs ?? ADDRESS_OVERLAY_READY_TIMEOUT_MS;
28917
+ this.log = deps.log ?? (() => {
28918
+ });
28919
+ this.now = deps.now ?? (() => Date.now());
28920
+ this.appMetrics = deps.appMetrics ?? null;
28921
+ this.view = null;
28922
+ this.childWebContentsId = null;
28923
+ this.state = "absent";
28924
+ this.failedReason = null;
28925
+ this.hiddenReason = null;
28926
+ this.generation = 0;
28927
+ this.childCreatedCount = 0;
28928
+ this.shownCount = 0;
28929
+ this.lastShow = null;
28930
+ this.layout = {
28931
+ activeTabId: null,
28932
+ presented: false,
28933
+ contentRect: null,
28934
+ revision: 0
28935
+ };
28936
+ this.layoutKey = "none";
28937
+ this.boundTabId = null;
28938
+ this.domReady = false;
28939
+ this.finished = false;
28940
+ this.loadStartedAt = null;
28941
+ this.loadMs = null;
28942
+ this.readyWaiter = null;
28943
+ this.readinessTimer = null;
28944
+ this.showInFlight = null;
28945
+ this.disposingChild = false;
28946
+ this.disposed = false;
28947
+ this.ownerListeners = [];
28948
+ this.childListeners = [];
28949
+ this.attachOwnerListeners();
28950
+ }
28951
+ // ---- observer hooks ------------------------------------------------------
28952
+ /**
28953
+ * The registry's post-layout hook. Called after every page layout pass,
28954
+ * including null and suppressed ones.
28955
+ *
28956
+ * A changed key (tab, presentation or rectangle) hides and invalidates first:
28957
+ * a moved page must never keep a stale rectangle floating over it, and a
28958
+ * resized window invalidates old geometry until a fresh renderer rect
28959
+ * arrives. An unchanged key is the background-page-creation case: the layout
28960
+ * pass may have added a page above the child, so the child is re-added last
28961
+ * and given the same rectangle. It never re-opens by itself; showing again is
28962
+ * always an explicit probe call.
28963
+ */
28964
+ onLayout(snapshot2) {
28965
+ if (this.disposed) return;
28966
+ const next = copyLayout(snapshot2);
28967
+ const nextKey = layoutKeyOf(next);
28968
+ const previousKey = this.layoutKey;
28969
+ this.layout = next;
28970
+ this.layoutKey = nextKey;
28971
+ if (previousKey !== nextKey) {
28972
+ this.hide("layout");
28973
+ return;
28974
+ }
28975
+ if (this.state !== "shown") return;
28976
+ const view = this.view;
28977
+ if (!view || this.viewUsable(view) === false) return;
28978
+ const bounds = overlayBoundsFor(next.contentRect, this.ownerSize());
28979
+ if (bounds === null || !next.presented) {
28980
+ this.hide("layout_invalid");
28981
+ return;
28982
+ }
28983
+ try {
28984
+ view.setBounds(bounds);
28985
+ this.raiseChild(view);
28986
+ } catch (error) {
28987
+ this.releaseChild("layout_error");
28988
+ this.log(`[browser] address overlay layout failed: ${String(error)}`);
28989
+ }
28990
+ }
28991
+ /** The bound page is going away. Dispose the child before the page release. */
28992
+ onTabReleased(tabId) {
28993
+ if (this.disposed) return;
28994
+ if (this.boundTabId !== tabId) return;
28995
+ this.releaseChild("bound-tab-released");
28996
+ }
28997
+ /** The bound page's renderer died but its webContents survives (a crashed tab).
28998
+ * The child is bound to that page's rectangle, so it goes with the renderer; a
28999
+ * later explicit show may create a fresh one. */
29000
+ onPageGone(tabId) {
29001
+ if (this.disposed) return;
29002
+ if (this.boundTabId !== tabId) return;
29003
+ this.releaseChild("page-crash");
29004
+ }
29005
+ // ---- probe surface ------------------------------------------------------
29006
+ async showOverlay() {
29007
+ if (this.showInFlight) return this.showInFlight;
29008
+ const pending = this.showOnce();
29009
+ this.showInFlight = pending;
29010
+ void pending.then(
29011
+ () => {
29012
+ if (this.showInFlight === pending) this.showInFlight = null;
29013
+ },
29014
+ () => {
29015
+ if (this.showInFlight === pending) this.showInFlight = null;
29016
+ }
29017
+ );
29018
+ return pending;
29019
+ }
29020
+ hide(reason = "hide") {
29021
+ if (this.disposed) return;
29022
+ this.generation += 1;
29023
+ this.settleReady(false);
29024
+ this.hiddenReason = reason;
29025
+ const view = this.view;
29026
+ if (view && this.viewUsable(view)) {
29027
+ try {
29028
+ view.setVisible(false);
29029
+ } catch {
29030
+ }
29031
+ }
29032
+ if (this.state === "shown") {
29033
+ this.state = this.failedReason ? "failed" : this.domReady && this.finished ? "ready" : "loading";
29034
+ }
29035
+ this.log(`[browser] address overlay hidden: ${reason}`);
29036
+ }
29037
+ /** Facts only: identifiers, geometry and counters. No page content. */
29038
+ facts() {
29039
+ const view = this.view;
29040
+ let child = null;
29041
+ if (view) {
29042
+ let visible = false;
29043
+ let bounds = null;
29044
+ let order = -1;
29045
+ let childCount = 0;
29046
+ try {
29047
+ visible = view.getVisible();
29048
+ bounds = view.getBounds();
29049
+ const children = this.window.contentView.children;
29050
+ childCount = children.length;
29051
+ order = children.indexOf(view);
29052
+ } catch {
29053
+ }
29054
+ child = {
29055
+ webContentsId: this.childWebContentsId ?? view.webContents.id,
29056
+ visible,
29057
+ bounds,
29058
+ order,
29059
+ childCount
29060
+ };
29061
+ }
29062
+ let ownerDestroyed = true;
29063
+ let contentBounds = null;
29064
+ try {
29065
+ ownerDestroyed = this.window.isDestroyed();
29066
+ if (!ownerDestroyed) contentBounds = this.ownerSize();
29067
+ } catch {
29068
+ ownerDestroyed = true;
29069
+ }
29070
+ return {
29071
+ documentUrl: this.documentUrl,
29072
+ state: this.state,
29073
+ failedReason: this.failedReason,
29074
+ hiddenReason: this.hiddenReason,
29075
+ generation: this.generation,
29076
+ childCreatedCount: this.childCreatedCount,
29077
+ shownCount: this.shownCount,
29078
+ lastShow: this.lastShow,
29079
+ readiness: {
29080
+ domReady: this.domReady,
29081
+ finished: this.finished,
29082
+ loadMs: this.loadMs
29083
+ },
29084
+ child,
29085
+ owner: {
29086
+ windowId: typeof this.window.id === "number" ? this.window.id : null,
29087
+ destroyed: ownerDestroyed,
29088
+ contentBounds
29089
+ },
29090
+ layout: copyLayout(this.layout),
29091
+ listeners: {
29092
+ owner: this.ownerListeners.length,
29093
+ child: this.childListeners.length
29094
+ },
29095
+ pendingShow: this.showInFlight !== null,
29096
+ readinessTimer: this.readinessTimer !== null,
29097
+ metrics: this.appMetrics ? this.appMetrics() : null
29098
+ };
29099
+ }
29100
+ async probe(action) {
29101
+ if (action === "show") {
29102
+ await this.showOverlay();
29103
+ return this.facts();
29104
+ }
29105
+ if (action === "hide") {
29106
+ this.hide("probe");
29107
+ return this.facts();
29108
+ }
29109
+ return this.facts();
29110
+ }
29111
+ /**
29112
+ * Idempotent teardown for the host's stop/rollback/window-close paths.
29113
+ * Closing the webContents before detaching is required: removing a
29114
+ * `WebContentsView` does not release its renderer.
29115
+ */
29116
+ dispose(reason) {
29117
+ if (this.disposed) return;
29118
+ this.disposed = true;
29119
+ this.generation += 1;
29120
+ this.settleReady(false);
29121
+ this.detachOwnerListeners();
29122
+ this.destroyChild();
29123
+ this.state = "disposed";
29124
+ this.hiddenReason = reason;
29125
+ this.log(`[browser] address overlay disposed: ${reason}`);
29126
+ }
29127
+ get isDisposed() {
29128
+ return this.disposed;
29129
+ }
29130
+ // ---- show path ----------------------------------------------------------
29131
+ async showOnce() {
29132
+ const refuse = (reason) => {
29133
+ this.lastShow = { shown: false, reason, bounds: null, at: this.now() };
29134
+ return { shown: false, reason, bounds: null };
29135
+ };
29136
+ try {
29137
+ if (this.disposed) return refuse("disposed");
29138
+ if (this.failedReason) return refuse(this.failedReason);
29139
+ if (this.ownerUnavailable()) {
29140
+ this.releaseChild("owner_unavailable");
29141
+ return refuse("owner_unavailable");
29142
+ }
29143
+ const snapshot2 = this.layout;
29144
+ const bounds = overlayBoundsFor(snapshot2.contentRect, this.ownerSize());
29145
+ if (snapshot2.activeTabId === null || !snapshot2.presented || bounds === null) {
29146
+ return refuse("no_layout");
29147
+ }
29148
+ this.generation += 1;
29149
+ const generation = this.generation;
29150
+ this.boundTabId = snapshot2.activeTabId;
29151
+ if (!this.view) {
29152
+ const created = this.createChild(bounds);
29153
+ if (!created) return refuse(this.failedReason ?? "child_create_failed");
29154
+ }
29155
+ if (!(this.domReady && this.finished)) {
29156
+ this.state = "loading";
29157
+ const ready = await this.waitForReady();
29158
+ if (!ready) return refuse(this.failedReason ?? "invalidated");
29159
+ }
29160
+ if (this.disposed || generation !== this.generation) {
29161
+ return refuse("invalidated");
29162
+ }
29163
+ if (this.ownerUnavailable()) {
29164
+ this.releaseChild("owner_unavailable");
29165
+ return refuse("owner_unavailable");
29166
+ }
29167
+ const view = this.view;
29168
+ if (!view) return refuse("child_missing");
29169
+ const finalBounds = overlayBoundsFor(
29170
+ this.layout.contentRect,
29171
+ this.ownerSize()
29172
+ );
29173
+ if (finalBounds === null || this.layout.activeTabId === null || !this.layout.presented || this.layout.activeTabId !== this.boundTabId) {
29174
+ return refuse("invalidated");
29175
+ }
29176
+ view.setBounds(finalBounds);
29177
+ this.raiseChild(view);
29178
+ view.setVisible(true);
29179
+ this.state = "shown";
29180
+ this.hiddenReason = null;
29181
+ this.shownCount += 1;
29182
+ this.lastShow = {
29183
+ shown: true,
29184
+ reason: null,
29185
+ bounds: finalBounds,
29186
+ at: this.now()
29187
+ };
29188
+ this.log(
29189
+ `[browser] address overlay shown tab=${this.boundTabId} bounds=${finalBounds.x},${finalBounds.y},${finalBounds.width},${finalBounds.height} generation=${generation}`
29190
+ );
29191
+ return { shown: true, reason: null, bounds: finalBounds };
29192
+ } catch (error) {
29193
+ this.failChild(`show_error:${String(error)}`);
29194
+ return refuse("child_error");
29195
+ }
29196
+ }
29197
+ createChild(bounds) {
29198
+ let view;
29199
+ try {
29200
+ view = this.createView();
29201
+ } catch (error) {
29202
+ this.failChild(`child_create_failed:${String(error)}`);
29203
+ return false;
29204
+ }
29205
+ this.view = view;
29206
+ this.childWebContentsId = view.webContents.id;
29207
+ this.childCreatedCount += 1;
29208
+ this.domReady = false;
29209
+ this.finished = false;
29210
+ this.loadMs = null;
29211
+ this.loadStartedAt = null;
29212
+ try {
29213
+ this.window.contentView.addChildView(view);
29214
+ view.setBounds(bounds);
29215
+ view.setVisible(false);
29216
+ } catch (error) {
29217
+ this.failChild(`child_attach_failed:${String(error)}`);
29218
+ return false;
29219
+ }
29220
+ this.wireChild(view);
29221
+ this.loadStartedAt = this.now();
29222
+ try {
29223
+ const loading = view.webContents.loadURL(this.documentUrl);
29224
+ void Promise.resolve(loading).catch((error) => {
29225
+ if (this.disposed || this.view !== view) return;
29226
+ this.failChild(`load_failed:${String(error)}`);
29227
+ });
29228
+ } catch (error) {
29229
+ this.failChild(`load_failed:${String(error)}`);
29230
+ return false;
29231
+ }
29232
+ this.log(
29233
+ `[browser] address overlay child created wc=${view.webContents.id}`
29234
+ );
29235
+ return true;
29236
+ }
29237
+ waitForReady() {
29238
+ if (this.domReady && this.finished) return Promise.resolve(true);
29239
+ if (this.readyWaiter) {
29240
+ return Promise.resolve(false);
29241
+ }
29242
+ return new Promise((resolve) => {
29243
+ this.readyWaiter = resolve;
29244
+ this.readinessTimer = setTimeout(() => {
29245
+ this.readinessTimer = null;
29246
+ if (this.readyWaiter) this.failChild("load_timeout");
29247
+ }, this.readinessTimeoutMs);
29248
+ });
29249
+ }
29250
+ settleReady(ok) {
29251
+ if (this.readinessTimer !== null) {
29252
+ clearTimeout(this.readinessTimer);
29253
+ this.readinessTimer = null;
29254
+ }
29255
+ const waiter = this.readyWaiter;
29256
+ this.readyWaiter = null;
29257
+ if (waiter) waiter(ok);
29258
+ }
29259
+ maybeReady() {
29260
+ if (!(this.domReady && this.finished)) return;
29261
+ if (this.loadStartedAt !== null && this.loadMs === null) {
29262
+ this.loadMs = this.now() - this.loadStartedAt;
29263
+ }
29264
+ if (this.state === "loading" || this.state === "absent") {
29265
+ this.state = this.readyWaiter ? this.state : "ready";
29266
+ }
29267
+ this.settleReady(true);
29268
+ }
29269
+ // ---- child wiring -------------------------------------------------------
29270
+ wireChild(view) {
29271
+ const contents = view.webContents;
29272
+ const on = (target2, event, listener) => {
29273
+ const emitter = target2;
29274
+ emitter.on(event, listener);
29275
+ this.childListeners.push(() => {
29276
+ try {
29277
+ emitter.removeListener(event, listener);
29278
+ } catch {
29279
+ }
29280
+ });
29281
+ };
29282
+ on(contents, "dom-ready", () => {
29283
+ if (this.view !== view) return;
29284
+ this.domReady = true;
29285
+ this.maybeReady();
29286
+ });
29287
+ on(contents, "did-finish-load", () => {
29288
+ if (this.view !== view) return;
29289
+ this.finished = true;
29290
+ this.maybeReady();
29291
+ });
29292
+ on(contents, "did-fail-load", (...args) => {
29293
+ if (this.view !== view) return;
29294
+ const code = typeof args[1] === "number" ? args[1] : 0;
29295
+ const isMainFrame = args[4] !== false;
29296
+ if (!isMainFrame || code === -3) return;
29297
+ this.failChild(`load_failed:${code}`);
29298
+ });
29299
+ on(contents, "render-process-gone", () => {
29300
+ if (this.view !== view) return;
29301
+ this.failChild("child_crash");
29302
+ });
29303
+ on(contents, "destroyed", () => {
29304
+ if (this.view !== view) return;
29305
+ if (this.disposingChild) return;
29306
+ this.failChild("child_destroyed");
29307
+ });
29308
+ on(contents, "will-navigate", (...args) => {
29309
+ const url = typeof args[1] === "string" ? args[1] : "";
29310
+ const event = args[0];
29311
+ if (url === this.documentUrl) return;
29312
+ event?.preventDefault?.();
29313
+ this.log(`[browser] address overlay refused navigation to ${url}`);
29314
+ });
29315
+ on(contents, "will-redirect", (...args) => {
29316
+ const url = typeof args[1] === "string" ? args[1] : "";
29317
+ const event = args[0];
29318
+ if (url === this.documentUrl) return;
29319
+ event?.preventDefault?.();
29320
+ this.log(`[browser] address overlay refused redirect to ${url}`);
29321
+ });
29322
+ }
29323
+ /** Terminal for this host lifetime: a broken document must not be retried. */
29324
+ failChild(reason) {
29325
+ if (this.failedReason) return;
29326
+ this.failedReason = reason;
29327
+ this.state = "failed";
29328
+ this.settleReady(false);
29329
+ this.destroyChild();
29330
+ this.log(`[browser] address overlay failed: ${reason}`);
29331
+ }
29332
+ /** Recoverable: the child goes, a later explicit show may lazily recreate one. */
29333
+ releaseChild(reason) {
29334
+ this.generation += 1;
29335
+ this.settleReady(false);
29336
+ this.destroyChild();
29337
+ if (!this.failedReason) this.state = "absent";
29338
+ this.boundTabId = null;
29339
+ this.domReady = false;
29340
+ this.finished = false;
29341
+ this.loadStartedAt = null;
29342
+ this.log(`[browser] address overlay child released: ${reason}`);
29343
+ }
29344
+ destroyChild() {
29345
+ const view = this.view;
29346
+ if (!view) return;
29347
+ this.view = null;
29348
+ this.childWebContentsId = null;
29349
+ this.disposingChild = true;
29350
+ for (const remove of this.childListeners.splice(0)) remove();
29351
+ try {
29352
+ if (!view.webContents.isDestroyed()) view.webContents.close();
29353
+ } catch {
29354
+ }
29355
+ try {
29356
+ this.window.contentView.removeChildView(view);
29357
+ } catch {
29358
+ }
29359
+ this.disposingChild = false;
29360
+ }
29361
+ raiseChild(view) {
29362
+ this.window.contentView.addChildView(view);
29363
+ }
29364
+ viewUsable(view) {
29365
+ try {
29366
+ return !view.webContents.isDestroyed();
29367
+ } catch {
29368
+ return false;
29369
+ }
29370
+ }
29371
+ // ---- owner wiring -------------------------------------------------------
29372
+ attachOwnerListeners() {
29373
+ const on = (target2, event, listener) => {
29374
+ const emitter = target2;
29375
+ emitter.on(event, listener);
29376
+ this.ownerListeners.push(() => {
29377
+ try {
29378
+ emitter.removeListener(event, listener);
29379
+ } catch {
29380
+ }
29381
+ });
29382
+ };
29383
+ on(this.window, "blur", () => {
29384
+ this.hide("window_blur");
29385
+ });
29386
+ on(this.window, "minimize", () => {
29387
+ this.hide("window_minimize");
29388
+ });
29389
+ on(this.window, "closed", () => {
29390
+ this.dispose("window_closed");
29391
+ });
29392
+ const contents = this.window.webContents;
29393
+ on(contents, "render-process-gone", () => {
29394
+ this.releaseChild("owner_crash");
29395
+ });
29396
+ on(contents, "destroyed", () => {
29397
+ this.dispose("owner_destroyed");
29398
+ });
29399
+ on(contents, "did-start-navigation", (...args) => {
29400
+ const details = args[0];
29401
+ if (details?.isMainFrame && details.isSameDocument !== true) {
29402
+ this.releaseChild("owner_navigation");
29403
+ }
29404
+ });
29405
+ }
29406
+ detachOwnerListeners() {
29407
+ for (const remove of this.ownerListeners.splice(0)) remove();
29408
+ }
29409
+ ownerSize() {
29410
+ const bounds = this.window.getContentBounds();
29411
+ return { width: bounds.width, height: bounds.height };
29412
+ }
29413
+ ownerUnavailable() {
29414
+ try {
29415
+ return this.window.isDestroyed() || this.window.webContents.isDestroyed();
29416
+ } catch {
29417
+ return true;
29418
+ }
29419
+ }
29420
+ }
28717
29421
  const PRIVATE_FILE_MODE = 384;
28718
29422
  const PRIVATE_DIR_MODE = 448;
28719
29423
  function writeJsonAtomic(path2, value) {
@@ -34003,7 +34707,7 @@ const enUiCommandPalette = {
34003
34707
  "ui.command_palette.palette_search.unread": "Unread",
34004
34708
  "ui.command_palette.palette_search.untitled_chat": "Untitled chat",
34005
34709
  "ui.command_palette.use_palette_sources.agent_chat": "Agent chat",
34006
- "ui.command_palette.use_palette_sources.agent_hub": "Agent hub",
34710
+ "ui.command_palette.use_palette_sources.agent_hub": "Agent Hub",
34007
34711
  "ui.command_palette.use_palette_sources.agent_settings": "Agent settings",
34008
34712
  "ui.command_palette.use_palette_sources.analytics": "Analytics",
34009
34713
  "ui.command_palette.use_palette_sources.app_backend_and_environment": "App, backend and environment",
@@ -36509,7 +37213,7 @@ const enUiSettingsUpdates = {
36509
37213
  const enUiShell = {
36510
37214
  "ui.shell.collapsible_app_logo.local_operator": "Local Operator",
36511
37215
  "ui.shell.panel_rail.panels": "Panels",
36512
- "ui.shell.sidebar_navigation.agent_hub": "Agent hub",
37216
+ "ui.shell.sidebar_navigation.agent_hub": "Agent Hub",
36513
37217
  "ui.shell.sidebar_navigation.agents": "Agents",
36514
37218
  "ui.shell.sidebar_navigation.aida_missed": "{name}, {count, plural, one {{count, number, ::group-off} missed message} other {{count, number, ::group-off} missed messages}}",
36515
37219
  "ui.shell.sidebar_navigation.aida_working": "{name}, working",
@@ -36517,17 +37221,31 @@ const enUiShell = {
36517
37221
  "ui.shell.sidebar_navigation.browser_waiting": "Browser, {count, plural, one {{countText} waiting} other {{countText} waiting}}",
36518
37222
  "ui.shell.sidebar_navigation.close_sidebar": "Close sidebar",
36519
37223
  "ui.shell.sidebar_navigation.collapse_sidebar": "Collapse sidebar",
37224
+ "ui.shell.sidebar_navigation.drag_armed": "Moving {name}. Press Escape to cancel.",
36520
37225
  "ui.shell.sidebar_navigation.expand_sidebar": "Expand sidebar",
36521
37226
  "ui.shell.sidebar_navigation.mesh": "Mesh",
36522
37227
  "ui.shell.sidebar_navigation.mesh_waiting": "Mesh, {count, plural, one {{countText} waiting} other {{countText} waiting}}",
37228
+ "ui.shell.sidebar_navigation.more_waiting": "More, {count, plural, one {{countText} waiting} other {{countText} waiting}}",
37229
+ "ui.shell.sidebar_navigation.more_working": "More, working",
37230
+ "ui.shell.sidebar_navigation.move_down": "Move down",
37231
+ "ui.shell.sidebar_navigation.move_note": "Moved {name} to position {position} of {total}.",
37232
+ "ui.shell.sidebar_navigation.move_to_more": "Move to More",
37233
+ "ui.shell.sidebar_navigation.move_to_more_note": "{name} moved to More.",
37234
+ "ui.shell.sidebar_navigation.move_up": "Move up",
36523
37235
  "ui.shell.sidebar_navigation.new_chat": "New chat",
36524
37236
  "ui.shell.sidebar_navigation.new_chat_shortcut": "New chat ({shortcut})",
36525
37237
  "ui.shell.sidebar_navigation.projects": "Projects",
37238
+ "ui.shell.sidebar_navigation.reset_layout": "Reset sidebar layout",
37239
+ "ui.shell.sidebar_navigation.reset_note": "Sidebar layout reset.",
37240
+ "ui.shell.sidebar_navigation.row_actions": "Actions for {name}",
37241
+ "ui.shell.sidebar_navigation.save_failed": "Could not save the sidebar layout.",
36526
37242
  "ui.shell.sidebar_navigation.schedules": "Schedules",
36527
37243
  "ui.shell.sidebar_navigation.search": "Search",
36528
37244
  "ui.shell.sidebar_navigation.search_accessible": "Search ({everything}) — chats ({chats})",
36529
37245
  "ui.shell.sidebar_navigation.search_tooltip": "Search everything ({everything}) · your chats ({chats})",
36530
37246
  "ui.shell.sidebar_navigation.settings": "Settings",
37247
+ "ui.shell.sidebar_navigation.show_in_sidebar": "Show in sidebar",
37248
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name} shown in the sidebar.",
36531
37249
  "ui.shell.user_profile_sidebar.account_settings": "Account settings",
36532
37250
  "ui.shell.user_profile_sidebar.account_unavailable": "Account unavailable",
36533
37251
  "ui.shell.user_profile_sidebar.checking_account": "Checking account…",
@@ -40081,17 +40799,31 @@ const esUiShell = {
40081
40799
  "ui.shell.sidebar_navigation.browser_waiting": "Navegador, {count, plural, one {{countText} en espera} many {{countText} en espera} other {{countText} en espera}}",
40082
40800
  "ui.shell.sidebar_navigation.close_sidebar": "Cerrar barra lateral",
40083
40801
  "ui.shell.sidebar_navigation.collapse_sidebar": "Contraer barra lateral",
40802
+ "ui.shell.sidebar_navigation.drag_armed": "Moviendo {name}. Pulsa Esc para cancelar.",
40084
40803
  "ui.shell.sidebar_navigation.expand_sidebar": "Expandir barra lateral",
40085
40804
  "ui.shell.sidebar_navigation.mesh": "Mesh",
40086
40805
  "ui.shell.sidebar_navigation.mesh_waiting": "Mesh, {count, plural, one {{countText} en espera} many {{countText} en espera} other {{countText} en espera}}",
40806
+ "ui.shell.sidebar_navigation.more_waiting": "Más, {count, plural, one {{countText} en espera} many {{countText} en espera} other {{countText} en espera}}",
40807
+ "ui.shell.sidebar_navigation.more_working": "Más, trabajando",
40808
+ "ui.shell.sidebar_navigation.move_down": "Bajar",
40809
+ "ui.shell.sidebar_navigation.move_note": "Se movió {name} a la posición {position} de {total}.",
40810
+ "ui.shell.sidebar_navigation.move_to_more": "Mover a Más",
40811
+ "ui.shell.sidebar_navigation.move_to_more_note": "{name} se movió a Más.",
40812
+ "ui.shell.sidebar_navigation.move_up": "Subir",
40087
40813
  "ui.shell.sidebar_navigation.new_chat": "Nuevo chat",
40088
40814
  "ui.shell.sidebar_navigation.new_chat_shortcut": "Nuevo chat ({shortcut})",
40089
40815
  "ui.shell.sidebar_navigation.projects": "Proyectos",
40816
+ "ui.shell.sidebar_navigation.reset_layout": "Restablecer la disposición",
40817
+ "ui.shell.sidebar_navigation.reset_note": "Disposición de la barra lateral restablecida.",
40818
+ "ui.shell.sidebar_navigation.row_actions": "Acciones para {name}",
40819
+ "ui.shell.sidebar_navigation.save_failed": "No se pudo guardar la disposición de la barra lateral.",
40090
40820
  "ui.shell.sidebar_navigation.schedules": "Programaciones",
40091
40821
  "ui.shell.sidebar_navigation.search": "Buscar",
40092
40822
  "ui.shell.sidebar_navigation.search_accessible": "Buscar en todo ({everything}) — chats ({chats})",
40093
40823
  "ui.shell.sidebar_navigation.search_tooltip": "Buscar en todo ({everything}) · tus chats ({chats})",
40094
40824
  "ui.shell.sidebar_navigation.settings": "Ajustes",
40825
+ "ui.shell.sidebar_navigation.show_in_sidebar": "Mostrar en la barra lateral",
40826
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name} ahora aparece en la barra lateral.",
40095
40827
  "ui.shell.user_profile_sidebar.account_settings": "Ajustes de cuenta",
40096
40828
  "ui.shell.user_profile_sidebar.account_unavailable": "Cuenta no disponible",
40097
40829
  "ui.shell.user_profile_sidebar.checking_account": "Comprobando la cuenta…",
@@ -43645,17 +44377,31 @@ const frUiShell = {
43645
44377
  "ui.shell.sidebar_navigation.browser_waiting": "Navigateur, {count, plural, one {{countText} approbation en attente} many {{countText} d’approbations en attente} other {{countText} approbations en attente}}",
43646
44378
  "ui.shell.sidebar_navigation.close_sidebar": "Fermer la barre latérale",
43647
44379
  "ui.shell.sidebar_navigation.collapse_sidebar": "Réduire la barre latérale",
44380
+ "ui.shell.sidebar_navigation.drag_armed": "Déplacement de {name}. Appuyez sur Esc pour annuler.",
43648
44381
  "ui.shell.sidebar_navigation.expand_sidebar": "Développer la barre latérale",
43649
44382
  "ui.shell.sidebar_navigation.mesh": "Maillage",
43650
44383
  "ui.shell.sidebar_navigation.mesh_waiting": "Mesh, {count, plural, one {{countText} demande en attente} many {{countText} de demandes en attente} other {{countText} demandes en attente}}",
44384
+ "ui.shell.sidebar_navigation.more_waiting": "Plus, {count, plural, one {{countText} en attente} many {{countText} en attente} other {{countText} en attente}}",
44385
+ "ui.shell.sidebar_navigation.more_working": "Plus, en cours",
44386
+ "ui.shell.sidebar_navigation.move_down": "Déplacer vers le bas",
44387
+ "ui.shell.sidebar_navigation.move_note": "{name} est maintenant en position {position} sur {total}.",
44388
+ "ui.shell.sidebar_navigation.move_to_more": "Déplacer vers Plus",
44389
+ "ui.shell.sidebar_navigation.move_to_more_note": "{name} fait maintenant partie de Plus.",
44390
+ "ui.shell.sidebar_navigation.move_up": "Déplacer vers le haut",
43651
44391
  "ui.shell.sidebar_navigation.new_chat": "Nouvelle conversation",
43652
44392
  "ui.shell.sidebar_navigation.new_chat_shortcut": "Nouvelle conversation ({shortcut})",
43653
44393
  "ui.shell.sidebar_navigation.projects": "Projets",
44394
+ "ui.shell.sidebar_navigation.reset_layout": "Réinitialiser la disposition",
44395
+ "ui.shell.sidebar_navigation.reset_note": "Disposition de la barre latérale réinitialisée.",
44396
+ "ui.shell.sidebar_navigation.row_actions": "Actions pour {name}",
44397
+ "ui.shell.sidebar_navigation.save_failed": "Impossible d’enregistrer la disposition de la barre latérale.",
43654
44398
  "ui.shell.sidebar_navigation.schedules": "Planifications",
43655
44399
  "ui.shell.sidebar_navigation.search": "Rechercher",
43656
44400
  "ui.shell.sidebar_navigation.search_accessible": "Rechercher ({everything}) — conversations ({chats})",
43657
44401
  "ui.shell.sidebar_navigation.search_tooltip": "Tout rechercher ({everything}) · vos conversations ({chats})",
43658
44402
  "ui.shell.sidebar_navigation.settings": "Paramètres",
44403
+ "ui.shell.sidebar_navigation.show_in_sidebar": "Afficher dans la barre latérale",
44404
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name} apparaît maintenant dans la barre latérale.",
43659
44405
  "ui.shell.user_profile_sidebar.account_settings": "Paramètres du compte",
43660
44406
  "ui.shell.user_profile_sidebar.account_unavailable": "Compte indisponible",
43661
44407
  "ui.shell.user_profile_sidebar.checking_account": "Vérification du compte…",
@@ -47167,17 +47913,31 @@ const hiUiShell = {
47167
47913
  "ui.shell.sidebar_navigation.browser_waiting": "ब्राउज़र, {count, plural, one {{countText} इंतज़ार में} other {{countText} इंतज़ार में}}",
47168
47914
  "ui.shell.sidebar_navigation.close_sidebar": "साइडबार बंद करें",
47169
47915
  "ui.shell.sidebar_navigation.collapse_sidebar": "साइडबार समेटें",
47916
+ "ui.shell.sidebar_navigation.drag_armed": "{name} को ले जाया जा रहा है। रद्द करने के लिए Esc दबाएँ।",
47170
47917
  "ui.shell.sidebar_navigation.expand_sidebar": "साइडबार फैलाएँ",
47171
47918
  "ui.shell.sidebar_navigation.mesh": "मेश",
47172
47919
  "ui.shell.sidebar_navigation.mesh_waiting": "मेश, {count, plural, one {{countText} इंतज़ार में} other {{countText} इंतज़ार में}}",
47920
+ "ui.shell.sidebar_navigation.more_waiting": "और, {count, plural, one {{countText} इंतज़ार में} other {{countText} इंतज़ार में}}",
47921
+ "ui.shell.sidebar_navigation.more_working": "और, काम जारी है",
47922
+ "ui.shell.sidebar_navigation.move_down": "नीचे ले जाएँ",
47923
+ "ui.shell.sidebar_navigation.move_note": "{name} को कुल {total} में से स्थान {position} पर ले जाया गया।",
47924
+ "ui.shell.sidebar_navigation.move_to_more": "और सेक्शन में ले जाएँ",
47925
+ "ui.shell.sidebar_navigation.move_to_more_note": "{name} को और सेक्शन में ले जाया गया।",
47926
+ "ui.shell.sidebar_navigation.move_up": "ऊपर ले जाएँ",
47173
47927
  "ui.shell.sidebar_navigation.new_chat": "नई चैट",
47174
47928
  "ui.shell.sidebar_navigation.new_chat_shortcut": "नई चैट ({shortcut})",
47175
47929
  "ui.shell.sidebar_navigation.projects": "प्रोजेक्ट",
47930
+ "ui.shell.sidebar_navigation.reset_layout": "साइडबार लेआउट रीसेट करें",
47931
+ "ui.shell.sidebar_navigation.reset_note": "साइडबार लेआउट रीसेट हो गया।",
47932
+ "ui.shell.sidebar_navigation.row_actions": "{name} की कार्रवाइयाँ",
47933
+ "ui.shell.sidebar_navigation.save_failed": "साइडबार लेआउट सहेजा नहीं जा सका।",
47176
47934
  "ui.shell.sidebar_navigation.schedules": "शेड्यूल",
47177
47935
  "ui.shell.sidebar_navigation.search": "खोजें",
47178
47936
  "ui.shell.sidebar_navigation.search_accessible": "खोजें ({everything}) — चैट ({chats})",
47179
47937
  "ui.shell.sidebar_navigation.search_tooltip": "सब कुछ खोजें ({everything}) · आपकी चैट ({chats})",
47180
47938
  "ui.shell.sidebar_navigation.settings": "सेटिंग्स",
47939
+ "ui.shell.sidebar_navigation.show_in_sidebar": "साइडबार में दिखाएँ",
47940
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name} अब साइडबार में है।",
47181
47941
  "ui.shell.user_profile_sidebar.account_settings": "खाते की सेटिंग्स",
47182
47942
  "ui.shell.user_profile_sidebar.account_unavailable": "खाता उपलब्ध नहीं",
47183
47943
  "ui.shell.user_profile_sidebar.checking_account": "खाता जाँचा जा रहा है…",
@@ -50528,17 +51288,31 @@ const ruUiShell = {
50528
51288
  "ui.shell.sidebar_navigation.browser_waiting": "Браузер, {count, plural, one {ожидает {countText}} few {ожидают {countText}} many {ожидают {countText}} other {ожидают {countText}}}",
50529
51289
  "ui.shell.sidebar_navigation.close_sidebar": "Закрыть боковую панель",
50530
51290
  "ui.shell.sidebar_navigation.collapse_sidebar": "Свернуть боковую панель",
51291
+ "ui.shell.sidebar_navigation.drag_armed": "Перемещение: {name}. Нажмите Esc, чтобы отменить.",
50531
51292
  "ui.shell.sidebar_navigation.expand_sidebar": "Развернуть боковую панель",
50532
51293
  "ui.shell.sidebar_navigation.mesh": "Меш-сеть",
50533
51294
  "ui.shell.sidebar_navigation.mesh_waiting": "Меш-сеть, {count, plural, one {ожидает {countText}} few {ожидают {countText}} many {ожидают {countText}} other {ожидают {countText}}}",
51295
+ "ui.shell.sidebar_navigation.more_waiting": "Ещё, {count, plural, one {ожидает {countText}} few {ожидают {countText}} many {ожидают {countText}} other {ожидают {countText}}}",
51296
+ "ui.shell.sidebar_navigation.more_working": "Ещё, идёт работа",
51297
+ "ui.shell.sidebar_navigation.move_down": "Переместить ниже",
51298
+ "ui.shell.sidebar_navigation.move_note": "{name} теперь на позиции {position} из {total}.",
51299
+ "ui.shell.sidebar_navigation.move_to_more": "Переместить в «Ещё»",
51300
+ "ui.shell.sidebar_navigation.move_to_more_note": "{name} теперь в «Ещё».",
51301
+ "ui.shell.sidebar_navigation.move_up": "Переместить выше",
50534
51302
  "ui.shell.sidebar_navigation.new_chat": "Новый чат",
50535
51303
  "ui.shell.sidebar_navigation.new_chat_shortcut": "Новый чат ({shortcut})",
50536
51304
  "ui.shell.sidebar_navigation.projects": "Проекты",
51305
+ "ui.shell.sidebar_navigation.reset_layout": "Сбросить расположение боковой панели",
51306
+ "ui.shell.sidebar_navigation.reset_note": "Расположение боковой панели сброшено.",
51307
+ "ui.shell.sidebar_navigation.row_actions": "Действия для {name}",
51308
+ "ui.shell.sidebar_navigation.save_failed": "Не удалось сохранить расположение боковой панели.",
50537
51309
  "ui.shell.sidebar_navigation.schedules": "Расписания",
50538
51310
  "ui.shell.sidebar_navigation.search": "Поиск",
50539
51311
  "ui.shell.sidebar_navigation.search_accessible": "Поиск ({everything}) — чаты ({chats})",
50540
51312
  "ui.shell.sidebar_navigation.search_tooltip": "Поиск по всему ({everything}) · ваши чаты ({chats})",
50541
51313
  "ui.shell.sidebar_navigation.settings": "Настройки",
51314
+ "ui.shell.sidebar_navigation.show_in_sidebar": "Показать на боковой панели",
51315
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name} теперь отображается на боковой панели.",
50542
51316
  "ui.shell.user_profile_sidebar.account_settings": "Настройки учётной записи",
50543
51317
  "ui.shell.user_profile_sidebar.account_unavailable": "Учётная запись недоступна",
50544
51318
  "ui.shell.user_profile_sidebar.checking_account": "Проверка учётной записи…",
@@ -53975,17 +54749,31 @@ const urUiShell = {
53975
54749
  "ui.shell.sidebar_navigation.browser_waiting": "براؤزر، {count, plural, one {{countText} منتظر} other {{countText} منتظر}}",
53976
54750
  "ui.shell.sidebar_navigation.close_sidebar": "سائیڈ بار بند کریں",
53977
54751
  "ui.shell.sidebar_navigation.collapse_sidebar": "سائیڈ بار سمیٹیں",
54752
+ "ui.shell.sidebar_navigation.drag_armed": "{name} منتقل کیا جا رہا ہے۔ منسوخ کرنے کے لیے Esc دبائیں۔",
53978
54753
  "ui.shell.sidebar_navigation.expand_sidebar": "سائیڈ بار پھیلائیں",
53979
54754
  "ui.shell.sidebar_navigation.mesh": "Mesh",
53980
54755
  "ui.shell.sidebar_navigation.mesh_waiting": "Mesh، {count, plural, one {{countText} منتظر} other {{countText} منتظر}}",
54756
+ "ui.shell.sidebar_navigation.more_waiting": "مزید، {count, plural, one {{countText} منتظر} other {{countText} منتظر}}",
54757
+ "ui.shell.sidebar_navigation.more_working": "مزید، کام جاری ہے",
54758
+ "ui.shell.sidebar_navigation.move_down": "نیچے کریں",
54759
+ "ui.shell.sidebar_navigation.move_note": "{name} کو {total} میں سے {position} مقام پر منتقل کر دیا گیا۔",
54760
+ "ui.shell.sidebar_navigation.move_to_more": "مزید حصے میں منتقل کریں",
54761
+ "ui.shell.sidebar_navigation.move_to_more_note": "{name} کو مزید حصے میں منتقل کر دیا گیا۔",
54762
+ "ui.shell.sidebar_navigation.move_up": "اوپر کریں",
53981
54763
  "ui.shell.sidebar_navigation.new_chat": "نئی چیٹ",
53982
54764
  "ui.shell.sidebar_navigation.new_chat_shortcut": "نئی چیٹ — {shortcut}",
53983
54765
  "ui.shell.sidebar_navigation.projects": "پروجیکٹس",
54766
+ "ui.shell.sidebar_navigation.reset_layout": "سائیڈ بار کا لے آؤٹ ری سیٹ کریں",
54767
+ "ui.shell.sidebar_navigation.reset_note": "سائیڈ بار کا لے آؤٹ ری سیٹ ہو گیا۔",
54768
+ "ui.shell.sidebar_navigation.row_actions": "{name} کے لیے اقدامات",
54769
+ "ui.shell.sidebar_navigation.save_failed": "سائیڈ بار کا لے آؤٹ محفوظ نہیں ہو سکا۔",
53984
54770
  "ui.shell.sidebar_navigation.schedules": "شیڈول",
53985
54771
  "ui.shell.sidebar_navigation.search": "تلاش کریں",
53986
54772
  "ui.shell.sidebar_navigation.search_accessible": "تلاش — {everything} — چیٹس — {chats}",
53987
54773
  "ui.shell.sidebar_navigation.search_tooltip": "سب کچھ تلاش کریں — {everything} · آپ کی چیٹس — {chats}",
53988
54774
  "ui.shell.sidebar_navigation.settings": "ترتیبات",
54775
+ "ui.shell.sidebar_navigation.show_in_sidebar": "سائیڈ بار میں دکھائیں",
54776
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name} اب سائیڈ بار میں ہے۔",
53989
54777
  "ui.shell.user_profile_sidebar.account_settings": "اکاؤنٹ کی ترتیبات",
53990
54778
  "ui.shell.user_profile_sidebar.account_unavailable": "اکاؤنٹ دستیاب نہیں",
53991
54779
  "ui.shell.user_profile_sidebar.checking_account": "اکاؤنٹ کی جانچ ہو رہی ہے…",
@@ -57145,17 +57933,31 @@ const viUiShell = {
57145
57933
  "ui.shell.sidebar_navigation.browser_waiting": "Trình duyệt, {count, plural, other {{countText} đang chờ}}",
57146
57934
  "ui.shell.sidebar_navigation.close_sidebar": "Đóng thanh bên",
57147
57935
  "ui.shell.sidebar_navigation.collapse_sidebar": "Thu gọn thanh bên",
57936
+ "ui.shell.sidebar_navigation.drag_armed": "Đang chuyển {name}. Nhấn Esc để hủy.",
57148
57937
  "ui.shell.sidebar_navigation.expand_sidebar": "Mở rộng thanh bên",
57149
57938
  "ui.shell.sidebar_navigation.mesh": "Mạng lưới",
57150
57939
  "ui.shell.sidebar_navigation.mesh_waiting": "Mạng lưới, {count, plural, other {{countText} đang chờ}}",
57940
+ "ui.shell.sidebar_navigation.more_waiting": "Khác, {count, plural, other {{countText} đang chờ}}",
57941
+ "ui.shell.sidebar_navigation.more_working": "Khác, đang làm việc",
57942
+ "ui.shell.sidebar_navigation.move_down": "Chuyển xuống",
57943
+ "ui.shell.sidebar_navigation.move_note": "Đã chuyển {name} đến vị trí {position} trên {total}.",
57944
+ "ui.shell.sidebar_navigation.move_to_more": "Chuyển vào mục Khác",
57945
+ "ui.shell.sidebar_navigation.move_to_more_note": "Đã chuyển {name} vào mục Khác.",
57946
+ "ui.shell.sidebar_navigation.move_up": "Chuyển lên",
57151
57947
  "ui.shell.sidebar_navigation.new_chat": "Cuộc trò chuyện mới",
57152
57948
  "ui.shell.sidebar_navigation.new_chat_shortcut": "Cuộc trò chuyện mới ({shortcut})",
57153
57949
  "ui.shell.sidebar_navigation.projects": "Dự án",
57950
+ "ui.shell.sidebar_navigation.reset_layout": "Đặt lại bố cục thanh bên",
57951
+ "ui.shell.sidebar_navigation.reset_note": "Đã đặt lại bố cục thanh bên.",
57952
+ "ui.shell.sidebar_navigation.row_actions": "Thao tác cho {name}",
57953
+ "ui.shell.sidebar_navigation.save_failed": "Không lưu được bố cục thanh bên.",
57154
57954
  "ui.shell.sidebar_navigation.schedules": "Lịch chạy",
57155
57955
  "ui.shell.sidebar_navigation.search": "Tìm kiếm",
57156
57956
  "ui.shell.sidebar_navigation.search_accessible": "Tìm kiếm ({everything}) — cuộc trò chuyện ({chats})",
57157
57957
  "ui.shell.sidebar_navigation.search_tooltip": "Tìm mọi thứ ({everything}) · cuộc trò chuyện của bạn ({chats})",
57158
57958
  "ui.shell.sidebar_navigation.settings": "Cài đặt",
57959
+ "ui.shell.sidebar_navigation.show_in_sidebar": "Hiện trong thanh bên",
57960
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name} đã được hiển thị trong thanh bên.",
57159
57961
  "ui.shell.user_profile_sidebar.account_settings": "Cài đặt tài khoản",
57160
57962
  "ui.shell.user_profile_sidebar.account_unavailable": "Không truy cập được tài khoản",
57161
57963
  "ui.shell.user_profile_sidebar.checking_account": "Đang kiểm tra tài khoản…",
@@ -60614,17 +61416,31 @@ const zhCNUiShell = {
60614
61416
  "ui.shell.sidebar_navigation.browser_waiting": "浏览器,{count, plural, other {{countText}项待处理}}",
60615
61417
  "ui.shell.sidebar_navigation.close_sidebar": "关闭侧边栏",
60616
61418
  "ui.shell.sidebar_navigation.collapse_sidebar": "收起侧边栏",
61419
+ "ui.shell.sidebar_navigation.drag_armed": "正在移动{name}。按Esc取消。",
60617
61420
  "ui.shell.sidebar_navigation.expand_sidebar": "展开侧边栏",
60618
61421
  "ui.shell.sidebar_navigation.mesh": "网格",
60619
61422
  "ui.shell.sidebar_navigation.mesh_waiting": "网格,{count, plural, other {{countText}项待处理}}",
61423
+ "ui.shell.sidebar_navigation.more_waiting": "更多,{count, plural, other {{countText}项待处理}}",
61424
+ "ui.shell.sidebar_navigation.more_working": "更多,工作中",
61425
+ "ui.shell.sidebar_navigation.move_down": "下移",
61426
+ "ui.shell.sidebar_navigation.move_note": "已将{name}移至第{position}位,共{total}个。",
61427
+ "ui.shell.sidebar_navigation.move_to_more": "移至更多",
61428
+ "ui.shell.sidebar_navigation.move_to_more_note": "{name}已移至更多。",
61429
+ "ui.shell.sidebar_navigation.move_up": "上移",
60620
61430
  "ui.shell.sidebar_navigation.new_chat": "新建对话",
60621
61431
  "ui.shell.sidebar_navigation.new_chat_shortcut": "新建对话({shortcut})",
60622
61432
  "ui.shell.sidebar_navigation.projects": "项目",
61433
+ "ui.shell.sidebar_navigation.reset_layout": "重置侧边栏布局",
61434
+ "ui.shell.sidebar_navigation.reset_note": "侧边栏布局已重置。",
61435
+ "ui.shell.sidebar_navigation.row_actions": "{name}的操作",
61436
+ "ui.shell.sidebar_navigation.save_failed": "无法保存侧边栏布局。",
60623
61437
  "ui.shell.sidebar_navigation.schedules": "定时任务",
60624
61438
  "ui.shell.sidebar_navigation.search": "搜索",
60625
61439
  "ui.shell.sidebar_navigation.search_accessible": "搜索({everything})—对话({chats})",
60626
61440
  "ui.shell.sidebar_navigation.search_tooltip": "搜索全部内容({everything})·搜索对话({chats})",
60627
61441
  "ui.shell.sidebar_navigation.settings": "设置",
61442
+ "ui.shell.sidebar_navigation.show_in_sidebar": "在侧边栏中显示",
61443
+ "ui.shell.sidebar_navigation.show_in_sidebar_note": "{name}已显示在侧边栏中。",
60628
61444
  "ui.shell.user_profile_sidebar.account_settings": "账户设置",
60629
61445
  "ui.shell.user_profile_sidebar.account_unavailable": "账户不可用",
60630
61446
  "ui.shell.user_profile_sidebar.checking_account": "正在检查账户……",
@@ -62955,10 +63771,29 @@ function mintNonce() {
62955
63771
  return node_crypto.randomBytes(16).toString("hex");
62956
63772
  }
62957
63773
  class TabRegistry {
62958
- constructor(viewFactory, onRemove, onChanged) {
63774
+ /**
63775
+ * The fourth callback is a post-layout observer, optional and defaulted so
63776
+ * every existing three-argument construction is unchanged.
63777
+ *
63778
+ * WHY IT EXISTS: a native child positioned over a page has to know that the
63779
+ * presented tab, its presentation bit or the content rectangle moved. Polling
63780
+ * the registry would read a rectangle that is already stale, and `onChanged`
63781
+ * is deliberately NOT that signal (`setContentRect` does not call it). The
63782
+ * snapshot is copied and delivered after every pass — including null and
63783
+ * suppressed layouts — because "nothing is presented now" is exactly when a
63784
+ * stale overlay must hide.
63785
+ *
63786
+ * WHY IT CANNOT FAIL THE LAYOUT: page geometry is the product's behaviour and
63787
+ * an observer is infrastructure around it. A throwing observer is swallowed
63788
+ * here (the controller logs its own failure) so one experimental child can
63789
+ * never leave pages unlaid-out.
63790
+ */
63791
+ constructor(viewFactory, onRemove, onChanged, onLayout = () => {
63792
+ }) {
62959
63793
  this.viewFactory = viewFactory;
62960
63794
  this.onRemove = onRemove;
62961
63795
  this.onChanged = onChanged;
63796
+ this.onLayout = onLayout;
62962
63797
  }
62963
63798
  tabs = /* @__PURE__ */ new Map();
62964
63799
  nextTabId = 1;
@@ -62968,6 +63803,9 @@ class TabRegistry {
62968
63803
  /** Tabs with a command in flight, keyed by tabId. See `lane`. */
62969
63804
  busy = /* @__PURE__ */ new Set();
62970
63805
  epochListeners = [];
63806
+ /** Monotone count of layout passes, for an observer that needs identity, not
63807
+ * just values (S1's address overlay). */
63808
+ layoutRevision = 0;
62971
63809
  // ---- creation, addressing, listing ---------------------------------------
62972
63810
  /**
62973
63811
  * Create a tab. A user tab becomes active (the user asked for it); an AGENT
@@ -63270,6 +64108,22 @@ class TabRegistry {
63270
64108
  );
63271
64109
  record.view.setVisible(record.presented);
63272
64110
  }
64111
+ this.layoutRevision += 1;
64112
+ const rect = this.contentRect;
64113
+ try {
64114
+ this.onLayout({
64115
+ activeTabId: this.activeTabId,
64116
+ presented: active?.presented === true,
64117
+ contentRect: rect ? {
64118
+ x: rect.x,
64119
+ y: rect.y,
64120
+ width: rect.width,
64121
+ height: rect.height
64122
+ } : null,
64123
+ revision: this.layoutRevision
64124
+ });
64125
+ } catch {
64126
+ }
63273
64127
  }
63274
64128
  // ---- removal -------------------------------------------------------------
63275
64129
  /**
@@ -66365,6 +67219,58 @@ function restrictMode(path2, log2) {
66365
67219
  );
66366
67220
  }
66367
67221
  }
67222
+ const DEV_DRIVER_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER";
67223
+ const DEV_DRIVER_OUT_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER_OUT";
67224
+ const DEV_DRIVER_ARG = "--lo-dev-driver";
67225
+ const DEV_DRIVER_CAPTURE = "dev-driver-capture";
67226
+ const DEV_DRIVER_FACTS = "dev-driver-facts";
67227
+ const DEV_DRIVER_ADDRESS_OVERLAY = "dev-driver-address-overlay";
67228
+ const TRUTHY = /* @__PURE__ */ new Set(["1", "true"]);
67229
+ function readOptIn(env) {
67230
+ const raw = env[DEV_DRIVER_ENV];
67231
+ if (raw === void 0 || raw.trim() === "")
67232
+ return { asked: false, value: null };
67233
+ return { asked: true, value: raw.trim() };
67234
+ }
67235
+ function resolveDevDriverArming(input) {
67236
+ const off = (problems = []) => ({
67237
+ armed: false,
67238
+ outDir: null,
67239
+ problems
67240
+ });
67241
+ const optIn = readOptIn(input.env);
67242
+ if (!optIn.asked) return off();
67243
+ if (!TRUTHY.has(optIn.value.toLowerCase())) {
67244
+ return off([
67245
+ `${DEV_DRIVER_ENV}=${optIn.value} is not an opt-in (accepted: 1, true); the renderer dev driver stayed off`
67246
+ ]);
67247
+ }
67248
+ if (input.windowMode !== "headless" && input.windowMode !== "inactive") {
67249
+ return off([
67250
+ `the renderer dev driver refused to arm in a "${input.windowMode}" window; it never raises one, so use --window-mode=headless (or inactive)`
67251
+ ]);
67252
+ }
67253
+ const outDir = input.env[DEV_DRIVER_OUT_ENV]?.trim() ?? "";
67254
+ if (outDir === "" || !outDir.startsWith("/")) {
67255
+ return off([
67256
+ `${DEV_DRIVER_ENV} was set but ${DEV_DRIVER_OUT_ENV} is ${outDir === "" ? "missing" : `"${outDir}"`}; an absolute frames directory is required, so the driver did not arm`
67257
+ ]);
67258
+ }
67259
+ return { armed: true, outDir, problems: [] };
67260
+ }
67261
+ function headlessExerciserAllowed(input) {
67262
+ return input.arming.armed && input.windowMode === "headless";
67263
+ }
67264
+ function devDriverArgument(outDir) {
67265
+ return `${DEV_DRIVER_ARG}=${outDir}`;
67266
+ }
67267
+ function describeDevDriverArming(arming) {
67268
+ if (arming.armed) {
67269
+ return `[dev-driver] ARMED; frames are written to ${arming.outDir}`;
67270
+ }
67271
+ if (arming.problems.length === 0) return null;
67272
+ return `[dev-driver] not armed: ${arming.problems.join("; ")}`;
67273
+ }
66368
67274
  class StartupRollback {
66369
67275
  owners = [];
66370
67276
  add(cleanup) {
@@ -66460,7 +67366,14 @@ const BROWSER_IPC_CHANNELS = [
66460
67366
  "browser-reveal-downloads",
66461
67367
  /** The user's own recovery click on the `unavailable` state (round 1, D1a).
66462
67368
  * Named here so the namespace stays the one place that lists its channels. */
66463
- "browser-retry"
67369
+ "browser-retry",
67370
+ /**
67371
+ * S1's probe-only channel. Listed here for unregistration only: the handler
67372
+ * below is registered only when the launch gate passed, and this entry makes
67373
+ * `unregisterBrowserIpc` remove it on a stop/retry like every other channel
67374
+ * (removing an unregistered handler is a no-op).
67375
+ */
67376
+ DEV_DRIVER_ADDRESS_OVERLAY
66464
67377
  ];
66465
67378
  function registerBrowserIpc(options) {
66466
67379
  function authorizeSender(event) {
@@ -66706,6 +67619,23 @@ function registerBrowserIpc(options) {
66706
67619
  await options.retry();
66707
67620
  return { retried: true };
66708
67621
  });
67622
+ if (options.addressOverlayProbe) {
67623
+ electron.ipcMain.handle(DEV_DRIVER_ADDRESS_OVERLAY, (event, action) => {
67624
+ authorizeSender(event);
67625
+ if (action !== "show" && action !== "hide" && action !== "facts") {
67626
+ throw new Error(
67627
+ "address_overlay_invalid_action: expected 'show', 'hide' or 'facts'."
67628
+ );
67629
+ }
67630
+ const probe = options.addressOverlayProbe;
67631
+ if (!probe) {
67632
+ throw new Error(
67633
+ "address_overlay_unavailable: the overlay probe is not running."
67634
+ );
67635
+ }
67636
+ return probe(action);
67637
+ });
67638
+ }
66709
67639
  }
66710
67640
  function unregisterBrowserIpc() {
66711
67641
  for (const channel of BROWSER_IPC_CHANNELS) electron.ipcMain.removeHandler(channel);
@@ -68683,6 +69613,22 @@ function startBrowserHost(options) {
68683
69613
  await startBrowserHost(options).catch(() => {
68684
69614
  });
68685
69615
  },
69616
+ /*
69617
+ * S1's probe channel is registered ONLY when this launch's gate passed, and
69618
+ * then it reads the current attempt's callback through `bindings` (a retry
69619
+ * replaces it) rather than capturing a controller here.
69620
+ */
69621
+ ...options.addressOverlay?.enabled ? {
69622
+ addressOverlayProbe: (action) => {
69623
+ const probe = bindings.addressOverlayProbe;
69624
+ if (!probe) {
69625
+ throw new Error(
69626
+ "address_overlay_unavailable: the overlay controller is not running."
69627
+ );
69628
+ }
69629
+ return probe(action);
69630
+ }
69631
+ } : {},
68686
69632
  log: options.log
68687
69633
  });
68688
69634
  starting = startWithRetries({
@@ -68719,6 +69665,7 @@ async function initializeBrowserHost(options, bindings) {
68719
69665
  };
68720
69666
  try {
68721
69667
  let releaseTab = function(tabId, webContentsId) {
69668
+ addressOverlay?.onTabReleased(tabId);
68722
69669
  const view = views.get(tabId);
68723
69670
  views.delete(tabId);
68724
69671
  downloads.forget(tabId);
@@ -68870,6 +69817,9 @@ async function initializeBrowserHost(options, bindings) {
68870
69817
  });
68871
69818
  contents.on("did-stop-loading", notifyChrome);
68872
69819
  contents.on("page-title-updated", notifyChrome);
69820
+ contents.on("render-process-gone", () => {
69821
+ addressOverlay?.onPageGone(tabId);
69822
+ });
68873
69823
  contents.on(
68874
69824
  "did-fail-load",
68875
69825
  (_event, code, description, url, isMainFrame) => {
@@ -69064,6 +70014,15 @@ async function initializeBrowserHost(options, bindings) {
69064
70014
  const views = /* @__PURE__ */ new Map();
69065
70015
  const releases = /* @__PURE__ */ new Set();
69066
70016
  let stateWriter = null;
70017
+ const addressOverlay = options.addressOverlay?.enabled === true ? new AddressOverlayController({
70018
+ window: options.window,
70019
+ documentUrl: options.addressOverlay.documentUrl,
70020
+ log: log2,
70021
+ appMetrics: () => electron.app.getAppMetrics().map((metric) => ({
70022
+ pid: metric.pid,
70023
+ type: metric.type
70024
+ }))
70025
+ }) : null;
69067
70026
  const sessionStore = new BrowserSessionStore({
69068
70027
  dir: path$1.join(options.userDataDir, "browser"),
69069
70028
  log: log2
@@ -69104,7 +70063,9 @@ async function initializeBrowserHost(options, bindings) {
69104
70063
  };
69105
70064
  const notifyChanged = () => {
69106
70065
  stateWriter?.publishNow();
69107
- options.window.webContents.send("browser-state-changed");
70066
+ if (!options.window.isDestroyed() && !options.window.webContents.isDestroyed()) {
70067
+ options.window.webContents.send("browser-state-changed");
70068
+ }
69108
70069
  captureSession();
69109
70070
  };
69110
70071
  const registry = new TabRegistry(
@@ -69115,7 +70076,8 @@ async function initializeBrowserHost(options, bindings) {
69115
70076
  return view;
69116
70077
  },
69117
70078
  releaseTab,
69118
- notifyChanged
70079
+ notifyChanged,
70080
+ (snapshot2) => addressOverlay?.onLayout(snapshot2)
69119
70081
  );
69120
70082
  registryForDownloads = registry;
69121
70083
  rollback.add(async () => {
@@ -69124,6 +70086,7 @@ async function initializeBrowserHost(options, bindings) {
69124
70086
  registry.destroyAll();
69125
70087
  await Promise.allSettled([...releases]);
69126
70088
  });
70089
+ rollback.add(() => addressOverlay?.dispose("startup-rollback"));
69127
70090
  const ownership = new OwnershipLedger({
69128
70091
  mayAdopt: (token, requester) => {
69129
70092
  const record = registry.requireSurface(token);
@@ -69150,7 +70113,9 @@ async function initializeBrowserHost(options, bindings) {
69150
70113
  const approvals = new ApprovalStore({
69151
70114
  dir: path$1.join(options.userDataDir, "browser"),
69152
70115
  onChanged: () => {
69153
- options.window.webContents.send("browser-consent-changed");
70116
+ if (!options.window.isDestroyed() && !options.window.webContents.isDestroyed()) {
70117
+ options.window.webContents.send("browser-consent-changed");
70118
+ }
69154
70119
  consentNotifier.announce(approvals.pendingEntries());
69155
70120
  },
69156
70121
  log: log2
@@ -69232,6 +70197,7 @@ async function initializeBrowserHost(options, bindings) {
69232
70197
  host.clearPageFocus();
69233
70198
  };
69234
70199
  const resetMenuShortcutSuppression = () => {
70200
+ if (options.window.isDestroyed()) return;
69235
70201
  if (!options.window.webContents.isDestroyed())
69236
70202
  options.window.webContents.setIgnoreMenuShortcuts(false);
69237
70203
  };
@@ -69249,6 +70215,7 @@ async function initializeBrowserHost(options, bindings) {
69249
70215
  options.window.webContents.on("render-process-gone", resetChordFocus);
69250
70216
  const detachChords = () => {
69251
70217
  host.clearChordState();
70218
+ if (options.window.isDestroyed()) return;
69252
70219
  options.window.webContents.removeListener(
69253
70220
  "before-input-event",
69254
70221
  onChromeInput
@@ -69358,6 +70325,25 @@ async function initializeBrowserHost(options, bindings) {
69358
70325
  );
69359
70326
  rollback.add(() => stateWriter?.clear());
69360
70327
  stateWriter.start(server.port, sessionKey);
70328
+ const probeAddressOverlay = async (action) => {
70329
+ if (!addressOverlay) {
70330
+ throw new Error(
70331
+ "address_overlay_unavailable: this host owns no controller."
70332
+ );
70333
+ }
70334
+ const facts2 = await addressOverlay.probe(action);
70335
+ const record = registry.activeTab;
70336
+ const page = record ? {
70337
+ tabId: record.tabId,
70338
+ presented: record.presented,
70339
+ bounds: record.view.getBounds?.() ?? null,
70340
+ visible: record.view.getVisible?.() ?? false
70341
+ } : null;
70342
+ return { ...facts2, page };
70343
+ };
70344
+ if (addressOverlay) {
70345
+ bindings.addressOverlayProbe = probeAddressOverlay;
70346
+ }
69361
70347
  Object.assign(bindings, {
69362
70348
  window: () => options.window,
69363
70349
  expectedUrl: options.expectedUrl,
@@ -69387,6 +70373,7 @@ async function initializeBrowserHost(options, bindings) {
69387
70373
  profileDir,
69388
70374
  agentTabs: () => registry.agentTabCount(),
69389
70375
  sessionCookies: () => restoreReport,
70376
+ ...addressOverlay ? { addressOverlay: probeAddressOverlay } : {},
69390
70377
  stop: async () => {
69391
70378
  detachChords();
69392
70379
  const atStop = captureTabs(
@@ -69401,6 +70388,7 @@ async function initializeBrowserHost(options, bindings) {
69401
70388
  );
69402
70389
  }
69403
70390
  sessionStore.flush();
70391
+ addressOverlay?.dispose("host-stop");
69404
70392
  registry.destroyAll();
69405
70393
  await Promise.allSettled([...releases]);
69406
70394
  await cdp.close();
@@ -70419,57 +71407,6 @@ class DesktopNotifier {
70419
71407
  notification.show();
70420
71408
  }
70421
71409
  }
70422
- const DEV_DRIVER_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER";
70423
- const DEV_DRIVER_OUT_ENV = "LOCAL_OPERATOR_UI_DEV_DRIVER_OUT";
70424
- const DEV_DRIVER_ARG = "--lo-dev-driver";
70425
- const DEV_DRIVER_CAPTURE = "dev-driver-capture";
70426
- const DEV_DRIVER_FACTS = "dev-driver-facts";
70427
- const TRUTHY = /* @__PURE__ */ new Set(["1", "true"]);
70428
- function readOptIn(env) {
70429
- const raw = env[DEV_DRIVER_ENV];
70430
- if (raw === void 0 || raw.trim() === "")
70431
- return { asked: false, value: null };
70432
- return { asked: true, value: raw.trim() };
70433
- }
70434
- function resolveDevDriverArming(input) {
70435
- const off = (problems = []) => ({
70436
- armed: false,
70437
- outDir: null,
70438
- problems
70439
- });
70440
- const optIn = readOptIn(input.env);
70441
- if (!optIn.asked) return off();
70442
- if (!TRUTHY.has(optIn.value.toLowerCase())) {
70443
- return off([
70444
- `${DEV_DRIVER_ENV}=${optIn.value} is not an opt-in (accepted: 1, true); the renderer dev driver stayed off`
70445
- ]);
70446
- }
70447
- if (input.windowMode !== "headless" && input.windowMode !== "inactive") {
70448
- return off([
70449
- `the renderer dev driver refused to arm in a "${input.windowMode}" window; it never raises one, so use --window-mode=headless (or inactive)`
70450
- ]);
70451
- }
70452
- const outDir = input.env[DEV_DRIVER_OUT_ENV]?.trim() ?? "";
70453
- if (outDir === "" || !outDir.startsWith("/")) {
70454
- return off([
70455
- `${DEV_DRIVER_ENV} was set but ${DEV_DRIVER_OUT_ENV} is ${outDir === "" ? "missing" : `"${outDir}"`}; an absolute frames directory is required, so the driver did not arm`
70456
- ]);
70457
- }
70458
- return { armed: true, outDir, problems: [] };
70459
- }
70460
- function headlessExerciserAllowed(input) {
70461
- return input.arming.armed && input.windowMode === "headless";
70462
- }
70463
- function devDriverArgument(outDir) {
70464
- return `${DEV_DRIVER_ARG}=${outDir}`;
70465
- }
70466
- function describeDevDriverArming(arming) {
70467
- if (arming.armed) {
70468
- return `[dev-driver] ARMED; frames are written to ${arming.outDir}`;
70469
- }
70470
- if (arming.problems.length === 0) return null;
70471
- return `[dev-driver] not armed: ${arming.problems.join("; ")}`;
70472
- }
70473
71410
  const FRAME_LABEL = /^[a-z0-9][a-z0-9_-]{0,63}$/;
70474
71411
  function registerDevDriverIPC(options) {
70475
71412
  const { window, expectedUrl, outDir, identity: identity2 } = options;
@@ -80764,6 +81701,16 @@ const devDriverArming = resolveDevDriverArming({
80764
81701
  });
80765
81702
  const devDriverLine = describeDevDriverArming(devDriverArming);
80766
81703
  if (devDriverLine) console.log(devDriverLine);
81704
+ const addressOverlayGate = resolveAddressOverlayGate({
81705
+ env: launchEnv,
81706
+ devDriverArmed: devDriverArming.armed,
81707
+ windowMode: windowLaunch.mode
81708
+ });
81709
+ if (addressOverlayGate.asked) {
81710
+ console.log(
81711
+ addressOverlayGate.enabled ? "[address-overlay] ARMED (S1 probe: native child, no product path)" : `[address-overlay] not armed: ${addressOverlayGate.reason}`
81712
+ );
81713
+ }
80767
81714
  const devDriverWebPreferences = devDriverArming.armed && devDriverArming.outDir ? { additionalArguments: [devDriverArgument(devDriverArming.outDir)] } : {};
80768
81715
  const telemetryWebPreferences = {
80769
81716
  additionalArguments: [telemetryArgument(telemetryLaunch.enabled)]
@@ -81167,6 +82114,7 @@ electron.app.whenReady().then(async () => {
81167
82114
  });
81168
82115
  const rendererUrl = rendererDocumentUrl();
81169
82116
  const consoleCaptureUrl = consoleCaptureUrlFor(rendererUrl);
82117
+ const addressOverlayDocumentUrl = addressOverlayDocumentUrlFor(rendererUrl);
81170
82118
  backendService.observeDesktopFeed(
81171
82119
  (frame) => {
81172
82120
  if (frame.type === "notification") {
@@ -81975,6 +82923,14 @@ electron.app.whenReady().then(async () => {
81975
82923
  // document, and the preload every renderer in this app gets, which is what
81976
82924
  // lets main feed the reconstruction to it.
81977
82925
  consoleCaptureUrl,
82926
+ // S1: only a gated headless probe arm gets this option at all. The
82927
+ // URL is this app's own packaged document, not a caller's string.
82928
+ ...addressOverlayGate.enabled ? {
82929
+ addressOverlay: {
82930
+ enabled: true,
82931
+ documentUrl: addressOverlayDocumentUrl
82932
+ }
82933
+ } : {},
81978
82934
  preloadPath: path$1.join(__dirname, "../preload/index.js"),
81979
82935
  /*
81980
82936
  * The console's surfaces are handed the user's own PATH, from the same