local-operator-ui 0.41.1 → 0.41.2

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 (80) hide show
  1. package/out/main/index.js +390 -26
  2. package/out/preload/index.js +19 -0
  3. package/out/renderer/assets/{_basePickBy-BP7Q8i4W.js → _basePickBy-BgapP5T6.js} +1 -1
  4. package/out/renderer/assets/{_baseUniq-D36dAcoY.js → _baseUniq-B9rnfho3.js} +1 -1
  5. package/out/renderer/assets/{agent-details-page-D3ljlPdf.js → agent-details-page-CKRUVtjJ.js} +1 -1
  6. package/out/renderer/assets/{agent-hub-page-BMyIHnNM.js → agent-hub-page-5qLVOZEV.js} +1 -1
  7. package/out/renderer/assets/{agents-page-mMqgQd2V.js → agents-page-tQooOOKH.js} +3 -3
  8. package/out/renderer/assets/{arc-GVvow4so.js → arc-Feq-cl9G.js} +1 -1
  9. package/out/renderer/assets/{architectureDiagram-IEHRJDOE-BjGwXAtH.js → architectureDiagram-IEHRJDOE-BmZeJuzA.js} +1 -1
  10. package/out/renderer/assets/{blockDiagram-JOT3LUYC-BTuigKlt.js → blockDiagram-JOT3LUYC-DEqkKuOE.js} +1 -1
  11. package/out/renderer/assets/{browser-page-B3mjDx8k.js → browser-page-CB-_usY1.js} +1 -1
  12. package/out/renderer/assets/{browser-webauthn-prompt-CzYoJfO4.js → browser-webauthn-prompt-CKUBOIHd.js} +1 -1
  13. package/out/renderer/assets/{c4Diagram-VJAJSXHY-DK7eaKE8.js → c4Diagram-VJAJSXHY-EbhUbSdf.js} +1 -1
  14. package/out/renderer/assets/channel-CPGK3lub.js +1 -0
  15. package/out/renderer/assets/{chunk-4BMEZGHF-DkQrsDhM.js → chunk-4BMEZGHF-DIk7XDrx.js} +1 -1
  16. package/out/renderer/assets/{chunk-A2AXSNBT-guh0INPR.js → chunk-A2AXSNBT-D_MflthZ.js} +1 -1
  17. package/out/renderer/assets/{chunk-AEK57VVT-DvgIx6-r.js → chunk-AEK57VVT-C0iLgwbv.js} +1 -1
  18. package/out/renderer/assets/{chunk-D6G4REZN-FNdvnFYo.js → chunk-D6G4REZN-BbFuFCzc.js} +1 -1
  19. package/out/renderer/assets/{chunk-RZ5BOZE2-CgCQC9Mn.js → chunk-RZ5BOZE2-BxQo8VeZ.js} +1 -1
  20. package/out/renderer/assets/{chunk-XZIHB7SX-D1VRTTc4.js → chunk-XZIHB7SX-DnNtYGsR.js} +1 -1
  21. package/out/renderer/assets/classDiagram-GIVACNV2-hDc6ku-l.js +1 -0
  22. package/out/renderer/assets/classDiagram-v2-COTLJTTW-hDc6ku-l.js +1 -0
  23. package/out/renderer/assets/clone--PuuOIog.js +1 -0
  24. package/out/renderer/assets/{console-mirror-DRkz3vUY.js → console-mirror-Bxl6t4e9.js} +1 -1
  25. package/out/renderer/assets/{consoleCapture-BJfSUatx.js → consoleCapture-BzSftKjg.js} +1 -1
  26. package/out/renderer/assets/{conversation-input-sync-CJU5GIzR.js → conversation-input-sync-MZPvyAzc.js} +239 -239
  27. package/out/renderer/assets/{dagre-OKDRZEBW-DeeYQh6O.js → dagre-OKDRZEBW-qejdp-TF.js} +1 -1
  28. package/out/renderer/assets/{diagram-SSKATNLV-DD-xNxKH.js → diagram-SSKATNLV-qHrLhzXc.js} +1 -1
  29. package/out/renderer/assets/{diagram-VNBRO52H-YAoPlXaR.js → diagram-VNBRO52H-q0teJTmh.js} +1 -1
  30. package/out/renderer/assets/{erDiagram-Q7BY3M3F-OKzGXyMI.js → erDiagram-Q7BY3M3F-DI6rp9FR.js} +1 -1
  31. package/out/renderer/assets/{flowDiagram-4HSFHLVR-BG-3pPqS.js → flowDiagram-4HSFHLVR-xVi21DAI.js} +1 -1
  32. package/out/renderer/assets/{ganttDiagram-APWFNJXF-CRyD5vsE.js → ganttDiagram-APWFNJXF-BUKGBOB_.js} +1 -1
  33. package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-aly2C__q.js → gitGraphDiagram-7IBYFJ6S-CdE3ZeMn.js} +1 -1
  34. package/out/renderer/assets/{graph-CCWwMmhg.js → graph-CRaHrZRK.js} +1 -1
  35. package/out/renderer/assets/{index-BaNzqqGN.js → index-B9E-fwX4.js} +1 -1
  36. package/out/renderer/assets/{index-CRjnV9wx.js → index-DknTGnAk.js} +208 -208
  37. package/out/renderer/assets/{index-DaCf2W9T.js → index-FsaxlHdZ.js} +1 -1
  38. package/out/renderer/assets/{infoDiagram-PH2N3AL5-BY536sF5.js → infoDiagram-PH2N3AL5-pOK9P20l.js} +1 -1
  39. package/out/renderer/assets/{journeyDiagram-U35MCT3I-DGvx__t6.js → journeyDiagram-U35MCT3I-D5Sg1JPA.js} +1 -1
  40. package/out/renderer/assets/{kanban-definition-NDS4AKOZ-CG2Lgkpw.js → kanban-definition-NDS4AKOZ-BfhWqBCl.js} +1 -1
  41. package/out/renderer/assets/{layout-vpRrwE7T.js → layout-IqsTm240.js} +1 -1
  42. package/out/renderer/assets/{legacy-agents-page-D6Yma1Gm.js → legacy-agents-page-bdH6oKjE.js} +5 -5
  43. package/out/renderer/assets/{library-page-B0gC-rRh.js → library-page-DDvrG_aA.js} +3 -3
  44. package/out/renderer/assets/{mermaid.core-COeGB8I0.js → mermaid.core-D0YPuNli.js} +5 -5
  45. package/out/renderer/assets/{mesh-page-PabU05tN.js → mesh-page-DYFNof_0.js} +1 -1
  46. package/out/renderer/assets/{mindmap-definition-ALO5MXBD-B0hkjZLY.js → mindmap-definition-ALO5MXBD-Tx5iMDRU.js} +1 -1
  47. package/out/renderer/assets/{mini-Df5C4rpd.js → mini-BoZCnSK9.js} +1 -1
  48. package/out/renderer/assets/{org-access-BacMtLkn.js → org-access-DoZK5gF3.js} +1 -1
  49. package/out/renderer/assets/{org-surface-gate-tkB025lu.js → org-surface-gate-Dy0B7mtt.js} +1 -1
  50. package/out/renderer/assets/path-utils-CRYGE4mK.js +58 -0
  51. package/out/renderer/assets/{pieDiagram-IB7DONF6-DfFtQXU5.js → pieDiagram-IB7DONF6-D0rED3_3.js} +1 -1
  52. package/out/renderer/assets/{projects-page-CoHTKLZH.js → projects-page-D7j1GOvI.js} +1 -1
  53. package/out/renderer/assets/{publication-validation-B0Mf3mmP.js → publication-validation-CLbFS0n9.js} +1 -1
  54. package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-C4eDJWaK.js → quadrantDiagram-7GDLP6J5-D8jKSQt5.js} +1 -1
  55. package/out/renderer/assets/{radar-MK3ICKWK-BEv1HS9Q.js → radar-MK3ICKWK-Co2EJbaJ.js} +1 -1
  56. package/out/renderer/assets/{radient-auth-buttons-BX5vf982.js → radient-auth-buttons-B11cdRmS.js} +1 -1
  57. package/out/renderer/assets/{requirementDiagram-KVF5MWMF-B7f3qUcB.js → requirementDiagram-KVF5MWMF-BI13h11j.js} +1 -1
  58. package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-xM7E-74l.js → sankeyDiagram-QLVOVGJD-D4hZ6_ML.js} +1 -1
  59. package/out/renderer/assets/{schedules-page-5q7pvL1H.js → schedules-page-DFfDDHYC.js} +1 -1
  60. package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-upwR02kU.js → sequenceDiagram-X6HHIX6F-U6CqBtco.js} +1 -1
  61. package/out/renderer/assets/{settings-page-DcnGr-GP.js → settings-page-CZ7NUDoe.js} +9 -9
  62. package/out/renderer/assets/{smartart-CYnMNs5u.js → smartart-BVm_cEaq.js} +1 -1
  63. package/out/renderer/assets/{stateDiagram-DGXRK772-BqTri7Q-.js → stateDiagram-DGXRK772-DBg11bkx.js} +1 -1
  64. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-jmaink9i.js +1 -0
  65. package/out/renderer/assets/team-bridge-page-u_OqiZGS.js +16 -0
  66. package/out/renderer/assets/{timeline-definition-BDJGKUSR-Bi2is17s.js → timeline-definition-BDJGKUSR-WQ6aYia6.js} +1 -1
  67. package/out/renderer/assets/{use-download-agent-mutation-PHtokPlg.js → use-download-agent-mutation-ZoivWizY.js} +2 -2
  68. package/out/renderer/assets/{use-session-snapshot-B5sxthdQ.js → use-session-snapshot-CdYiirKJ.js} +1 -1
  69. package/out/renderer/assets/{xychartDiagram-VJFVF3MP-B0TrjzLJ.js → xychartDiagram-VJFVF3MP-f11BpHer.js} +1 -1
  70. package/out/renderer/console-capture.html +3 -3
  71. package/out/renderer/index.html +4 -4
  72. package/out/renderer/mini.html +4 -4
  73. package/package.json +4 -3
  74. package/out/renderer/assets/channel-B05rL6In.js +0 -1
  75. package/out/renderer/assets/classDiagram-GIVACNV2-DpB8-8cT.js +0 -1
  76. package/out/renderer/assets/classDiagram-v2-COTLJTTW-DpB8-8cT.js +0 -1
  77. package/out/renderer/assets/clone-BHHjv3HP.js +0 -1
  78. package/out/renderer/assets/path-utils-Ct0VTUZS.js +0 -58
  79. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-D8Sl1QhX.js +0 -1
  80. package/out/renderer/assets/team-bridge-page-vnNJdCi3.js +0 -16
package/out/main/index.js CHANGED
@@ -2423,6 +2423,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2423
2423
  }).strict(),
2424
2424
  zod.z.object({
2425
2425
  op: zod.z.literal("team_bridge.conversations.create"),
2426
+ expected_account_id: id$1.optional(),
2426
2427
  tenant_id: id$1.optional(),
2427
2428
  kind: zod.z.enum(["dm", "group", "channel"]),
2428
2429
  name: zod.z.string().min(1).max(128).optional(),
@@ -2440,6 +2441,8 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2440
2441
  }).strict(),
2441
2442
  zod.z.object({
2442
2443
  op: zod.z.literal("team_bridge.conversations.lifecycle"),
2444
+ expected_account_id: id$1.optional(),
2445
+ tenant_id: id$1.optional(),
2443
2446
  conversation_id: id$1,
2444
2447
  action: zod.z.enum(["archive", "unarchive", "join", "leave"])
2445
2448
  }).strict(),
@@ -2456,17 +2459,20 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2456
2459
  */
2457
2460
  zod.z.object({
2458
2461
  op: zod.z.literal("team_bridge.conversations.join"),
2462
+ expected_account_id: id$1.optional(),
2459
2463
  conversation_id: id$1,
2460
2464
  tenant_id: id$1.optional()
2461
2465
  }).strict(),
2462
2466
  zod.z.object({
2463
2467
  op: zod.z.literal("team_bridge.conversations.notify"),
2468
+ expected_account_id: id$1.optional(),
2464
2469
  conversation_id: id$1,
2465
2470
  tenant_id: id$1.optional(),
2466
2471
  notify: zod.z.enum(["all", "mention", "mute"])
2467
2472
  }).strict(),
2468
2473
  zod.z.object({
2469
2474
  op: zod.z.literal("team_bridge.conversations.members.add"),
2475
+ expected_account_id: id$1.optional(),
2470
2476
  conversation_id: id$1,
2471
2477
  tenant_id: id$1.optional(),
2472
2478
  members: zod.z.array(
@@ -2480,11 +2486,14 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2480
2486
  }).strict(),
2481
2487
  zod.z.object({
2482
2488
  op: zod.z.literal("team_bridge.conversations.members.remove"),
2489
+ expected_account_id: id$1.optional(),
2490
+ tenant_id: id$1.optional(),
2483
2491
  conversation_id: id$1,
2484
2492
  account_id: id$1
2485
2493
  }).strict(),
2486
2494
  zod.z.object({
2487
2495
  op: zod.z.literal("team_bridge.conversations.consent"),
2496
+ expected_account_id: id$1.optional(),
2488
2497
  conversation_id: id$1,
2489
2498
  account_id: id$1,
2490
2499
  decision: zod.z.enum(["accept", "decline"]),
@@ -2509,6 +2518,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2509
2518
  }).strict(),
2510
2519
  zod.z.object({
2511
2520
  op: zod.z.literal("team_bridge.messages.send"),
2521
+ expected_account_id: id$1.optional(),
2512
2522
  conversation_id: id$1,
2513
2523
  tenant_id: id$1.optional(),
2514
2524
  client_ref: id$1,
@@ -2531,6 +2541,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
2531
2541
  }).strict(),
2532
2542
  zod.z.object({
2533
2543
  op: zod.z.literal("team_bridge.read"),
2544
+ expected_account_id: id$1.optional(),
2534
2545
  conversation_id: id$1,
2535
2546
  tenant_id: id$1.optional(),
2536
2547
  seq: zod.z.number().int().nonnegative().optional(),
@@ -3058,6 +3069,14 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
3058
3069
  ]);
3059
3070
  const desktopRequestSchema = desktopRequestUnion.superRefine(
3060
3071
  (request, ctx) => {
3072
+ if (request.op.startsWith("team_bridge.") && "expected_account_id" in request && request.expected_account_id && (!("tenant_id" in request) || !request.tenant_id)) {
3073
+ ctx.addIssue({
3074
+ code: zod.z.ZodIssueCode.custom,
3075
+ path: ["tenant_id"],
3076
+ message: "Guarded conversation writes require an explicit tenant"
3077
+ });
3078
+ return;
3079
+ }
3061
3080
  if (request.op === "hub.skillPull" || request.op === "hub.skillSubscribe" || request.op === "hub.skillPublish") {
3062
3081
  if (request.visibility === "public" && request.tenantId !== null || request.visibility === "org" && !request.tenantId) {
3063
3082
  ctx.addIssue({
@@ -3631,6 +3650,13 @@ function harnessImportBody(request) {
3631
3650
  ...request.maxSessions === void 0 ? {} : { max_sessions: request.maxSessions }
3632
3651
  };
3633
3652
  }
3653
+ function conversationOwnerQuery(request) {
3654
+ const query = new URLSearchParams();
3655
+ if (request.tenant_id) query.set("tenant_id", request.tenant_id);
3656
+ if (request.expected_account_id)
3657
+ query.set("expected_account_id", request.expected_account_id);
3658
+ return query.size ? `?${query.toString()}` : "";
3659
+ }
3634
3660
  function tenantQuery(tenantId) {
3635
3661
  return tenantId === void 0 ? "" : `?tenant_id=${encodeURIComponent(tenantId)}`;
3636
3662
  }
@@ -5026,6 +5052,7 @@ function desktopEndpoint(request) {
5026
5052
  path: "/v1/desktop/team-bridge/conversations",
5027
5053
  method: "POST",
5028
5054
  body: {
5055
+ ...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
5029
5056
  ...request.tenant_id ? { tenant_id: request.tenant_id } : {},
5030
5057
  kind: request.kind,
5031
5058
  ...request.name ? { name: request.name } : {},
@@ -5037,14 +5064,25 @@ function desktopEndpoint(request) {
5037
5064
  };
5038
5065
  case "team_bridge.conversations.lifecycle":
5039
5066
  return {
5040
- path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/${request.action}`,
5041
- method: "POST"
5067
+ path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/${request.action}${request.action === "join" ? "" : conversationOwnerQuery(request)}`,
5068
+ method: "POST",
5069
+ ...request.action === "join" && (request.tenant_id || request.expected_account_id) ? {
5070
+ body: {
5071
+ ...request.tenant_id ? { tenant_id: request.tenant_id } : {},
5072
+ ...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {}
5073
+ }
5074
+ } : {}
5042
5075
  };
5043
5076
  case "team_bridge.conversations.join":
5044
5077
  return {
5045
5078
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/join`,
5046
5079
  method: "POST",
5047
- ...request.tenant_id ? { body: { tenant_id: request.tenant_id } } : {}
5080
+ ...request.tenant_id || request.expected_account_id ? {
5081
+ body: {
5082
+ ...request.tenant_id ? { tenant_id: request.tenant_id } : {},
5083
+ ...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {}
5084
+ }
5085
+ } : {}
5048
5086
  };
5049
5087
  case "team_bridge.conversations.notify":
5050
5088
  return {
@@ -5053,6 +5091,7 @@ function desktopEndpoint(request) {
5053
5091
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/read`,
5054
5092
  method: "POST",
5055
5093
  body: {
5094
+ ...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
5056
5095
  ...request.tenant_id ? { tenant_id: request.tenant_id } : {},
5057
5096
  notify: request.notify
5058
5097
  }
@@ -5060,6 +5099,8 @@ function desktopEndpoint(request) {
5060
5099
  case "team_bridge.conversations.members.add": {
5061
5100
  const query = new URLSearchParams();
5062
5101
  if (request.tenant_id) query.set("tenant_id", request.tenant_id);
5102
+ if (request.expected_account_id)
5103
+ query.set("expected_account_id", request.expected_account_id);
5063
5104
  const suffix = query.size > 0 ? `?${query.toString()}` : "";
5064
5105
  return {
5065
5106
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members${suffix}`,
@@ -5069,7 +5110,7 @@ function desktopEndpoint(request) {
5069
5110
  }
5070
5111
  case "team_bridge.conversations.members.remove":
5071
5112
  return {
5072
- path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members/${encodeURIComponent(request.account_id)}`,
5113
+ path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members/${encodeURIComponent(request.account_id)}${conversationOwnerQuery(request)}`,
5073
5114
  method: "DELETE"
5074
5115
  };
5075
5116
  case "team_bridge.conversations.consent":
@@ -5077,6 +5118,7 @@ function desktopEndpoint(request) {
5077
5118
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members/${encodeURIComponent(request.account_id)}/consent`,
5078
5119
  method: "POST",
5079
5120
  body: {
5121
+ ...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
5080
5122
  ...request.tenant_id ? { tenant_id: request.tenant_id } : {},
5081
5123
  decision: request.decision,
5082
5124
  consent_version: request.consent_version
@@ -5112,6 +5154,7 @@ function desktopEndpoint(request) {
5112
5154
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/messages`,
5113
5155
  method: "POST",
5114
5156
  body: {
5157
+ ...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
5115
5158
  ...request.tenant_id ? { tenant_id: request.tenant_id } : {},
5116
5159
  client_ref: request.client_ref,
5117
5160
  body: request.body,
@@ -5137,6 +5180,7 @@ function desktopEndpoint(request) {
5137
5180
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/read`,
5138
5181
  method: "POST",
5139
5182
  body: {
5183
+ ...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
5140
5184
  ...request.tenant_id ? { tenant_id: request.tenant_id } : {},
5141
5185
  ...request.seq === void 0 ? {} : { seq: request.seq },
5142
5186
  ...request.muted === void 0 ? {} : { muted: request.muted }
@@ -64806,6 +64850,158 @@ function pageOf(view) {
64806
64850
  title: view.webContents.isDestroyed() ? "" : view.webContents.getTitle()
64807
64851
  };
64808
64852
  }
64853
+ const LABELLABLE = /* @__PURE__ */ new Set([
64854
+ "checkbox",
64855
+ "radio",
64856
+ "switch",
64857
+ "textbox",
64858
+ "searchbox",
64859
+ "combobox",
64860
+ "listbox",
64861
+ "spinbutton",
64862
+ "slider",
64863
+ "button"
64864
+ ]);
64865
+ const CLICKABLE = /* @__PURE__ */ new Set([
64866
+ "button",
64867
+ "link",
64868
+ "menuitem",
64869
+ "menuitemcheckbox",
64870
+ "menuitemradio",
64871
+ "tab",
64872
+ "option",
64873
+ "treeitem",
64874
+ "DisclosureTriangle",
64875
+ "checkbox",
64876
+ "radio",
64877
+ "switch"
64878
+ ]);
64879
+ function normalise(value) {
64880
+ return String(value ?? "").replace(/\s+/g, " ").trim();
64881
+ }
64882
+ function readValue(raw) {
64883
+ const text = raw.trim();
64884
+ if (!text) return null;
64885
+ const quote = text[0];
64886
+ if (quote === '"' || quote === "'") {
64887
+ let value = "";
64888
+ for (let index = 1; index < text.length; index += 1) {
64889
+ const char = text[index] ?? "";
64890
+ if (char === "\\" && index + 1 < text.length) {
64891
+ value += text[index + 1] ?? "";
64892
+ index += 1;
64893
+ continue;
64894
+ }
64895
+ if (char === quote) {
64896
+ return index === text.length - 1 ? value : null;
64897
+ }
64898
+ value += char;
64899
+ }
64900
+ return null;
64901
+ }
64902
+ if (/[\[\]]/.test(text) || text.startsWith("*")) return null;
64903
+ return text;
64904
+ }
64905
+ function parseLocator(value) {
64906
+ const text = value.trim();
64907
+ const match = /^(role|label|text)(\*?)=([\s\S]+)$/i.exec(text);
64908
+ if (!match) return null;
64909
+ const kind = (match[1] ?? "").toLowerCase();
64910
+ const prefixSubstring = match[2] === "*";
64911
+ const rest = (match[3] ?? "").trim();
64912
+ if (kind === "role") {
64913
+ const roleMatch = /^([A-Za-z][A-Za-z0-9_-]*)\s*(?:\[\s*name(\*?)=\s*([\s\S]+?)\s*\])?$/.exec(rest);
64914
+ if (!roleMatch) return null;
64915
+ const role = roleMatch[1] ?? "";
64916
+ const substring = roleMatch[2] === "*";
64917
+ const rawName = roleMatch[3];
64918
+ const name2 = rawName === void 0 ? "" : readValue(rawName);
64919
+ if (name2 === null) return null;
64920
+ return { kind: "role", role: role.toLowerCase(), name: name2, substring };
64921
+ }
64922
+ const name = readValue(rest);
64923
+ if (name === null) return null;
64924
+ return { kind: kind === "label" ? "label" : "text", name, substring: prefixSubstring };
64925
+ }
64926
+ function matches(haystack, needle, substring) {
64927
+ const left = normalise(haystack).toLowerCase();
64928
+ const right = normalise(needle).toLowerCase();
64929
+ if (!right) return false;
64930
+ return substring ? left.includes(right) : left === right;
64931
+ }
64932
+ function candidateNodes(nodes) {
64933
+ return nodes.filter((node) => !node.ignored && node.backendDOMNodeId !== void 0);
64934
+ }
64935
+ function resolveLocator(nodes, locator) {
64936
+ const pool = candidateNodes(nodes);
64937
+ const hits = [];
64938
+ const consider = (role, name) => {
64939
+ if (locator.kind === "role") {
64940
+ if (role.toLowerCase() !== locator.role) return false;
64941
+ if (locator.name && !matches(name, locator.name, locator.substring)) return false;
64942
+ return true;
64943
+ }
64944
+ return matches(name, locator.name, locator.substring);
64945
+ };
64946
+ const collect = (accept) => {
64947
+ for (const node of pool) {
64948
+ const role = String(node.role?.value ?? "");
64949
+ const name = normalise(node.name?.value);
64950
+ if (!accept(role)) continue;
64951
+ if (!consider(role, name)) continue;
64952
+ hits.push({ backendNodeId: node.backendDOMNodeId, role, name, matched: 0 });
64953
+ }
64954
+ };
64955
+ if (locator.kind === "role") {
64956
+ collect(() => true);
64957
+ } else if (locator.kind === "label") {
64958
+ collect((role) => LABELLABLE.has(role));
64959
+ if (!hits.length) collect((role) => CLICKABLE.has(role));
64960
+ } else {
64961
+ collect((role) => CLICKABLE.has(role));
64962
+ if (!hits.length) collect(() => true);
64963
+ }
64964
+ const first = hits[0];
64965
+ if (!first) return null;
64966
+ return { ...first, matched: hits.length };
64967
+ }
64968
+ function locatorSuggestions(nodes, query, limit = 5) {
64969
+ const wanted = normalise(query).toLowerCase();
64970
+ const parsed = parseLocator(query);
64971
+ const term = parsed ? parsed.name.toLowerCase() : wanted;
64972
+ const words = term.split(/[^a-z0-9]+/).filter((word) => word.length > 1);
64973
+ const wantedRole = parsed && parsed.kind === "role" ? parsed.role : "";
64974
+ const scored = [];
64975
+ for (const node of candidateNodes(nodes)) {
64976
+ const role = String(node.role?.value ?? "");
64977
+ const name = normalise(node.name?.value);
64978
+ if (!name) continue;
64979
+ const lowerName = name.toLowerCase();
64980
+ let score = 0;
64981
+ if (term && lowerName === term) score += 100;
64982
+ else if (term && lowerName.includes(term)) score += 60;
64983
+ for (const word of words) if (lowerName.includes(word)) score += 8;
64984
+ if (wantedRole && role.toLowerCase() === wantedRole) score += 25;
64985
+ if (CLICKABLE.has(role)) score += 4;
64986
+ if (!score) continue;
64987
+ scored.push({ score, role, name });
64988
+ }
64989
+ scored.sort((left, right) => right.score - left.score || left.name.localeCompare(right.name));
64990
+ const seen = /* @__PURE__ */ new Set();
64991
+ const out = [];
64992
+ for (const entry of scored) {
64993
+ const key = `${entry.role}\0${entry.name}`;
64994
+ if (seen.has(key)) continue;
64995
+ seen.add(key);
64996
+ out.push({ role: entry.role, name: entry.name, locator: locatorFor(entry.role, entry.name) });
64997
+ if (out.length >= limit) break;
64998
+ }
64999
+ return out;
65000
+ }
65001
+ function locatorFor(role, name) {
65002
+ const quoted = name.includes('"') && !name.includes("'") ? `'${name.replace(/\\/g, "\\\\")}'` : JSON.stringify(name);
65003
+ return role && /^[A-Za-z][A-Za-z0-9_-]*$/.test(role) ? `role=${role}[name=${quoted}]` : `text=${quoted}`;
65004
+ }
64809
65005
  const FRAME_HOP = ">>>";
64810
65006
  const MAX_FRAME_DEPTH = 3;
64811
65007
  const MAX_FRAMES_SEARCHED = 20;
@@ -65056,7 +65252,7 @@ async function resolveHops(ctx, contents, hops) {
65056
65252
  return { scope, nodeId };
65057
65253
  }
65058
65254
  async function searchFrames(ctx, contents, selector) {
65059
- const matches = [];
65255
+ const matches2 = [];
65060
65256
  const walk = await listFrames(ctx, contents);
65061
65257
  for (const scope of walk.frames) {
65062
65258
  const nodeId = await queryIn(ctx, contents, scope, selector).catch(
@@ -65065,9 +65261,9 @@ async function searchFrames(ctx, contents, selector) {
65065
65261
  return 0;
65066
65262
  }
65067
65263
  );
65068
- if (nodeId) matches.push({ scope, nodeId });
65264
+ if (nodeId) matches2.push({ scope, nodeId });
65069
65265
  }
65070
- return { matches, walk };
65266
+ return { matches: matches2, walk };
65071
65267
  }
65072
65268
  async function listFrames(ctx, contents) {
65073
65269
  const walk = {
@@ -65202,24 +65398,46 @@ async function editableInFrame(ctx, contents, scope, target2) {
65202
65398
  }
65203
65399
  const LANDMARKS = /* @__PURE__ */ new Set(["banner", "main", "navigation", "complementary", "contentinfo", "form", "region"]);
65204
65400
  const INTERACTIVE = /* @__PURE__ */ new Set(["button", "link", "textbox", "checkbox", "radio", "combobox", "menuitem", "tab", "switch", "slider", "spinbutton"]);
65205
- function compactAX(nodes, epoch) {
65401
+ function stateSuffix(node) {
65402
+ const truthy = (value) => value === true || value === "true";
65403
+ const falsy = (value) => value === false || value === "false";
65404
+ const property = (name) => node.properties?.find((entry) => entry.name === name)?.value.value;
65405
+ const markers = [];
65406
+ if (falsy(property("expanded"))) markers.push("collapsed");
65407
+ const checked = property("checked");
65408
+ if (truthy(checked)) markers.push("checked");
65409
+ else if (checked === "mixed") markers.push("mixed");
65410
+ if (truthy(property("disabled"))) markers.push("disabled");
65411
+ return markers.length ? ` [${markers.join("] [")}]` : "";
65412
+ }
65413
+ function compactAX(nodes, epoch, options = {}) {
65206
65414
  const byId = new Map(nodes.map((node) => [node.nodeId, node]));
65207
65415
  const refs = {};
65208
65416
  const lines = [];
65209
65417
  let sequence = 0;
65418
+ const scopeId = options.rootBackendNodeId;
65419
+ let scopeAt = null;
65420
+ let framesInScope = 0;
65210
65421
  const visited = /* @__PURE__ */ new Set();
65211
65422
  function visit2(node, depth) {
65212
65423
  if (visited.has(node.nodeId)) return;
65213
65424
  visited.add(node.nodeId);
65425
+ const savedScope = scopeAt;
65426
+ if (scopeAt === null && scopeId !== void 0 && node.backendDOMNodeId === scopeId) {
65427
+ scopeAt = depth;
65428
+ }
65429
+ const inside2 = scopeId === void 0 || scopeAt !== null && depth >= scopeAt;
65214
65430
  if (node.ignored) {
65215
65431
  for (const child of node.childIds ?? []) {
65216
65432
  const found = byId.get(child);
65217
65433
  if (found) visit2(found, depth);
65218
65434
  }
65435
+ scopeAt = savedScope;
65219
65436
  return;
65220
65437
  }
65221
65438
  const role = String(node.role?.value ?? "");
65222
65439
  const name = String(node.name?.value ?? "").trim();
65440
+ if (inside2 && role === "Iframe") framesInScope += 1;
65223
65441
  const focusable = node.properties?.some((property) => property.name === "focusable" && property.value.value === true);
65224
65442
  const interesting = INTERACTIVE.has(role) || LANDMARKS.has(role) || focusable || Boolean(name && role !== "StaticText");
65225
65443
  if (interesting) {
@@ -65228,16 +65446,54 @@ function compactAX(nodes, epoch) {
65228
65446
  ref = `e${++sequence}`;
65229
65447
  refs[ref] = { backendNodeId: node.backendDOMNodeId, epoch };
65230
65448
  }
65231
- lines.push(`${" ".repeat(depth)}- ${role || "node"}${name ? ` ${JSON.stringify(name)}` : ""}${ref ? ` [${ref}]` : ""}`);
65449
+ if (inside2) {
65450
+ const shown = depth - (scopeAt ?? 0);
65451
+ lines.push(`${" ".repeat(shown)}- ${role || "node"}${name ? ` ${JSON.stringify(name)}` : ""}${ref ? ` [${ref}]` : ""}${stateSuffix(node)}`);
65452
+ }
65232
65453
  }
65233
65454
  for (const child of node.childIds ?? []) {
65234
65455
  const found = byId.get(child);
65235
65456
  if (found) visit2(found, interesting ? depth + 1 : depth);
65236
65457
  }
65458
+ scopeAt = savedScope;
65459
+ }
65460
+ const scopedRoot = scopeId === void 0 ? void 0 : nodes.find((node) => node.backendDOMNodeId === scopeId);
65461
+ if (scopeId !== void 0 && scopedRoot === void 0) {
65462
+ return { snapshot: "", refs, framesInScope: 0, totalLines: 0, scoped: false };
65237
65463
  }
65238
65464
  const childIds = new Set(nodes.flatMap((node) => node.childIds ?? []));
65239
65465
  for (const root of nodes.filter((node) => !childIds.has(node.nodeId))) visit2(root, 0);
65240
- return { snapshot: lines.join("\n"), refs };
65466
+ return {
65467
+ snapshot: lines.join("\n"),
65468
+ refs,
65469
+ // Unscoped means "the whole page", and every frame is then read by the
65470
+ // caller's own frame walk: the count exists only to explain a SCOPE.
65471
+ framesInScope: scopeId === void 0 ? 0 : framesInScope,
65472
+ totalLines: lines.length,
65473
+ scoped: scopeId !== void 0
65474
+ };
65475
+ }
65476
+ function windowSnapshot(text, options = {}) {
65477
+ const lines = text ? text.split("\n").filter((line) => line.length > 0) : [];
65478
+ const totalLines = lines.length;
65479
+ const search = String(options.search ?? "").trim();
65480
+ const matched = search ? lines.filter((line) => line.toLowerCase().includes(search.toLowerCase())) : lines;
65481
+ const matchedLines = matched.length;
65482
+ const requested = Number(options.start ?? 1);
65483
+ const start = Number.isFinite(requested) && requested >= 1 ? Math.floor(requested) : 1;
65484
+ const rawLimit = Number(options.limit ?? 0);
65485
+ const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.floor(rawLimit) : 0;
65486
+ const end = limit ? start - 1 + limit : matchedLines;
65487
+ const page = matched.slice(start - 1, end);
65488
+ return {
65489
+ text: page.join("\n"),
65490
+ totalLines,
65491
+ matchedLines,
65492
+ returnedLines: page.length,
65493
+ start,
65494
+ limit,
65495
+ search
65496
+ };
65241
65497
  }
65242
65498
  const PAGE_OVERLAP_PX = 80;
65243
65499
  function defaultScrollExpression() {
@@ -65317,6 +65573,8 @@ async function read(ctx, params) {
65317
65573
  async function snapshot(ctx, params) {
65318
65574
  const record = ctx.registry.requireSurface(params.tab);
65319
65575
  const contents = record.view.webContents;
65576
+ const scope = stringParam(params, "selector");
65577
+ const rootBackendNodeId = scope ? await backendNodeIdForSelector(ctx, record.view, scope) : void 0;
65320
65578
  await ctx.cdp.send(contents, "Accessibility.enable", {});
65321
65579
  let nodes = [];
65322
65580
  try {
@@ -65330,22 +65588,49 @@ async function snapshot(ctx, params) {
65330
65588
  await ctx.cdp.send(contents, "Accessibility.disable", {}).catch(() => {
65331
65589
  });
65332
65590
  }
65333
- const { snapshot: topRendered, refs: topRefs } = compactAX(
65334
- nodes,
65335
- record.epoch
65336
- );
65591
+ const {
65592
+ snapshot: topRendered,
65593
+ refs: topRefs,
65594
+ scoped,
65595
+ framesInScope
65596
+ } = compactAX(nodes, record.epoch, { rootBackendNodeId });
65597
+ if (rootBackendNodeId !== void 0 && !scoped) {
65598
+ throw new BridgeCommandError(
65599
+ "element_not_found",
65600
+ `selector ${scope} matched an element with no accessibility subtree (hidden, aria-hidden, or inside a collapsed section); expand it first, then snapshot again`
65601
+ );
65602
+ }
65337
65603
  const refs = { ...topRefs };
65338
65604
  let rendered = topRendered;
65339
- if (nodes.some(isFrameNode)) {
65605
+ if (!scope && nodes.some(isFrameNode)) {
65340
65606
  const blocks = await frameSnapshots(ctx, record, nodes, refs);
65341
65607
  if (blocks.length) rendered = [rendered, ...blocks].join("\n");
65342
65608
  }
65343
65609
  record.refs = refs;
65344
65610
  ctx.registry.touch(record);
65611
+ let note = "";
65612
+ if (scope && framesInScope > 0) {
65613
+ const frames = framesInScope;
65614
+ note = `
65615
+ - (a scoped snapshot does not read frames: this section contains ${frames} frame${frames === 1 ? "" : "s"}; snapshot without selector= for their contents)`;
65616
+ }
65617
+ const page = windowSnapshot(rendered, {
65618
+ search: stringParam(params, "search"),
65619
+ start: numberParam(params, "start") ?? 1,
65620
+ limit: numberParam(params, "limit") ?? 0
65621
+ });
65345
65622
  return {
65346
- snapshot: rendered,
65623
+ snapshot: page.text + note,
65347
65624
  refs: Object.keys(refs).length,
65348
65625
  epoch: record.epoch,
65626
+ scoped,
65627
+ frames_in_scope: framesInScope,
65628
+ total_lines: page.totalLines,
65629
+ matched_lines: page.matchedLines,
65630
+ returned_lines: page.returnedLines,
65631
+ start: page.start,
65632
+ limit: page.limit,
65633
+ search: page.search,
65349
65634
  ...pageOf(record.view)
65350
65635
  };
65351
65636
  }
@@ -65596,6 +65881,22 @@ async function nodeIdForSelector(ctx, view, selector) {
65596
65881
  }
65597
65882
  return queried.nodeId;
65598
65883
  }
65884
+ async function backendNodeIdForSelector(ctx, view, selector) {
65885
+ const nodeId = await nodeIdForSelector(ctx, view, selector);
65886
+ const described = await ctx.cdp.send(
65887
+ view.webContents,
65888
+ "DOM.describeNode",
65889
+ { nodeId, depth: 0 }
65890
+ );
65891
+ const backendNodeId = described?.node?.backendNodeId;
65892
+ if (backendNodeId === void 0) {
65893
+ throw new BridgeCommandError(
65894
+ "element_not_found",
65895
+ `selector ${selector} has no backend node id`
65896
+ );
65897
+ }
65898
+ return backendNodeId;
65899
+ }
65599
65900
  const CLICK_FUNCTION = `function () {
65600
65901
  const r = this.getBoundingClientRect();
65601
65902
  const cx = r.left + r.width / 2, cy = r.top + r.height / 2;
@@ -65694,9 +65995,33 @@ const READ_VALUE_FUNCTION = `function () {
65694
65995
  return String(this.textContent || '');
65695
65996
  }`;
65696
65997
  const SNAPSHOT_REF = /^e\d+$/;
65998
+ function resolvedFields(node) {
65999
+ return node.resolvedBy === "locator" ? {
66000
+ resolved: {
66001
+ by: "locator",
66002
+ role: node.role ?? "",
66003
+ name: node.name ?? "",
66004
+ matched: node.matched ?? 1
66005
+ }
66006
+ } : {};
66007
+ }
65697
66008
  function frameFields(node) {
65698
66009
  return node.frame ? { frame_origin: node.frame.origin ?? "" } : {};
65699
66010
  }
66011
+ async function readAccessibilityTree(ctx, contents) {
66012
+ await ctx.cdp.send(contents, "Accessibility.enable", {});
66013
+ try {
66014
+ const tree = await ctx.cdp.send(
66015
+ contents,
66016
+ "Accessibility.getFullAXTree",
66017
+ {}
66018
+ );
66019
+ return Array.isArray(tree?.nodes) ? tree.nodes : [];
66020
+ } finally {
66021
+ await ctx.cdp.send(contents, "Accessibility.disable", {}).catch(() => {
66022
+ });
66023
+ }
66024
+ }
65700
66025
  async function resolveNode(ctx, record, target2) {
65701
66026
  const view = record.view;
65702
66027
  const contents = view.webContents;
@@ -65721,6 +66046,39 @@ async function resolveNode(ctx, record, target2) {
65721
66046
  }
65722
66047
  return finishTop(ctx, contents, target2, pushedId, ref.frameOrigin);
65723
66048
  }
66049
+ const locator = parseLocator(target2);
66050
+ if (locator) {
66051
+ const nodes = await readAccessibilityTree(ctx, contents);
66052
+ const hit = resolveLocator(nodes, locator);
66053
+ if (!hit) {
66054
+ throw new BridgeCommandError(
66055
+ "element_not_found",
66056
+ `no element matches ${target2}`,
66057
+ { candidates: locatorSuggestions(nodes, target2), matched: 0 }
66058
+ );
66059
+ }
66060
+ await ctx.cdp.send(contents, "DOM.getDocument", { depth: 0 });
66061
+ const pushed = await ctx.cdp.send(
66062
+ contents,
66063
+ "DOM.pushNodesByBackendIdsToFrontend",
66064
+ { backendNodeIds: [hit.backendNodeId] }
66065
+ );
66066
+ const nodeId2 = pushed?.nodeIds?.[0];
66067
+ if (nodeId2 === void 0) {
66068
+ throw new BridgeCommandError(
66069
+ "element_not_found",
66070
+ `${target2} is no longer in the document`
66071
+ );
66072
+ }
66073
+ const resolved = await finishTop(ctx, contents, target2, nodeId2);
66074
+ return {
66075
+ ...resolved,
66076
+ resolvedBy: "locator",
66077
+ role: hit.role,
66078
+ name: hit.name,
66079
+ matched: hit.matched
66080
+ };
66081
+ }
65724
66082
  const hops = parseFrameHops(target2);
65725
66083
  if (hops) {
65726
66084
  const hit = await resolveHops(ctx, contents, hops);
@@ -65733,8 +66091,8 @@ async function resolveNode(ctx, record, target2) {
65733
66091
  if (!(error instanceof BridgeCommandError) || !TOP_MISS.test(error.message)) {
65734
66092
  throw error;
65735
66093
  }
65736
- const { matches, walk } = await searchFrames(ctx, contents, target2);
65737
- if (matches.length === 0) {
66094
+ const { matches: matches2, walk } = await searchFrames(ctx, contents, target2);
66095
+ if (matches2.length === 0) {
65738
66096
  if (!walk.truncated && walk.skipped === 0 && walk.denied === 0)
65739
66097
  throw error;
65740
66098
  throw new BridgeCommandError(
@@ -65742,21 +66100,21 @@ async function resolveNode(ctx, record, target2) {
65742
66100
  `selector ${target2} matched nothing in the page itself or the frames searched (${walkNote(walk)}); address the frame explicitly as <iframe-selector> ${FRAME_HOP} <selector>`
65743
66101
  );
65744
66102
  }
65745
- if (matches.length === 1 && (walk.truncated || walk.skipped > 0)) {
65746
- const candidate = candidatePath(matches[0].scope, target2);
66103
+ if (matches2.length === 1 && (walk.truncated || walk.skipped > 0)) {
66104
+ const candidate = candidatePath(matches2[0].scope, target2);
65747
66105
  throw new BridgeCommandError(
65748
66106
  "element_not_found",
65749
66107
  `selector ${target2} matched nothing in the page itself and one element in the frames searched, but not every frame was searched (${walkNote(walk)}), so nothing was done; if this is the one, name it: ${candidate}`,
65750
66108
  { candidates: [candidate] }
65751
66109
  );
65752
66110
  }
65753
- if (matches.length > 1) {
65754
- const candidates = matches.map(
66111
+ if (matches2.length > 1) {
66112
+ const candidates = matches2.map(
65755
66113
  (match) => candidatePath(match.scope, target2)
65756
66114
  );
65757
66115
  throw new BridgeCommandError(
65758
66116
  "element_not_found",
65759
- `selector ${target2} matched nothing in the page itself and ${matches.length} elements inside its frames, so nothing was done; name one: ${candidates.join(", ")}`,
66117
+ `selector ${target2} matched nothing in the page itself and ${matches2.length} elements inside its frames, so nothing was done; name one: ${candidates.join(", ")}`,
65760
66118
  { candidates }
65761
66119
  );
65762
66120
  }
@@ -65764,8 +66122,8 @@ async function resolveNode(ctx, record, target2) {
65764
66122
  ctx,
65765
66123
  contents,
65766
66124
  target2,
65767
- matches[0].scope,
65768
- matches[0].nodeId
66125
+ matches2[0].scope,
66126
+ matches2[0].nodeId
65769
66127
  );
65770
66128
  }
65771
66129
  return finishTop(ctx, contents, target2, nodeId);
@@ -65918,6 +66276,7 @@ async function click(ctx, params) {
65918
66276
  return {
65919
66277
  navigated: navigationSeen || after.url !== before,
65920
66278
  ...frameFields(node),
66279
+ ...resolvedFields(node),
65921
66280
  ...after
65922
66281
  };
65923
66282
  }
@@ -65930,7 +66289,12 @@ async function type(ctx, params) {
65930
66289
  const typed = await typeInto(ctx, contents, node, text, target2);
65931
66290
  if (typed) {
65932
66291
  ctx.registry.touch(record);
65933
- return { ...typed, ...frameFields(node), ...pageOf(record.view) };
66292
+ return {
66293
+ ...typed,
66294
+ ...frameFields(node),
66295
+ ...resolvedFields(node),
66296
+ ...pageOf(record.view)
66297
+ };
65934
66298
  }
65935
66299
  const frame = await iframeScopeOf(ctx, contents, node);
65936
66300
  if (frame) {