local-operator-ui 0.41.2 → 0.42.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 (98) hide show
  1. package/out/main/index.js +877 -225
  2. package/out/preload/index.js +83 -4
  3. package/out/renderer/assets/{_basePickBy-BgapP5T6.js → _basePickBy-KfApUmWE.js} +1 -1
  4. package/out/renderer/assets/{_baseUniq-B9rnfho3.js → _baseUniq-DXd1h_x3.js} +1 -1
  5. package/out/renderer/assets/{agent-details-page-CKRUVtjJ.js → agent-details-page-D-oKoyjm.js} +2 -2
  6. package/out/renderer/assets/{agent-hub-page-5qLVOZEV.js → agent-hub-page-CMbCN_Bg.js} +2 -2
  7. package/out/renderer/assets/agents-page-COpZu9CS.js +7 -0
  8. package/out/renderer/assets/{arc-Feq-cl9G.js → arc-Dim07OWx.js} +1 -1
  9. package/out/renderer/assets/{architectureDiagram-IEHRJDOE-BmZeJuzA.js → architectureDiagram-IEHRJDOE-BdwEpGi5.js} +1 -1
  10. package/out/renderer/assets/{blockDiagram-JOT3LUYC-DEqkKuOE.js → blockDiagram-JOT3LUYC-BcLFfkMT.js} +1 -1
  11. package/out/renderer/assets/{book-open-C1uak1LZ.js → book-open-C2DZijqP.js} +1 -1
  12. package/out/renderer/assets/browser-page-DzwNid1n.js +1 -0
  13. package/out/renderer/assets/{browser-webauthn-prompt-CKUBOIHd.js → browser-webauthn-prompt-C4aaSeT0.js} +1 -1
  14. package/out/renderer/assets/{building-2-Bpz1qaDa.js → building-2-DfFTqKaJ.js} +1 -1
  15. package/out/renderer/assets/{c4Diagram-VJAJSXHY-EbhUbSdf.js → c4Diagram-VJAJSXHY-Dm38eTOl.js} +1 -1
  16. package/out/renderer/assets/channel-CefUnWw7.js +1 -0
  17. package/out/renderer/assets/{chunk-4BMEZGHF-DIk7XDrx.js → chunk-4BMEZGHF-94enK1_-.js} +1 -1
  18. package/out/renderer/assets/{chunk-A2AXSNBT-D_MflthZ.js → chunk-A2AXSNBT-YiigwCRa.js} +1 -1
  19. package/out/renderer/assets/{chunk-AEK57VVT-C0iLgwbv.js → chunk-AEK57VVT-Bo9PQDfg.js} +1 -1
  20. package/out/renderer/assets/{chunk-D6G4REZN-BbFuFCzc.js → chunk-D6G4REZN-vwOZoeTn.js} +1 -1
  21. package/out/renderer/assets/{chunk-RZ5BOZE2-BxQo8VeZ.js → chunk-RZ5BOZE2-BY9NQkOq.js} +1 -1
  22. package/out/renderer/assets/{chunk-XZIHB7SX-DnNtYGsR.js → chunk-XZIHB7SX-D31wKKrQ.js} +1 -1
  23. package/out/renderer/assets/classDiagram-GIVACNV2-BKByQj4B.js +1 -0
  24. package/out/renderer/assets/classDiagram-v2-COTLJTTW-BKByQj4B.js +1 -0
  25. package/out/renderer/assets/clone-DpeVXG90.js +1 -0
  26. package/out/renderer/assets/{console-mirror-Bxl6t4e9.js → console-mirror-ClsQ7RUr.js} +1 -1
  27. package/out/renderer/assets/{consoleCapture-BzSftKjg.js → consoleCapture-DHR2J1Z2.js} +1 -1
  28. package/out/renderer/assets/{conversation-input-sync-MZPvyAzc.js → conversation-input-sync-CxT2etWK.js} +271 -251
  29. package/out/renderer/assets/{dagre-OKDRZEBW-qejdp-TF.js → dagre-OKDRZEBW-DV8UoEV8.js} +1 -1
  30. package/out/renderer/assets/{diagram-SSKATNLV-qHrLhzXc.js → diagram-SSKATNLV-KF8nQEWd.js} +1 -1
  31. package/out/renderer/assets/{diagram-VNBRO52H-q0teJTmh.js → diagram-VNBRO52H-P7VEv-Kl.js} +1 -1
  32. package/out/renderer/assets/{erDiagram-Q7BY3M3F-DI6rp9FR.js → erDiagram-Q7BY3M3F-B17XYgVW.js} +1 -1
  33. package/out/renderer/assets/{error-boundary-ZYkSCpZC.js → error-boundary-DBgLhXDJ.js} +1 -1
  34. package/out/renderer/assets/{flowDiagram-4HSFHLVR-xVi21DAI.js → flowDiagram-4HSFHLVR-BuuUG-g9.js} +1 -1
  35. package/out/renderer/assets/{ganttDiagram-APWFNJXF-BUKGBOB_.js → ganttDiagram-APWFNJXF-D8R9R-AO.js} +1 -1
  36. package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-CdE3ZeMn.js → gitGraphDiagram-7IBYFJ6S-fr4ArrNz.js} +1 -1
  37. package/out/renderer/assets/{graph-CRaHrZRK.js → graph-nV36Izm2.js} +1 -1
  38. package/out/renderer/assets/{hash-BN0ECl3H.js → hash-0qLX32ng.js} +1 -1
  39. package/out/renderer/assets/{heart-tKYqMVIH.js → heart-DFAcW-lm.js} +1 -1
  40. package/out/renderer/assets/{index-FsaxlHdZ.js → index-BKg4FYjW.js} +1 -1
  41. package/out/renderer/assets/index-BlshO0D3.css +1 -0
  42. package/out/renderer/assets/{index-B9E-fwX4.js → index-BmixXvR4.js} +1 -1
  43. package/out/renderer/assets/index-D6Di-Q2H.js +57 -0
  44. package/out/renderer/assets/index-DQKtrmMo.js +830 -0
  45. package/out/renderer/assets/{infoDiagram-PH2N3AL5-pOK9P20l.js → infoDiagram-PH2N3AL5-DmrijSS0.js} +1 -1
  46. package/out/renderer/assets/{installer-Dw1P6j8q.js → installer-4TSvERLS.js} +1 -1
  47. package/out/renderer/assets/{journeyDiagram-U35MCT3I-D5Sg1JPA.js → journeyDiagram-U35MCT3I-BwwXu0up.js} +1 -1
  48. package/out/renderer/assets/{kanban-definition-NDS4AKOZ-BfhWqBCl.js → kanban-definition-NDS4AKOZ-CDbDK3QO.js} +1 -1
  49. package/out/renderer/assets/{layout-IqsTm240.js → layout-B7RIhnQw.js} +1 -1
  50. package/out/renderer/assets/{legacy-agents-page-bdH6oKjE.js → legacy-agents-page-DFGXD5LW.js} +6 -6
  51. package/out/renderer/assets/library-page-DPid0cmw.js +157 -0
  52. package/out/renderer/assets/{mermaid.core-D0YPuNli.js → mermaid.core-DcMJPeY9.js} +5 -5
  53. package/out/renderer/assets/{mesh-page-DYFNof_0.js → mesh-page-CIV9irJF.js} +1 -1
  54. package/out/renderer/assets/{mindmap-definition-ALO5MXBD-Tx5iMDRU.js → mindmap-definition-ALO5MXBD-aLvI45Tt.js} +1 -1
  55. package/out/renderer/assets/mini-leTyoKhc.js +1 -0
  56. package/out/renderer/assets/{notebook-pen-C3CwzwGA.js → notebook-pen-ClukfLau.js} +1 -1
  57. package/out/renderer/assets/{org-access-DoZK5gF3.js → org-access-BmjQJdOO.js} +1 -1
  58. package/out/renderer/assets/{org-surface-gate-Dy0B7mtt.js → org-surface-gate-B66nUFl-.js} +1 -1
  59. package/out/renderer/assets/{page-header-6mrV9W-E.js → page-header-C8bsR5wI.js} +1 -1
  60. package/out/renderer/assets/path-utils-DbnynqGJ.js +58 -0
  61. package/out/renderer/assets/{pieDiagram-IB7DONF6-D0rED3_3.js → pieDiagram-IB7DONF6-DvzUPikw.js} +1 -1
  62. package/out/renderer/assets/projects-page-4Cv9HMNh.js +45 -0
  63. package/out/renderer/assets/{publication-validation-CLbFS0n9.js → publication-validation-BlKeNjlY.js} +1 -1
  64. package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-D8jKSQt5.js → quadrantDiagram-7GDLP6J5-DFsFogdr.js} +1 -1
  65. package/out/renderer/assets/{radar-MK3ICKWK-Co2EJbaJ.js → radar-MK3ICKWK-YGPF88zl.js} +1 -1
  66. package/out/renderer/assets/{radient-auth-buttons-B11cdRmS.js → radient-auth-buttons-syGP58Ed.js} +1 -1
  67. package/out/renderer/assets/{requirementDiagram-KVF5MWMF-BI13h11j.js → requirementDiagram-KVF5MWMF-x2D5VXdu.js} +1 -1
  68. package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-D4hZ6_ML.js → sankeyDiagram-QLVOVGJD-DA4pKMXD.js} +1 -1
  69. package/out/renderer/assets/{schedules-page-DFfDDHYC.js → schedules-page-CLrwsPcv.js} +1 -1
  70. package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-U6CqBtco.js → sequenceDiagram-X6HHIX6F-BUX2Yk2J.js} +1 -1
  71. package/out/renderer/assets/{settings-page-CZ7NUDoe.js → settings-page-BAVKJQXi.js} +1 -1
  72. package/out/renderer/assets/{smartart-BVm_cEaq.js → smartart-ipuU9VIr.js} +1 -1
  73. package/out/renderer/assets/{stateDiagram-DGXRK772-DBg11bkx.js → stateDiagram-DGXRK772-BsVvaiaW.js} +1 -1
  74. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-BvVuptXT.js +1 -0
  75. package/out/renderer/assets/{team-bridge-page-u_OqiZGS.js → team-bridge-page-DU_d4Yfc.js} +2 -2
  76. package/out/renderer/assets/{timeline-definition-BDJGKUSR-WQ6aYia6.js → timeline-definition-BDJGKUSR-Doja7siy.js} +1 -1
  77. package/out/renderer/assets/{use-download-agent-mutation-ZoivWizY.js → use-download-agent-mutation-CH4V_o78.js} +1 -1
  78. package/out/renderer/assets/{use-session-snapshot-CdYiirKJ.js → use-session-snapshot-7A4rQnOH.js} +1 -1
  79. package/out/renderer/assets/{xychartDiagram-VJFVF3MP-f11BpHer.js → xychartDiagram-VJFVF3MP-D2e6wZz8.js} +1 -1
  80. package/out/renderer/console-capture.html +5 -5
  81. package/out/renderer/index.html +7 -7
  82. package/out/renderer/installer.html +4 -4
  83. package/out/renderer/mini.html +7 -7
  84. package/package.json +2 -2
  85. package/out/renderer/assets/agents-page-tQooOOKH.js +0 -7
  86. package/out/renderer/assets/browser-page-CB-_usY1.js +0 -1
  87. package/out/renderer/assets/channel-CPGK3lub.js +0 -1
  88. package/out/renderer/assets/classDiagram-GIVACNV2-hDc6ku-l.js +0 -1
  89. package/out/renderer/assets/classDiagram-v2-COTLJTTW-hDc6ku-l.js +0 -1
  90. package/out/renderer/assets/clone--PuuOIog.js +0 -1
  91. package/out/renderer/assets/index-BDzV3bGH.js +0 -57
  92. package/out/renderer/assets/index-DknTGnAk.js +0 -835
  93. package/out/renderer/assets/index-ZovyVTxQ.css +0 -1
  94. package/out/renderer/assets/library-page-DDvrG_aA.js +0 -157
  95. package/out/renderer/assets/mini-BoZCnSK9.js +0 -1
  96. package/out/renderer/assets/path-utils-CRYGE4mK.js +0 -58
  97. package/out/renderer/assets/projects-page-D7j1GOvI.js +0 -45
  98. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-jmaink9i.js +0 -1
package/out/main/index.js CHANGED
@@ -200,6 +200,8 @@ zod.z.object({
200
200
  }).passthrough()
201
201
  }).passthrough()
202
202
  }).passthrough();
203
+ const MAX_ATTACHMENT_UPLOAD_BYTES = 32 * 1024 * 1024;
204
+ const DESKTOP_MESSAGE_MAX_FILES = 8;
203
205
  const SIDEBAR_DESTINATION_IDS = [
204
206
  "aida",
205
207
  "library",
@@ -213,9 +215,9 @@ const SIDEBAR_DESTINATION_IDS = [
213
215
  ];
214
216
  const JOURNAL_ORDER_QUERY_BYTES = 6 * 1024;
215
217
  const JOURNAL_ORDER_ID_LIMIT = 512;
216
- function appendJournalOrderIds(query, path2, ids) {
218
+ function appendJournalOrderIds(query2, path2, ids) {
217
219
  let bytes = new TextEncoder().encode(
218
- `${path2}${query.size ? `?${query}` : ""}`
220
+ `${path2}${query2.size ? `?${query2}` : ""}`
219
221
  ).length;
220
222
  const selected = [];
221
223
  for (const id2 of ids) {
@@ -223,7 +225,7 @@ function appendJournalOrderIds(query, path2, ids) {
223
225
  const encoded = new URLSearchParams({ order_ids: id2 }).toString();
224
226
  const extra = encoded.length + 1;
225
227
  if (bytes + extra > JOURNAL_ORDER_QUERY_BYTES) break;
226
- query.append("order_ids", id2);
228
+ query2.append("order_ids", id2);
227
229
  selected.push(id2);
228
230
  bytes += extra;
229
231
  }
@@ -251,7 +253,21 @@ const libraryAssetId = zod.z.string().regex(/^la_[0-9a-f]{16}$/);
251
253
  const libraryTagId = zod.z.string().min(1).max(128).regex(/^[A-Za-z0-9_.:-]+$/);
252
254
  const sessionImage = zod.z.object({
253
255
  data_b64: zod.z.string().min(1).max(1e6),
254
- mime_type: zod.z.enum(["image/png", "image/jpeg", "image/gif", "image/webp"])
256
+ mime_type: zod.z.enum(["image/png", "image/jpeg", "image/gif", "image/webp"]),
257
+ /**
258
+ * Where the image came from, when it came from disk. Provenance only: the
259
+ * daemon carries it to `ImageContent.path` and every provider serializer
260
+ * ignores it (attachment contract v1 §1.3). Absent on pasted images, which
261
+ * have no path.
262
+ */
263
+ origin_path: zod.z.string().max(4096).optional()
264
+ }).strict();
265
+ const sessionFile = zod.z.object({
266
+ digest: zod.z.string().regex(/^[0-9a-f]{32}$/),
267
+ name: zod.z.string().max(1024).optional(),
268
+ mime_type: zod.z.string().max(255).optional(),
269
+ bytes: zod.z.number().int().min(0).optional(),
270
+ path: zod.z.string().max(4096).optional()
255
271
  }).strict();
256
272
  const DESKTOP_MESSAGE_MAX_CHARS = 2e5;
257
273
  const DESKTOP_MESSAGE_MAX_IMAGES = 8;
@@ -1222,6 +1238,13 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
1222
1238
  requestId,
1223
1239
  text: zod.z.string().max(DESKTOP_MESSAGE_MAX_CHARS),
1224
1240
  images: zod.z.array(sessionImage).max(DESKTOP_MESSAGE_MAX_IMAGES).optional(),
1241
+ /**
1242
+ * Uploaded files this message references, bounded to the backend's
1243
+ * `Prompt.files` ceiling. Absent rather than empty when the send carries
1244
+ * none, so an older harness's `extra=forbid` sees a legacy body - the same
1245
+ * rule the optional fields below follow.
1246
+ */
1247
+ files: zod.z.array(sessionFile).max(DESKTOP_MESSAGE_MAX_FILES).optional(),
1225
1248
  mode: zod.z.enum(["prompt", "steer"]).optional(),
1226
1249
  /*
1227
1250
  * HOW THE MESSAGE WAS PRODUCED (arch §4.2), and the harness gate is what
@@ -1318,7 +1341,28 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
1318
1341
  * its own sentence once the response row exists; this client does not
1319
1342
  * pre-judge that, it renders the owner's refusal.
1320
1343
  */
1321
- revise: zod.z.boolean().optional()
1344
+ revise: zod.z.boolean().optional(),
1345
+ /**
1346
+ * PUT AN OPEN ASK AWAY instead of answering it (harness PR #2833, SA-D5).
1347
+ *
1348
+ * A modifier on the SAME `{ask_id}` body rather than a fourth op: a dismissal
1349
+ * is the same epoch-free queued-ask door an answer is, addressed by an id that
1350
+ * outlives any owner. Only `true` selects the shape — `false` is the same
1351
+ * statement as omitting it — and the shape rules below refuse it beside
1352
+ * answers/decline/revise, because no single body may answer and dismiss one ask.
1353
+ *
1354
+ * GATED ON `features.ask_dismiss` at the surface that offers the control: the
1355
+ * backend's `Answer` is `extra="forbid"`, so an older daemon answers 422 to this
1356
+ * field rather than ignoring it.
1357
+ */
1358
+ dismiss: zod.z.boolean().optional(),
1359
+ /**
1360
+ * Why the operator put it away: `answered_in_chat` (the conversation already
1361
+ * answered it) or `moot` (no longer needed). Optional; the ask log records
1362
+ * `moot` when absent. Refused without `dismiss: true` — the same no-op rule
1363
+ * `revise` follows above.
1364
+ */
1365
+ reason: zod.z.enum(["answered_in_chat", "moot"]).optional()
1322
1366
  }).strict(),
1323
1367
  zod.z.object({
1324
1368
  op: zod.z.literal("sessions.seen"),
@@ -3166,7 +3210,22 @@ const desktopRequestSchema = desktopRequestUnion.superRefine(
3166
3210
  message: "ask_id must be a non-empty string",
3167
3211
  path: ["askId"]
3168
3212
  });
3169
- if (request.decline !== true && !request.answers)
3213
+ if (request.dismiss === true) {
3214
+ if (request.answers !== void 0 || request.decline === true || request.revise === true)
3215
+ ctx.addIssue({
3216
+ code: zod.z.ZodIssueCode.custom,
3217
+ message: "A dismissal carries no answers, decline or revise",
3218
+ path: ["dismiss"]
3219
+ });
3220
+ return;
3221
+ }
3222
+ if (request.reason !== void 0)
3223
+ ctx.addIssue({
3224
+ code: zod.z.ZodIssueCode.custom,
3225
+ message: "A reason applies to a dismissal",
3226
+ path: ["reason"]
3227
+ });
3228
+ else if (request.decline !== true && !request.answers)
3170
3229
  ctx.addIssue({
3171
3230
  code: zod.z.ZodIssueCode.custom,
3172
3231
  message: "A queued-ask answer needs answers or decline",
@@ -3210,6 +3269,18 @@ const desktopRequestSchema = desktopRequestUnion.superRefine(
3210
3269
  message: "revise applies to a queued ask",
3211
3270
  path: ["revise"]
3212
3271
  });
3272
+ if (request.dismiss === true)
3273
+ ctx.addIssue({
3274
+ code: zod.z.ZodIssueCode.custom,
3275
+ message: "dismiss applies to a queued ask",
3276
+ path: ["dismiss"]
3277
+ });
3278
+ if (request.reason !== void 0)
3279
+ ctx.addIssue({
3280
+ code: zod.z.ZodIssueCode.custom,
3281
+ message: "reason applies to a queued ask",
3282
+ path: ["reason"]
3283
+ });
3213
3284
  return;
3214
3285
  }
3215
3286
  if (request.op === "sessions.create" && request.purpose === void 0) {
@@ -3651,11 +3722,11 @@ function harnessImportBody(request) {
3651
3722
  };
3652
3723
  }
3653
3724
  function conversationOwnerQuery(request) {
3654
- const query = new URLSearchParams();
3655
- if (request.tenant_id) query.set("tenant_id", request.tenant_id);
3725
+ const query2 = new URLSearchParams();
3726
+ if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
3656
3727
  if (request.expected_account_id)
3657
- query.set("expected_account_id", request.expected_account_id);
3658
- return query.size ? `?${query.toString()}` : "";
3728
+ query2.set("expected_account_id", request.expected_account_id);
3729
+ return query2.size ? `?${query2.toString()}` : "";
3659
3730
  }
3660
3731
  function tenantQuery(tenantId) {
3661
3732
  return tenantId === void 0 ? "" : `?tenant_id=${encodeURIComponent(tenantId)}`;
@@ -3758,10 +3829,10 @@ function desktopEndpoint(request) {
3758
3829
  case "imports.sources":
3759
3830
  return { path: "/v1/desktop/imports/sources", method: "GET" };
3760
3831
  case "imports.sessions": {
3761
- const query = new URLSearchParams({ source: request.source });
3762
- if (request.includeSubagents) query.set("include_subagents", "true");
3832
+ const query2 = new URLSearchParams({ source: request.source });
3833
+ if (request.includeSubagents) query2.set("include_subagents", "true");
3763
3834
  return {
3764
- path: `/v1/desktop/imports/sessions?${query.toString()}`,
3835
+ path: `/v1/desktop/imports/sessions?${query2.toString()}`,
3765
3836
  method: "GET"
3766
3837
  };
3767
3838
  }
@@ -4026,13 +4097,13 @@ function desktopEndpoint(request) {
4026
4097
  method: "POST"
4027
4098
  };
4028
4099
  case "sessions.search": {
4029
- const query = new URLSearchParams({
4100
+ const query2 = new URLSearchParams({
4030
4101
  q: request.q,
4031
4102
  limit: String(request.limit ?? SESSION_SEARCH_DEFAULT_LIMIT)
4032
4103
  });
4033
- if (request.include_archived) query.set("include_archived", "true");
4104
+ if (request.include_archived) query2.set("include_archived", "true");
4034
4105
  return {
4035
- path: `/v1/desktop/sessions/search?${query}`,
4106
+ path: `/v1/desktop/sessions/search?${query2}`,
4036
4107
  method: "GET"
4037
4108
  };
4038
4109
  }
@@ -4112,23 +4183,23 @@ function desktopEndpoint(request) {
4112
4183
  }
4113
4184
  };
4114
4185
  case "sessions.get": {
4115
- const query = new URLSearchParams();
4186
+ const query2 = new URLSearchParams();
4116
4187
  if (request.journalOrder) {
4117
- query.set("journal_order", "1");
4118
- if (request.peerJournalSource) query.set("peer_journal_source", "1");
4188
+ query2.set("journal_order", "1");
4189
+ if (request.peerJournalSource) query2.set("peer_journal_source", "1");
4119
4190
  appendJournalOrderIds(
4120
- query,
4191
+ query2,
4121
4192
  `/v1/desktop/sessions/${request.sessionId}`,
4122
4193
  request.orderIds ?? []
4123
4194
  );
4124
4195
  }
4125
4196
  return {
4126
- path: `/v1/desktop/sessions/${request.sessionId}${query.size ? `?${query}` : ""}`,
4197
+ path: `/v1/desktop/sessions/${request.sessionId}${query2.size ? `?${query2}` : ""}`,
4127
4198
  method: "GET"
4128
4199
  };
4129
4200
  }
4130
4201
  case "sessions.files": {
4131
- const query = new URLSearchParams({
4202
+ const query2 = new URLSearchParams({
4132
4203
  limit: String(request.limit ?? 200)
4133
4204
  });
4134
4205
  for (const key of [
@@ -4140,10 +4211,10 @@ function desktopEndpoint(request) {
4140
4211
  "cursor"
4141
4212
  ]) {
4142
4213
  const value = request[key];
4143
- if (value !== void 0) query.set(key, value);
4214
+ if (value !== void 0) query2.set(key, value);
4144
4215
  }
4145
4216
  return {
4146
- path: `/v1/desktop/sessions/${encodeURIComponent(request.sessionId)}/files?${query}`,
4217
+ path: `/v1/desktop/sessions/${encodeURIComponent(request.sessionId)}/files?${query2}`,
4147
4218
  method: "GET"
4148
4219
  };
4149
4220
  }
@@ -4153,34 +4224,34 @@ function desktopEndpoint(request) {
4153
4224
  method: "POST"
4154
4225
  };
4155
4226
  case "sessions.history": {
4156
- const query = new URLSearchParams({
4227
+ const query2 = new URLSearchParams({
4157
4228
  limit: String(request.limit ?? 100)
4158
4229
  });
4159
- if (request.beforeId) query.set("before_id", request.beforeId);
4230
+ if (request.beforeId) query2.set("before_id", request.beforeId);
4160
4231
  if (request.openFrame) {
4161
- query.set("open_frame", "1");
4162
- query.set("supplements", "1");
4232
+ query2.set("open_frame", "1");
4233
+ query2.set("supplements", "1");
4163
4234
  }
4164
4235
  if (request.journalOrder) {
4165
- query.set("journal_order", "1");
4166
- if (request.peerJournalSource) query.set("peer_journal_source", "1");
4236
+ query2.set("journal_order", "1");
4237
+ if (request.peerJournalSource) query2.set("peer_journal_source", "1");
4167
4238
  if (request.sourceRead === "metadata")
4168
- query.set("source_read", "metadata");
4239
+ query2.set("source_read", "metadata");
4169
4240
  else if (request.sourceRead === "payload" && request.expectedJournalGeneration)
4170
- query.set("source_read", "payload");
4241
+ query2.set("source_read", "payload");
4171
4242
  if (request.expectedJournalGeneration)
4172
- query.set(
4243
+ query2.set(
4173
4244
  "expected_journal_generation",
4174
4245
  request.expectedJournalGeneration
4175
4246
  );
4176
4247
  appendJournalOrderIds(
4177
- query,
4248
+ query2,
4178
4249
  `/v1/desktop/sessions/${request.sessionId}/history`,
4179
4250
  request.orderIds ?? []
4180
4251
  );
4181
4252
  }
4182
4253
  return {
4183
- path: `/v1/desktop/sessions/${request.sessionId}/history?${query}`,
4254
+ path: `/v1/desktop/sessions/${request.sessionId}/history?${query2}`,
4184
4255
  method: "GET"
4185
4256
  };
4186
4257
  }
@@ -4205,22 +4276,22 @@ function desktopEndpoint(request) {
4205
4276
  }
4206
4277
  };
4207
4278
  case "sessions.find": {
4208
- const query = new URLSearchParams({
4279
+ const query2 = new URLSearchParams({
4209
4280
  q: request.q,
4210
4281
  limit: String(request.limit ?? THREAD_FIND_DEFAULT_LIMIT)
4211
4282
  });
4212
4283
  return {
4213
- path: `/v1/desktop/sessions/${request.sessionId}/find?${query}`,
4284
+ path: `/v1/desktop/sessions/${request.sessionId}/find?${query2}`,
4214
4285
  method: "GET"
4215
4286
  };
4216
4287
  }
4217
4288
  case "subagents.transcript": {
4218
- const query = new URLSearchParams({
4289
+ const query2 = new URLSearchParams({
4219
4290
  limit: String(request.limit ?? 100)
4220
4291
  });
4221
- if (request.beforeId) query.set("before_id", request.beforeId);
4292
+ if (request.beforeId) query2.set("before_id", request.beforeId);
4222
4293
  return {
4223
- path: `/v1/desktop/sessions/${request.sessionId}/children/${request.childId}/transcript?${query}`,
4294
+ path: `/v1/desktop/sessions/${request.sessionId}/children/${request.childId}/transcript?${query2}`,
4224
4295
  method: "GET"
4225
4296
  };
4226
4297
  }
@@ -4232,6 +4303,7 @@ function desktopEndpoint(request) {
4232
4303
  request_id: request.requestId,
4233
4304
  text: request.text,
4234
4305
  images: request.images ?? [],
4306
+ ...request.files?.length ? { files: request.files } : {},
4235
4307
  mode: request.mode ?? "prompt",
4236
4308
  /*
4237
4309
  * ABSENT, not empty, when the app has nothing to say: an older harness
@@ -4272,7 +4344,16 @@ function desktopEndpoint(request) {
4272
4344
  * body that carried `revise: false` on every ordinary submit would be
4273
4345
  * asserting an intent it does not have.
4274
4346
  */
4275
- ...request.revise === true ? { revise: true } : {}
4347
+ ...request.revise === true ? { revise: true } : {},
4348
+ /*
4349
+ * The dismissal modifier and its reason, on the same absent-when-not-
4350
+ * asked-for rule: an older harness refuses the field outright
4351
+ * (`extra="forbid"`), so an ordinary answer must not carry it.
4352
+ */
4353
+ ...request.dismiss === true ? {
4354
+ dismiss: true,
4355
+ ...request.reason !== void 0 ? { reason: request.reason } : {}
4356
+ } : {}
4276
4357
  }
4277
4358
  };
4278
4359
  return {
@@ -4450,12 +4531,12 @@ function desktopEndpoint(request) {
4450
4531
  method: "DELETE"
4451
4532
  };
4452
4533
  case "legacy.models": {
4453
- const query = new URLSearchParams();
4454
- if (request.provider) query.set("provider", request.provider);
4455
- if (request.sort) query.set("sort", request.sort);
4456
- if (request.direction) query.set("direction", request.direction);
4534
+ const query2 = new URLSearchParams();
4535
+ if (request.provider) query2.set("provider", request.provider);
4536
+ if (request.sort) query2.set("sort", request.sort);
4537
+ if (request.direction) query2.set("direction", request.direction);
4457
4538
  return {
4458
- path: query.size > 0 ? `/v1/models?${query}` : "/v1/models",
4539
+ path: query2.size > 0 ? `/v1/models?${query2}` : "/v1/models",
4459
4540
  method: "GET"
4460
4541
  };
4461
4542
  }
@@ -4470,12 +4551,12 @@ function desktopEndpoint(request) {
4470
4551
  return { path: `/v1/agents/${request.agentId}/upload`, method: "POST" };
4471
4552
  case "agent.publish": {
4472
4553
  assertPairedPublicationTarget(request);
4473
- const query = new URLSearchParams();
4554
+ const query2 = new URLSearchParams();
4474
4555
  if (request.visibility === "org" && request.tenantId) {
4475
- query.set("visibility", "org");
4476
- query.set("tenant_id", request.tenantId);
4556
+ query2.set("visibility", "org");
4557
+ query2.set("tenant_id", request.tenantId);
4477
4558
  }
4478
- const search = query.toString();
4559
+ const search = query2.toString();
4479
4560
  return {
4480
4561
  path: `/v1/agents/${request.agentId}/publish${search ? `?${search}` : ""}`,
4481
4562
  method: "POST",
@@ -4492,12 +4573,12 @@ function desktopEndpoint(request) {
4492
4573
  }
4493
4574
  case "agent.republish": {
4494
4575
  assertPairedPublicationTarget(request);
4495
- const query = new URLSearchParams();
4576
+ const query2 = new URLSearchParams();
4496
4577
  if (request.visibility === "org" && request.tenantId) {
4497
- query.set("visibility", "org");
4498
- query.set("tenant_id", request.tenantId);
4578
+ query2.set("visibility", "org");
4579
+ query2.set("tenant_id", request.tenantId);
4499
4580
  }
4500
- const search = query.toString();
4581
+ const search = query2.toString();
4501
4582
  return {
4502
4583
  path: `/v1/agents/${request.agentId}/publish${search ? `?${search}` : ""}`,
4503
4584
  method: "PUT",
@@ -4511,49 +4592,49 @@ function desktopEndpoint(request) {
4511
4592
  }
4512
4593
  case "team.publish": {
4513
4594
  assertPairedPublicationTarget(request);
4514
- const query = new URLSearchParams();
4595
+ const query2 = new URLSearchParams();
4515
4596
  if (request.visibility === "org" && request.tenantId) {
4516
- query.set("visibility", "org");
4517
- query.set("tenant_id", request.tenantId);
4597
+ query2.set("visibility", "org");
4598
+ query2.set("tenant_id", request.tenantId);
4518
4599
  }
4519
4600
  return {
4520
- path: `/v1/teams/${request.teamId}/publish${query.size ? `?${query}` : ""}`,
4601
+ path: `/v1/teams/${request.teamId}/publish${query2.size ? `?${query2}` : ""}`,
4521
4602
  method: "POST",
4522
4603
  body: publicationPolicyBody(request)
4523
4604
  };
4524
4605
  }
4525
4606
  case "team.pull": {
4526
- const query = new URLSearchParams();
4527
- if (request.tenantId) query.set("tenant_id", request.tenantId);
4528
- const search = query.toString();
4607
+ const query2 = new URLSearchParams();
4608
+ if (request.tenantId) query2.set("tenant_id", request.tenantId);
4609
+ const search = query2.toString();
4529
4610
  return {
4530
4611
  path: `/v1/teams/pull/${request.teamId}${search ? `?${search}` : ""}`,
4531
4612
  method: "GET"
4532
4613
  };
4533
4614
  }
4534
4615
  case "agent.nameAvailability": {
4535
- const query = new URLSearchParams({ name: request.name });
4536
- return { path: `/v1/agent-name-availability?${query}`, method: "GET" };
4616
+ const query2 = new URLSearchParams({ name: request.name });
4617
+ return { path: `/v1/agent-name-availability?${query2}`, method: "GET" };
4537
4618
  }
4538
4619
  case "legacy.agents.list": {
4539
- const query = new URLSearchParams({
4620
+ const query2 = new URLSearchParams({
4540
4621
  page: String(request.page ?? 1),
4541
4622
  per_page: String(request.perPage ?? 10)
4542
4623
  });
4543
- if (request.name) query.set("name", request.name);
4544
- if (request.sort) query.set("sort", request.sort);
4545
- if (request.direction) query.set("direction", request.direction);
4546
- return { path: `/v1/agents?${query}`, method: "GET" };
4624
+ if (request.name) query2.set("name", request.name);
4625
+ if (request.sort) query2.set("sort", request.sort);
4626
+ if (request.direction) query2.set("direction", request.direction);
4627
+ return { path: `/v1/agents?${query2}`, method: "GET" };
4547
4628
  }
4548
4629
  case "legacy.agent.get":
4549
4630
  return { path: `/v1/agents/${request.agentId}`, method: "GET" };
4550
4631
  case "legacy.agent.history": {
4551
- const query = new URLSearchParams({
4632
+ const query2 = new URLSearchParams({
4552
4633
  page: String(request.page ?? 1),
4553
4634
  per_page: String(request.perPage ?? 10)
4554
4635
  });
4555
4636
  return {
4556
- path: `/v1/agents/${request.agentId}/history?${query}`,
4637
+ path: `/v1/agents/${request.agentId}/history?${query2}`,
4557
4638
  method: "GET"
4558
4639
  };
4559
4640
  }
@@ -4563,13 +4644,13 @@ function desktopEndpoint(request) {
4563
4644
  * what the backend's models declare.
4564
4645
  */
4565
4646
  case "wakes.list": {
4566
- const query = new URLSearchParams();
4647
+ const query2 = new URLSearchParams();
4567
4648
  if (request.limit !== void 0)
4568
- query.set("limit", String(request.limit));
4649
+ query2.set("limit", String(request.limit));
4569
4650
  if (request.includeDormant !== void 0)
4570
- query.set("include_dormant", String(request.includeDormant));
4651
+ query2.set("include_dormant", String(request.includeDormant));
4571
4652
  return {
4572
- path: query.size > 0 ? `/v1/desktop/wakes?${query}` : "/v1/desktop/wakes",
4653
+ path: query2.size > 0 ? `/v1/desktop/wakes?${query2}` : "/v1/desktop/wakes",
4573
4654
  method: "GET"
4574
4655
  };
4575
4656
  }
@@ -4626,30 +4707,30 @@ function desktopEndpoint(request) {
4626
4707
  method: "POST"
4627
4708
  };
4628
4709
  case "legacy.jobs.list": {
4629
- const query = new URLSearchParams();
4630
- if (request.agentId) query.set("agent_id", request.agentId);
4631
- if (request.status) query.set("status", request.status);
4710
+ const query2 = new URLSearchParams();
4711
+ if (request.agentId) query2.set("agent_id", request.agentId);
4712
+ if (request.status) query2.set("status", request.status);
4632
4713
  return {
4633
- path: query.size > 0 ? `/v1/jobs?${query}` : "/v1/jobs",
4714
+ path: query2.size > 0 ? `/v1/jobs?${query2}` : "/v1/jobs",
4634
4715
  method: "GET"
4635
4716
  };
4636
4717
  }
4637
4718
  case "legacy.job.get":
4638
4719
  return { path: `/v1/jobs/${request.jobId}`, method: "GET" };
4639
4720
  case "legacy.schedules.list": {
4640
- const query = new URLSearchParams({
4721
+ const query2 = new URLSearchParams({
4641
4722
  page: String(request.page ?? 1),
4642
4723
  per_page: String(request.perPage ?? 10)
4643
4724
  });
4644
- return { path: `/v1/schedules?${query}`, method: "GET" };
4725
+ return { path: `/v1/schedules?${query2}`, method: "GET" };
4645
4726
  }
4646
4727
  case "legacy.agent.schedules.list": {
4647
- const query = new URLSearchParams({
4728
+ const query2 = new URLSearchParams({
4648
4729
  page: String(request.page ?? 1),
4649
4730
  per_page: String(request.perPage ?? 10)
4650
4731
  });
4651
4732
  return {
4652
- path: `/v1/agents/${request.agentId}/schedules?${query}`,
4733
+ path: `/v1/agents/${request.agentId}/schedules?${query2}`,
4653
4734
  method: "GET"
4654
4735
  };
4655
4736
  }
@@ -4714,29 +4795,29 @@ function desktopEndpoint(request) {
4714
4795
  };
4715
4796
  }
4716
4797
  case "usage.get": {
4717
- const query = new URLSearchParams({
4798
+ const query2 = new URLSearchParams({
4718
4799
  live: String(request.live ?? false),
4719
4800
  refresh: String(request.refresh ?? false)
4720
4801
  });
4721
- if (request.provider) query.set("provider", request.provider);
4722
- return { path: `/v1/desktop/usage?${query}`, method: "GET" };
4802
+ if (request.provider) query2.set("provider", request.provider);
4803
+ return { path: `/v1/desktop/usage?${query2}`, method: "GET" };
4723
4804
  }
4724
4805
  case "quota.notice": {
4725
- const query = new URLSearchParams({
4806
+ const query2 = new URLSearchParams({
4726
4807
  refresh: String(request.refresh ?? false)
4727
4808
  });
4728
- if (request.provider) query.set("provider", request.provider);
4729
- if (request.model) query.set("model", request.model);
4730
- return { path: `/v1/desktop/quota-notice?${query}`, method: "GET" };
4809
+ if (request.provider) query2.set("provider", request.provider);
4810
+ if (request.model) query2.set("model", request.model);
4811
+ return { path: `/v1/desktop/quota-notice?${query2}`, method: "GET" };
4731
4812
  }
4732
4813
  case "analytics.get": {
4733
- const query = new URLSearchParams({ days: String(request.days ?? 30) });
4734
- if (request.sessionId) query.set("session_id", request.sessionId);
4814
+ const query2 = new URLSearchParams({ days: String(request.days ?? 30) });
4815
+ if (request.sessionId) query2.set("session_id", request.sessionId);
4735
4816
  if (request.sinceMs !== void 0)
4736
- query.set("since_ms", String(request.sinceMs));
4817
+ query2.set("since_ms", String(request.sinceMs));
4737
4818
  if (request.untilMs !== void 0)
4738
- query.set("until_ms", String(request.untilMs));
4739
- return { path: `/v1/desktop/analytics?${query}`, method: "GET" };
4819
+ query2.set("until_ms", String(request.untilMs));
4820
+ return { path: `/v1/desktop/analytics?${query2}`, method: "GET" };
4740
4821
  }
4741
4822
  /*
4742
4823
  * `/analytics/models`, NOT `/analytics?models=1`.
@@ -4749,31 +4830,31 @@ function desktopEndpoint(request) {
4749
4830
  * the server resolves one window from either.
4750
4831
  */
4751
4832
  case "analytics.models": {
4752
- const query = new URLSearchParams({ days: String(request.days ?? 30) });
4753
- if (request.sessionId) query.set("session_id", request.sessionId);
4833
+ const query2 = new URLSearchParams({ days: String(request.days ?? 30) });
4834
+ if (request.sessionId) query2.set("session_id", request.sessionId);
4754
4835
  if (request.sinceMs !== void 0)
4755
- query.set("since_ms", String(request.sinceMs));
4836
+ query2.set("since_ms", String(request.sinceMs));
4756
4837
  if (request.untilMs !== void 0)
4757
- query.set("until_ms", String(request.untilMs));
4758
- return { path: `/v1/desktop/analytics/models?${query}`, method: "GET" };
4838
+ query2.set("until_ms", String(request.untilMs));
4839
+ return { path: `/v1/desktop/analytics/models?${query2}`, method: "GET" };
4759
4840
  }
4760
4841
  case "info.get":
4761
4842
  return { path: "/v1/desktop/info", method: "GET" };
4762
4843
  case "sessions.report": {
4763
- const query = new URLSearchParams({
4844
+ const query2 = new URLSearchParams({
4764
4845
  recent_limit: String(request.recentLimit ?? 12)
4765
4846
  });
4766
4847
  return {
4767
- path: `/v1/desktop/sessions/${request.sessionId}/report?${query}`,
4848
+ path: `/v1/desktop/sessions/${request.sessionId}/report?${query2}`,
4768
4849
  method: "GET"
4769
4850
  };
4770
4851
  }
4771
4852
  case "skills.list": {
4772
- const query = new URLSearchParams();
4773
- if (request.sessionId) query.set("session_id", request.sessionId);
4774
- if (request.cwd) query.set("cwd", request.cwd);
4775
- if (request.name) query.set("name", request.name);
4776
- const encoded = query.toString();
4853
+ const query2 = new URLSearchParams();
4854
+ if (request.sessionId) query2.set("session_id", request.sessionId);
4855
+ if (request.cwd) query2.set("cwd", request.cwd);
4856
+ if (request.name) query2.set("name", request.name);
4857
+ const encoded = query2.toString();
4777
4858
  return {
4778
4859
  path: `/v1/desktop/skills${encoded ? `?${encoded}` : ""}`,
4779
4860
  method: "GET"
@@ -4878,10 +4959,10 @@ function desktopEndpoint(request) {
4878
4959
  body: request.control
4879
4960
  };
4880
4961
  case "mcp.catalog": {
4881
- const query = new URLSearchParams();
4882
- if (request.cwd) query.set("cwd", request.cwd);
4883
- if (request.sessionId) query.set("session_id", request.sessionId);
4884
- const suffix = query.toString();
4962
+ const query2 = new URLSearchParams();
4963
+ if (request.cwd) query2.set("cwd", request.cwd);
4964
+ if (request.sessionId) query2.set("session_id", request.sessionId);
4965
+ const suffix = query2.toString();
4885
4966
  return {
4886
4967
  path: suffix ? `/v1/desktop/mcp?${suffix}` : "/v1/desktop/mcp",
4887
4968
  method: "GET"
@@ -5029,14 +5110,14 @@ function desktopEndpoint(request) {
5029
5110
  }
5030
5111
  };
5031
5112
  case "team_bridge.conversations.list": {
5032
- const query = new URLSearchParams();
5033
- if (request.scope === "account") query.set("scope", "account");
5034
- if (request.tenant_id) query.set("tenant_id", request.tenant_id);
5113
+ const query2 = new URLSearchParams();
5114
+ if (request.scope === "account") query2.set("scope", "account");
5115
+ if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
5035
5116
  if (request.limit !== void 0)
5036
- query.set("limit", String(request.limit));
5037
- if (request.cursor) query.set("cursor", request.cursor);
5038
- if (request.before) query.set("before", request.before);
5039
- const suffix = query.size > 0 ? `?${query.toString()}` : "";
5117
+ query2.set("limit", String(request.limit));
5118
+ if (request.cursor) query2.set("cursor", request.cursor);
5119
+ if (request.before) query2.set("before", request.before);
5120
+ const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
5040
5121
  return {
5041
5122
  path: `/v1/desktop/team-bridge/conversations${suffix}`,
5042
5123
  method: "GET"
@@ -5097,11 +5178,11 @@ function desktopEndpoint(request) {
5097
5178
  }
5098
5179
  };
5099
5180
  case "team_bridge.conversations.members.add": {
5100
- const query = new URLSearchParams();
5101
- if (request.tenant_id) query.set("tenant_id", request.tenant_id);
5181
+ const query2 = new URLSearchParams();
5182
+ if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
5102
5183
  if (request.expected_account_id)
5103
- query.set("expected_account_id", request.expected_account_id);
5104
- const suffix = query.size > 0 ? `?${query.toString()}` : "";
5184
+ query2.set("expected_account_id", request.expected_account_id);
5185
+ const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
5105
5186
  return {
5106
5187
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members${suffix}`,
5107
5188
  method: "POST",
@@ -5125,14 +5206,14 @@ function desktopEndpoint(request) {
5125
5206
  }
5126
5207
  };
5127
5208
  case "team_bridge.messages.list": {
5128
- const query = new URLSearchParams();
5129
- if (request.tenant_id) query.set("tenant_id", request.tenant_id);
5209
+ const query2 = new URLSearchParams();
5210
+ if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
5130
5211
  if (request.limit !== void 0)
5131
- query.set("limit", String(request.limit));
5212
+ query2.set("limit", String(request.limit));
5132
5213
  if (request.before_seq !== void 0)
5133
- query.set("before_seq", String(request.before_seq));
5134
- if (request.endpoint_id) query.set("endpoint_id", request.endpoint_id);
5135
- const suffix = query.size > 0 ? `?${query.toString()}` : "";
5214
+ query2.set("before_seq", String(request.before_seq));
5215
+ if (request.endpoint_id) query2.set("endpoint_id", request.endpoint_id);
5216
+ const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
5136
5217
  return {
5137
5218
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/messages${suffix}`,
5138
5219
  method: "GET"
@@ -5163,13 +5244,13 @@ function desktopEndpoint(request) {
5163
5244
  }
5164
5245
  };
5165
5246
  case "team_bridge.messages.replies": {
5166
- const query = new URLSearchParams();
5167
- if (request.tenant_id) query.set("tenant_id", request.tenant_id);
5247
+ const query2 = new URLSearchParams();
5248
+ if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
5168
5249
  if (request.limit !== void 0)
5169
- query.set("limit", String(request.limit));
5250
+ query2.set("limit", String(request.limit));
5170
5251
  if (request.after_seq !== void 0)
5171
- query.set("after_seq", String(request.after_seq));
5172
- const suffix = query.size > 0 ? `?${query.toString()}` : "";
5252
+ query2.set("after_seq", String(request.after_seq));
5253
+ const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
5173
5254
  return {
5174
5255
  path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/messages/${encodeURIComponent(request.message_id)}/replies${suffix}`,
5175
5256
  method: "GET"
@@ -5187,10 +5268,10 @@ function desktopEndpoint(request) {
5187
5268
  }
5188
5269
  };
5189
5270
  case "team_bridge.unread": {
5190
- const query = new URLSearchParams();
5191
- if (request.scope === "account") query.set("scope", "account");
5192
- else if (request.tenant_id) query.set("tenant_id", request.tenant_id);
5193
- const suffix = query.size > 0 ? `?${query.toString()}` : "";
5271
+ const query2 = new URLSearchParams();
5272
+ if (request.scope === "account") query2.set("scope", "account");
5273
+ else if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
5274
+ const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
5194
5275
  return {
5195
5276
  path: `/v1/desktop/team-bridge/unread${suffix}`,
5196
5277
  method: "GET"
@@ -5218,9 +5299,9 @@ function desktopEndpoint(request) {
5218
5299
  * op would emit for a missing value.
5219
5300
  */
5220
5301
  case "team_bridge.status": {
5221
- const query = new URLSearchParams();
5222
- if (request.boundary) query.set("boundary", request.boundary);
5223
- const suffix = query.size > 0 ? `?${query.toString()}` : "";
5302
+ const query2 = new URLSearchParams();
5303
+ if (request.boundary) query2.set("boundary", request.boundary);
5304
+ const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
5224
5305
  return {
5225
5306
  path: `/v1/desktop/team-bridge/status${suffix}`,
5226
5307
  method: "GET"
@@ -5279,29 +5360,29 @@ function desktopEndpoint(request) {
5279
5360
  * `op` because that key already names the desktop operation.
5280
5361
  */
5281
5362
  case "library.list": {
5282
- const query = new URLSearchParams();
5283
- if (request.scope) query.set("scope", request.scope);
5284
- if (request.q) query.set("q", request.q);
5285
- if (request.category) query.set("category", request.category);
5286
- if (request.kind) query.set("kind", request.kind);
5287
- if (request.origin_group) query.set("origin_group", request.origin_group);
5288
- if (request.origin) query.set("origin", request.origin);
5289
- if (request.tag) query.set("tag", request.tag);
5290
- if (request.tag_mode) query.set("tag_mode", request.tag_mode);
5363
+ const query2 = new URLSearchParams();
5364
+ if (request.scope) query2.set("scope", request.scope);
5365
+ if (request.q) query2.set("q", request.q);
5366
+ if (request.category) query2.set("category", request.category);
5367
+ if (request.kind) query2.set("kind", request.kind);
5368
+ if (request.origin_group) query2.set("origin_group", request.origin_group);
5369
+ if (request.origin) query2.set("origin", request.origin);
5370
+ if (request.tag) query2.set("tag", request.tag);
5371
+ if (request.tag_mode) query2.set("tag_mode", request.tag_mode);
5291
5372
  if (request.highlighted !== void 0)
5292
- query.set("highlighted", request.highlighted ? "1" : "0");
5373
+ query2.set("highlighted", request.highlighted ? "1" : "0");
5293
5374
  if (request.organized !== void 0)
5294
- query.set("organized", request.organized ? "1" : "0");
5375
+ query2.set("organized", request.organized ? "1" : "0");
5295
5376
  if (request.favorite !== void 0)
5296
- query.set("favorite", request.favorite ? "1" : "0");
5297
- if (request.session) query.set("session", request.session);
5298
- if (request.session_id) query.set("session_id", request.session_id);
5299
- if (request.sort) query.set("sort", request.sort);
5300
- if (request.order) query.set("order", request.order);
5377
+ query2.set("favorite", request.favorite ? "1" : "0");
5378
+ if (request.session) query2.set("session", request.session);
5379
+ if (request.session_id) query2.set("session_id", request.session_id);
5380
+ if (request.sort) query2.set("sort", request.sort);
5381
+ if (request.order) query2.set("order", request.order);
5301
5382
  if (request.limit !== void 0)
5302
- query.set("limit", String(request.limit));
5303
- if (request.cursor) query.set("cursor", request.cursor);
5304
- const suffix = query.toString();
5383
+ query2.set("limit", String(request.limit));
5384
+ if (request.cursor) query2.set("cursor", request.cursor);
5385
+ const suffix = query2.toString();
5305
5386
  return {
5306
5387
  path: `/v1/desktop/library/assets${suffix ? `?${suffix}` : ""}`,
5307
5388
  method: "GET"
@@ -5462,12 +5543,12 @@ function desktopEndpoint(request) {
5462
5543
  method: "POST"
5463
5544
  };
5464
5545
  case "projects.search": {
5465
- const query = new URLSearchParams({
5546
+ const query2 = new URLSearchParams({
5466
5547
  q: request.q,
5467
5548
  limit: String(request.limit ?? PROJECTS_SEARCH_DEFAULT_LIMIT)
5468
5549
  });
5469
5550
  return {
5470
- path: `/v1/desktop/projects/search?${query}`,
5551
+ path: `/v1/desktop/projects/search?${query2}`,
5471
5552
  method: "GET"
5472
5553
  };
5473
5554
  }
@@ -5867,6 +5948,187 @@ function windowGlassArgument(state2, scheme) {
5867
5948
  const { settings, capability } = state2;
5868
5949
  return `${WINDOW_GLASS_ARG}=${capability.mechanism}:${settings.coverage}:${settings.intensity}:${settings.material}:${scheme}`;
5869
5950
  }
5951
+ const UPLOAD_DEADLINE_MS = 5 * 6e4;
5952
+ const DIGEST_SHAPE = /^[0-9a-f]{32}$/;
5953
+ const PATH_SEPARATOR = /[/\\]/;
5954
+ const basenameOf = (filePath) => filePath.split(PATH_SEPARATOR).pop() || filePath;
5955
+ function bytesFromDataUrl(dataUrl) {
5956
+ const comma = dataUrl.indexOf(",");
5957
+ if (comma < 0 || !dataUrl.startsWith("data:")) return null;
5958
+ const header = dataUrl.slice(5, comma);
5959
+ const payload = dataUrl.slice(comma + 1);
5960
+ try {
5961
+ if (header.endsWith(";base64"))
5962
+ return new Uint8Array(Buffer.from(payload, "base64"));
5963
+ return new Uint8Array(Buffer.from(decodeURIComponent(payload), "utf8"));
5964
+ } catch {
5965
+ return null;
5966
+ }
5967
+ }
5968
+ function readRecord(payload) {
5969
+ if (payload === null || typeof payload !== "object") return null;
5970
+ const body = payload;
5971
+ const inner = body.result;
5972
+ if (inner !== null && typeof inner === "object")
5973
+ return inner;
5974
+ return body;
5975
+ }
5976
+ function toAttachment(payload) {
5977
+ const record = readRecord(payload);
5978
+ if (!record) return null;
5979
+ const digest = record.digest;
5980
+ const mime = record.mime_type;
5981
+ const bytes = record.bytes;
5982
+ if (typeof digest !== "string" || !DIGEST_SHAPE.test(digest)) return null;
5983
+ if (typeof mime !== "string" || mime.length === 0) return null;
5984
+ if (typeof bytes !== "number" || !Number.isFinite(bytes) || bytes < 0)
5985
+ return null;
5986
+ return {
5987
+ digest,
5988
+ name: typeof record.name === "string" ? record.name : null,
5989
+ mime_type: mime,
5990
+ bytes,
5991
+ path: typeof record.path === "string" ? record.path : null,
5992
+ stored_path: typeof record.stored_path === "string" ? record.stored_path : null
5993
+ };
5994
+ }
5995
+ function refusalDetail(payload) {
5996
+ if (payload === null || typeof payload !== "object") return null;
5997
+ const detail = payload.detail;
5998
+ if (typeof detail === "string" && detail.trim()) return detail;
5999
+ if (detail !== null && typeof detail === "object") {
6000
+ const message = detail.message;
6001
+ if (typeof message === "string" && message.trim()) return message;
6002
+ }
6003
+ return null;
6004
+ }
6005
+ async function uploadAttachment(input) {
6006
+ const cap = input.maxBytes ?? MAX_ATTACHMENT_UPLOAD_BYTES;
6007
+ const source = input.source;
6008
+ const displayName = source.name?.trim() || (source.kind === "path" ? basenameOf(source.path) : "pasted-file");
6009
+ let originPath = null;
6010
+ let size;
6011
+ if (source.kind === "path") {
6012
+ const filePath = source.path;
6013
+ originPath = filePath;
6014
+ try {
6015
+ const stat = fs.statSync(filePath, { throwIfNoEntry: false });
6016
+ if (!stat) {
6017
+ return {
6018
+ success: false,
6019
+ code: "not-found",
6020
+ error: `No file at ${filePath}`
6021
+ };
6022
+ }
6023
+ if (!stat.isFile()) {
6024
+ return {
6025
+ success: false,
6026
+ code: "not-a-file",
6027
+ error: `${filePath} is not a regular file`
6028
+ };
6029
+ }
6030
+ size = stat.size;
6031
+ } catch (error) {
6032
+ return {
6033
+ success: false,
6034
+ code: "unreadable",
6035
+ error: error instanceof Error ? error.message : String(error)
6036
+ };
6037
+ }
6038
+ } else {
6039
+ const decoded = bytesFromDataUrl(source.dataUrl);
6040
+ if (!decoded) {
6041
+ return {
6042
+ success: false,
6043
+ code: "unreadable",
6044
+ error: `${displayName} did not carry usable bytes`
6045
+ };
6046
+ }
6047
+ size = decoded.byteLength;
6048
+ }
6049
+ if (size === 0) {
6050
+ return {
6051
+ success: false,
6052
+ code: "refused",
6053
+ error: `${displayName} is empty`,
6054
+ sizeBytes: 0
6055
+ };
6056
+ }
6057
+ if (size > cap) {
6058
+ return {
6059
+ success: false,
6060
+ code: "too-large",
6061
+ error: `${displayName} is ${size} bytes, over the ${cap}-byte attachment limit`,
6062
+ sizeBytes: size
6063
+ };
6064
+ }
6065
+ let bytes;
6066
+ try {
6067
+ bytes = source.kind === "path" ? new Uint8Array(fs.readFileSync(source.path)) : bytesFromDataUrl(source.dataUrl);
6068
+ } catch (error) {
6069
+ return {
6070
+ success: false,
6071
+ code: "unreadable",
6072
+ error: error instanceof Error ? error.message : String(error)
6073
+ };
6074
+ }
6075
+ const form = new FormData();
6076
+ form.append(
6077
+ "file",
6078
+ new Blob([bytes], {
6079
+ type: "application/octet-stream"
6080
+ }),
6081
+ displayName
6082
+ );
6083
+ form.append("name", displayName);
6084
+ if (originPath) form.append("origin_path", originPath);
6085
+ let response;
6086
+ try {
6087
+ const doFetch = input.fetchImpl ?? fetch;
6088
+ response = await doFetch(
6089
+ new URL("/v1/desktop/attachments", input.backendUrl),
6090
+ {
6091
+ method: "POST",
6092
+ headers: {
6093
+ Accept: "application/json",
6094
+ ...input.token ? { Authorization: `Bearer ${input.token}` } : {}
6095
+ },
6096
+ body: form,
6097
+ redirect: "error",
6098
+ signal: AbortSignal.timeout(UPLOAD_DEADLINE_MS)
6099
+ }
6100
+ );
6101
+ } catch (error) {
6102
+ return {
6103
+ success: false,
6104
+ code: "unreachable",
6105
+ error: error instanceof Error ? error.message : "The daemon did not answer the upload."
6106
+ };
6107
+ }
6108
+ let payload = null;
6109
+ try {
6110
+ payload = await response.json();
6111
+ } catch {
6112
+ }
6113
+ if (response.status < 200 || response.status >= 300) {
6114
+ return {
6115
+ success: false,
6116
+ code: "refused",
6117
+ error: refusalDetail(payload) ?? `The daemon refused the upload (HTTP ${response.status}).`,
6118
+ sizeBytes: size
6119
+ };
6120
+ }
6121
+ const attachment = toAttachment(payload);
6122
+ if (!attachment) {
6123
+ return {
6124
+ success: false,
6125
+ code: "refused",
6126
+ error: `${displayName} was uploaded but the daemon's answer carried no attachment record.`,
6127
+ sizeBytes: size
6128
+ };
6129
+ }
6130
+ return { success: true, attachment };
6131
+ }
5870
6132
  const SERVE_RUN_DIRNAME = "run/serve";
5871
6133
  const REAPED_DIRNAME = "reaped";
5872
6134
  const REAPED_MAX_FILES = 200;
@@ -9466,25 +9728,25 @@ class DesktopStreamRelay {
9466
9728
  const streamId = node_crypto.randomBytes(16).toString("hex");
9467
9729
  const controller = new AbortController();
9468
9730
  this.streams.set(streamId, controller);
9469
- const query = new URLSearchParams();
9470
- if (args.epoch) query.set("epoch", args.epoch);
9731
+ const query2 = new URLSearchParams();
9732
+ if (args.epoch) query2.set("epoch", args.epoch);
9471
9733
  if (args.afterSeq !== void 0)
9472
- query.set("after_seq", String(args.afterSeq));
9473
- query.set("frontend_replace", "1");
9474
- if (args.openFrame === true) query.set("open_frame", "1");
9734
+ query2.set("after_seq", String(args.afterSeq));
9735
+ query2.set("frontend_replace", "1");
9736
+ if (args.openFrame === true) query2.set("open_frame", "1");
9475
9737
  if (args.journalOrder === true) {
9476
- query.set("journal_order", "1");
9738
+ query2.set("journal_order", "1");
9477
9739
  if (args.peerJournalSource === true)
9478
- query.set("peer_journal_source", "1");
9740
+ query2.set("peer_journal_source", "1");
9479
9741
  }
9480
- query.set("supplements", "1");
9742
+ query2.set("supplements", "1");
9481
9743
  if (args.journalOrder === true)
9482
9744
  appendJournalOrderIds(
9483
- query,
9745
+ query2,
9484
9746
  `/v1/desktop/sessions/${args.sessionId}/events`,
9485
9747
  args.orderIds ?? []
9486
9748
  );
9487
- const suffix = query.size > 0 ? `?${query}` : "";
9749
+ const suffix = query2.size > 0 ? `?${query2}` : "";
9488
9750
  const url = new URL(
9489
9751
  `/v1/desktop/sessions/${args.sessionId}/events${suffix}`,
9490
9752
  this.backendUrl
@@ -14738,6 +15000,20 @@ class BackendServiceManager {
14738
15000
  getBackendUrl() {
14739
15001
  return this.backendUrl;
14740
15002
  }
15003
+ /**
15004
+ * The bearer token this app presents to THAT daemon, or null while none has
15005
+ * been minted/adopted yet.
15006
+ *
15007
+ * Exposed for the one request that does not travel through the op plane: the
15008
+ * attachment UPLOAD (attachment contract v1 §1.1). It carries raw bytes in a
15009
+ * multipart body, which the op plane's JSON schemas cannot describe, so it
15010
+ * goes over `fetch` from main and has to present the same credential the
15011
+ * plane would. Kept a getter rather than a public field so the token's
15012
+ * lifecycle stays owned here (`mintDesktopToken`, adoption, persistence).
15013
+ */
15014
+ getDesktopToken() {
15015
+ return this.desktopToken;
15016
+ }
14741
15017
  /**
14742
15018
  * Check if the backend service is using an external backend
14743
15019
  * @returns True if using an external backend, false if we started our own
@@ -14883,12 +15159,12 @@ const REASON_LIMIT = 240;
14883
15159
  function installFailureReason(stdout, stderr) {
14884
15160
  const lines = `${stderr}
14885
15161
  ${stdout}`.split(/\r?\n/);
14886
- const pick = (accept) => {
15162
+ const pick = (accept2) => {
14887
15163
  for (let index = lines.length - 1; index >= 0; index -= 1) {
14888
15164
  const line = lines[index].trim();
14889
15165
  if (line.length === 0) continue;
14890
15166
  if (NOISE.some((pattern) => pattern.test(line))) continue;
14891
- if (!accept(line)) continue;
15167
+ if (!accept2(line)) continue;
14892
15168
  return line.length > REASON_LIMIT ? `${line.slice(0, REASON_LIMIT - 1).trimEnd()}…` : line;
14893
15169
  }
14894
15170
  return null;
@@ -16769,6 +17045,10 @@ const METHODS$1 = [
16769
17045
  "styles",
16770
17046
  "hit_test",
16771
17047
  "ancestors",
17048
+ // The read-only DOM query: CSS in, element descriptors out. A read by
17049
+ // construction (no write, no navigation, no caller-supplied code), served by
17050
+ // every non-cmux host like the structured reads above.
17051
+ "query",
16772
17052
  "request_access",
16773
17053
  "await_access",
16774
17054
  "cancel_access",
@@ -16833,6 +17113,7 @@ const HOST_CAPABILITIES = [
16833
17113
  "styles",
16834
17114
  "hit_test",
16835
17115
  "ancestors",
17116
+ "query",
16836
17117
  "download",
16837
17118
  "upload"
16838
17119
  ];
@@ -28133,7 +28414,7 @@ function nativeCapacityProbe(trustedPython) {
28133
28414
  let ptyMax = null;
28134
28415
  let stopped = false;
28135
28416
  const children = /* @__PURE__ */ new Set();
28136
- function readNumber(executable, args, accept) {
28417
+ function readNumber(executable, args, accept2) {
28137
28418
  const child = node_child_process.execFile(
28138
28419
  executable,
28139
28420
  args,
@@ -28148,7 +28429,7 @@ function nativeCapacityProbe(trustedPython) {
28148
28429
  children.delete(child);
28149
28430
  if (stopped || error) return;
28150
28431
  const value = Number(stdout.trim());
28151
- if (Number.isSafeInteger(value) && value > 0) accept(value);
28432
+ if (Number.isSafeInteger(value) && value > 0) accept2(value);
28152
28433
  }
28153
28434
  );
28154
28435
  children.add(child);
@@ -35734,6 +36015,34 @@ const enUiChatAnalytics = {
35734
36015
  "ui.chat.analytics.toolbar.refreshing": "Refreshing",
35735
36016
  "ui.chat.analytics.toolbar.this_session_only": "This session only"
35736
36017
  };
36018
+ const enUiChatAsks = {
36019
+ "ui.chat.asks.context.messages_since": "{count, plural, one {# message from you since this was asked} other {# messages from you since this was asked}} (last message {time})",
36020
+ "ui.chat.asks.dismiss.answered_in_chat.note": "you already replied in the conversation",
36021
+ "ui.chat.asks.dismiss.answered_in_chat.title": "Answered in chat",
36022
+ "ui.chat.asks.dismiss.cancel": "Cancel",
36023
+ "ui.chat.asks.dismiss.heading": "Dismiss this ask",
36024
+ "ui.chat.asks.dismiss.in_flight": "Dismissing…",
36025
+ "ui.chat.asks.dismiss.moot.note": "stop waiting on it",
36026
+ "ui.chat.asks.dismiss.moot.title": "No longer needed",
36027
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "Dismissed — settled in chat",
36028
+ "ui.chat.asks.dismiss.receipt.moot": "Dismissed — no longer needed",
36029
+ "ui.chat.asks.dismiss.refused": "Couldn't dismiss this ask — nothing was sent.",
36030
+ "ui.chat.asks.dismiss.trigger": "Dismiss…"
36031
+ };
36032
+ const enUiChatAttachments = {
36033
+ "ui.chat.attachments.pending_caption": "Not sent yet",
36034
+ "ui.chat.attachments.file_meta": "{type} · {size}",
36035
+ "ui.chat.attachments.file_missing": "Moved or deleted",
36036
+ "ui.chat.attachments.file_retained": "Still retained in the attachment store ({digest})",
36037
+ "ui.chat.attachments.file_unnamed": "Attached file",
36038
+ "ui.chat.attachments.copy_path": "Copy path",
36039
+ "ui.chat.attachments.path_copied": "Path copied",
36040
+ "ui.chat.attachments.file_missing_recovery": "The file is no longer at this path.",
36041
+ "ui.chat.attachments.file_type_unknown": "File",
36042
+ "ui.chat.attachments.copy_saved_path": "Copy saved copy path",
36043
+ "ui.chat.attachments.saved_path_copied": "Saved copy path copied",
36044
+ "ui.chat.attachments.saved_copy_label": "Saved copy"
36045
+ };
35737
36046
  const enUiChatCanonical = {
35738
36047
  "ui.chat.canonical.sound.batch_attachment_unavailable": "Audio attachment unavailable.",
35739
36048
  "ui.chat.canonical.sound.player_failed": "This sound could not be played",
@@ -39514,6 +39823,34 @@ const esUiCanvas = {
39514
39823
  "ui.canvas.files.prepareError": "No se pudo preparar una copia local para esta acción",
39515
39824
  "ui.canvas.files.pathCopyNote": "Las acciones de abrir, carpeta y ruta crean una copia local en el scratchpad de esta conversación."
39516
39825
  };
39826
+ const esUiChatAsks = {
39827
+ "ui.chat.asks.context.messages_since": "{count, plural, one {# mensaje tuyo desde que se hizo esta consulta (último mensaje: {time})} many {# de mensajes tuyos desde que se hizo esta consulta (último mensaje: {time})} other {# mensajes tuyos desde que se hizo esta consulta (último mensaje: {time})}}",
39828
+ "ui.chat.asks.dismiss.answered_in_chat.note": "ya respondiste en la conversación",
39829
+ "ui.chat.asks.dismiss.answered_in_chat.title": "Respondida en la conversación",
39830
+ "ui.chat.asks.dismiss.cancel": "Cancelar",
39831
+ "ui.chat.asks.dismiss.heading": "Descartar esta consulta",
39832
+ "ui.chat.asks.dismiss.in_flight": "Descartando…",
39833
+ "ui.chat.asks.dismiss.moot.note": "el agente dejará de esperar respuesta",
39834
+ "ui.chat.asks.dismiss.moot.title": "Ya no hace falta",
39835
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "Descartada — resuelta en la conversación",
39836
+ "ui.chat.asks.dismiss.receipt.moot": "Descartada — ya no hace falta",
39837
+ "ui.chat.asks.dismiss.refused": "No se pudo descartar esta consulta: no se envió nada.",
39838
+ "ui.chat.asks.dismiss.trigger": "Descartar…"
39839
+ };
39840
+ const esUiChatAttachments = {
39841
+ "ui.chat.attachments.pending_caption": "Aún no enviado",
39842
+ "ui.chat.attachments.file_meta": "{type} · {size}",
39843
+ "ui.chat.attachments.file_missing": "Movido o eliminado",
39844
+ "ui.chat.attachments.file_retained": "Todavía se conserva en el almacén de adjuntos ({digest})",
39845
+ "ui.chat.attachments.file_unnamed": "Archivo adjunto",
39846
+ "ui.chat.attachments.copy_path": "Copiar ruta",
39847
+ "ui.chat.attachments.path_copied": "Ruta copiada",
39848
+ "ui.chat.attachments.file_missing_recovery": "El archivo ya no está en esta ruta.",
39849
+ "ui.chat.attachments.file_type_unknown": "Archivo",
39850
+ "ui.chat.attachments.copy_saved_path": "Copiar ruta de la copia guardada",
39851
+ "ui.chat.attachments.saved_path_copied": "Ruta de la copia guardada copiada",
39852
+ "ui.chat.attachments.saved_copy_label": "Copia guardada"
39853
+ };
39517
39854
  const esUiChatComposer = {
39518
39855
  "ui.chat.composer.clear_message": "Borrar mensaje",
39519
39856
  "ui.chat.composer.message": "Mensaje",
@@ -43155,6 +43492,34 @@ const frUiCanvas = {
43155
43492
  "ui.canvas.files.prepareError": "Impossible de préparer une copie locale pour cette action",
43156
43493
  "ui.canvas.files.pathCopyNote": "Les actions Ouvrir, Dossier et Chemin créent une copie locale dans le dossier de travail de cette conversation."
43157
43494
  };
43495
+ const frUiChatAsks = {
43496
+ "ui.chat.asks.context.messages_since": "{count, plural, one {# message de votre part depuis cette demande (dernier message à {time})} many {# de messages de votre part depuis cette demande (dernier message à {time})} other {# messages de votre part depuis cette demande (dernier message à {time})}}",
43497
+ "ui.chat.asks.dismiss.answered_in_chat.note": "vous avez déjà répondu dans la conversation",
43498
+ "ui.chat.asks.dismiss.answered_in_chat.title": "Répondu dans la conversation",
43499
+ "ui.chat.asks.dismiss.cancel": "Annuler",
43500
+ "ui.chat.asks.dismiss.heading": "Ignorer cette demande",
43501
+ "ui.chat.asks.dismiss.in_flight": "En cours…",
43502
+ "ui.chat.asks.dismiss.moot.note": "l’agent n’attendra plus de réponse",
43503
+ "ui.chat.asks.dismiss.moot.title": "Plus nécessaire",
43504
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "Ignorée — réglée dans la conversation",
43505
+ "ui.chat.asks.dismiss.receipt.moot": "Ignorée — plus nécessaire",
43506
+ "ui.chat.asks.dismiss.refused": "Impossible d’ignorer cette demande : rien n’a été envoyé.",
43507
+ "ui.chat.asks.dismiss.trigger": "Ignorer…"
43508
+ };
43509
+ const frUiChatAttachments = {
43510
+ "ui.chat.attachments.pending_caption": "Pas encore envoyé",
43511
+ "ui.chat.attachments.file_meta": "{type} · {size}",
43512
+ "ui.chat.attachments.file_missing": "Déplacé ou supprimé",
43513
+ "ui.chat.attachments.file_retained": "Toujours conservé dans le stockage des pièces jointes ({digest})",
43514
+ "ui.chat.attachments.file_unnamed": "Pièce jointe",
43515
+ "ui.chat.attachments.copy_path": "Copier le chemin",
43516
+ "ui.chat.attachments.path_copied": "Chemin copié",
43517
+ "ui.chat.attachments.file_missing_recovery": "Le fichier n'est plus à cet emplacement.",
43518
+ "ui.chat.attachments.file_type_unknown": "Fichier",
43519
+ "ui.chat.attachments.copy_saved_path": "Copier le chemin de la copie conservée",
43520
+ "ui.chat.attachments.saved_path_copied": "Chemin de la copie conservée copié",
43521
+ "ui.chat.attachments.saved_copy_label": "Copie conservée"
43522
+ };
43158
43523
  const frUiChatComposer = {
43159
43524
  "ui.chat.composer.clear_message": "Effacer le message",
43160
43525
  "ui.chat.composer.message": "Message",
@@ -46796,6 +47161,34 @@ const hiUiCanvas = {
46796
47161
  "ui.canvas.files.prepareError": "इस कार्रवाई के लिए स्थानीय कॉपी तैयार नहीं हो सकी",
46797
47162
  "ui.canvas.files.pathCopyNote": "खोलने, फ़ोल्डर और पाथ की कार्रवाइयाँ इस बातचीत के स्क्रैचपैड में एक स्थानीय कॉपी बनाती हैं।"
46798
47163
  };
47164
+ const hiUiChatAsks = {
47165
+ "ui.chat.asks.context.messages_since": "{count, plural, one {इस सवाल के बाद से आपका # संदेश} other {इस सवाल के बाद से आपके # संदेश}} (अंतिम संदेश {time})",
47166
+ "ui.chat.asks.dismiss.answered_in_chat.note": "आप बातचीत में पहले ही जवाब दे चुके हैं",
47167
+ "ui.chat.asks.dismiss.answered_in_chat.title": "चैट में जवाब दिया गया",
47168
+ "ui.chat.asks.dismiss.cancel": "रद्द करें",
47169
+ "ui.chat.asks.dismiss.heading": "यह सवाल हटाएँ",
47170
+ "ui.chat.asks.dismiss.in_flight": "हटाया जा रहा है…",
47171
+ "ui.chat.asks.dismiss.moot.note": "एजेंट अब जवाब का इंतज़ार नहीं करेगा",
47172
+ "ui.chat.asks.dismiss.moot.title": "अब ज़रूरत नहीं",
47173
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "हटाया गया — चैट में तय हो गया",
47174
+ "ui.chat.asks.dismiss.receipt.moot": "हटाया गया — अब ज़रूरत नहीं",
47175
+ "ui.chat.asks.dismiss.refused": "यह सवाल हटाया नहीं जा सका — कुछ भी नहीं भेजा गया।",
47176
+ "ui.chat.asks.dismiss.trigger": "हटाएँ…"
47177
+ };
47178
+ const hiUiChatAttachments = {
47179
+ "ui.chat.attachments.pending_caption": "अभी तक नहीं भेजा गया",
47180
+ "ui.chat.attachments.file_meta": "{type} · {size}",
47181
+ "ui.chat.attachments.file_missing": "स्थानांतरित या हटाया गया",
47182
+ "ui.chat.attachments.file_retained": "अभी भी अनुलग्नक स्टोर में सुरक्षित है ({digest})",
47183
+ "ui.chat.attachments.file_unnamed": "अनुलग्नक फ़ाइल",
47184
+ "ui.chat.attachments.copy_path": "पाथ कॉपी करें",
47185
+ "ui.chat.attachments.path_copied": "पाथ कॉपी हो गया",
47186
+ "ui.chat.attachments.file_missing_recovery": "फ़ाइल अब इस पाथ पर नहीं है।",
47187
+ "ui.chat.attachments.file_type_unknown": "फ़ाइल",
47188
+ "ui.chat.attachments.copy_saved_path": "सहेजी गई प्रति का पाथ कॉपी करें",
47189
+ "ui.chat.attachments.saved_path_copied": "सहेजी गई प्रति का पाथ कॉपी हो गया",
47190
+ "ui.chat.attachments.saved_copy_label": "सहेजी गई प्रति"
47191
+ };
46799
47192
  const hiUiChatComposer = {
46800
47193
  "ui.chat.composer.clear_message": "संदेश मिटाएँ",
46801
47194
  "ui.chat.composer.message": "संदेश",
@@ -50395,6 +50788,34 @@ const ruUiCanvas = {
50395
50788
  "ui.canvas.files.videos": "Видео",
50396
50789
  "ui.canvas.files.working": "Рабочие файлы"
50397
50790
  };
50791
+ const ruUiChatAsks = {
50792
+ "ui.chat.asks.context.messages_since": "{count, plural, one {# сообщение от вас с момента этого запроса} few {# сообщения от вас с момента этого запроса} many {# сообщений от вас с момента этого запроса} other {# сообщения от вас с момента этого запроса}} (последнее сообщение: {time})",
50793
+ "ui.chat.asks.dismiss.answered_in_chat.note": "вы уже ответили в чате",
50794
+ "ui.chat.asks.dismiss.answered_in_chat.title": "Ответ дан в чате",
50795
+ "ui.chat.asks.dismiss.cancel": "Отмена",
50796
+ "ui.chat.asks.dismiss.heading": "Убрать этот запрос",
50797
+ "ui.chat.asks.dismiss.in_flight": "Убираем…",
50798
+ "ui.chat.asks.dismiss.moot.note": "агент больше не будет ждать ответа",
50799
+ "ui.chat.asks.dismiss.moot.title": "Больше не нужно",
50800
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "Убрано — решено в чате",
50801
+ "ui.chat.asks.dismiss.receipt.moot": "Убрано — больше не нужно",
50802
+ "ui.chat.asks.dismiss.refused": "Не удалось убрать этот запрос — ничего не отправлено.",
50803
+ "ui.chat.asks.dismiss.trigger": "Убрать…"
50804
+ };
50805
+ const ruUiChatAttachments = {
50806
+ "ui.chat.attachments.pending_caption": "Ещё не отправлено",
50807
+ "ui.chat.attachments.file_meta": "{type} · {size}",
50808
+ "ui.chat.attachments.file_missing": "Перемещено или удалено",
50809
+ "ui.chat.attachments.file_retained": "Всё ещё хранится в хранилище вложений ({digest})",
50810
+ "ui.chat.attachments.file_unnamed": "Вложенный файл",
50811
+ "ui.chat.attachments.copy_path": "Скопировать путь",
50812
+ "ui.chat.attachments.path_copied": "Путь скопирован",
50813
+ "ui.chat.attachments.file_missing_recovery": "Файла по этому пути больше нет.",
50814
+ "ui.chat.attachments.file_type_unknown": "Файл",
50815
+ "ui.chat.attachments.copy_saved_path": "Скопировать путь сохранённой копии",
50816
+ "ui.chat.attachments.saved_path_copied": "Путь сохранённой копии скопирован",
50817
+ "ui.chat.attachments.saved_copy_label": "Сохранённая копия"
50818
+ };
50398
50819
  const ruUiChatComposer = {
50399
50820
  "ui.chat.composer.ask_aside": "Спросить отдельно",
50400
50821
  "ui.chat.composer.attach_file": "Прикрепить файл",
@@ -54014,6 +54435,34 @@ const urUiCanvas = {
54014
54435
  "ui.canvas.files.prepareError": "اس عمل کے لیے مقامی نقل تیار نہیں ہو سکی",
54015
54436
  "ui.canvas.files.pathCopyNote": "کھولنے، فولڈر اور راستے کے اعمال اس گفتگو کے اسکریچ پیڈ میں مقامی نقل بناتے ہیں۔"
54016
54437
  };
54438
+ const urUiChatAsks = {
54439
+ "ui.chat.asks.context.messages_since": "{count, plural, one {اس سوال کے بعد سے آپ کا # پیغام} other {اس سوال کے بعد سے آپ کے # پیغامات}} (آخری پیغام {time})",
54440
+ "ui.chat.asks.dismiss.answered_in_chat.note": "آپ گفتگو میں پہلے ہی جواب دے چکے ہیں",
54441
+ "ui.chat.asks.dismiss.answered_in_chat.title": "چیٹ میں جواب دیا گیا",
54442
+ "ui.chat.asks.dismiss.cancel": "منسوخ کریں",
54443
+ "ui.chat.asks.dismiss.heading": "یہ سوال ہٹائیں",
54444
+ "ui.chat.asks.dismiss.in_flight": "ہٹایا جا رہا ہے…",
54445
+ "ui.chat.asks.dismiss.moot.note": "ایجنٹ اب جواب کا انتظار نہیں کرے گا",
54446
+ "ui.chat.asks.dismiss.moot.title": "اب ضرورت نہیں",
54447
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "ہٹا دیا — چیٹ میں طے ہو گیا",
54448
+ "ui.chat.asks.dismiss.receipt.moot": "ہٹا دیا — اب ضرورت نہیں",
54449
+ "ui.chat.asks.dismiss.refused": "یہ سوال ہٹایا نہیں جا سکا — کچھ نہیں بھیجا گیا۔",
54450
+ "ui.chat.asks.dismiss.trigger": "ہٹائیں…"
54451
+ };
54452
+ const urUiChatAttachments = {
54453
+ "ui.chat.attachments.pending_caption": "ابھی نہیں بھیجا گیا",
54454
+ "ui.chat.attachments.file_meta": "{type} · {size}",
54455
+ "ui.chat.attachments.file_missing": "منتقل یا حذف شدہ",
54456
+ "ui.chat.attachments.file_retained": "اب بھی منسلکات کے ذخیرے میں محفوظ ہے ({digest})",
54457
+ "ui.chat.attachments.file_unnamed": "منسلک فائل",
54458
+ "ui.chat.attachments.copy_path": "راستہ نقل کریں",
54459
+ "ui.chat.attachments.path_copied": "راستہ نقل ہو گیا",
54460
+ "ui.chat.attachments.file_missing_recovery": "فائل اب اس راستے پر موجود نہیں ہے۔",
54461
+ "ui.chat.attachments.file_type_unknown": "فائل",
54462
+ "ui.chat.attachments.copy_saved_path": "محفوظ شدہ نقل کا راستہ نقل کریں",
54463
+ "ui.chat.attachments.saved_path_copied": "محفوظ شدہ نقل کا راستہ نقل ہو گیا",
54464
+ "ui.chat.attachments.saved_copy_label": "محفوظ شدہ نقل"
54465
+ };
54017
54466
  const urUiChatComposer = {
54018
54467
  "ui.chat.composer.clear_message": "پیغام صاف کریں",
54019
54468
  "ui.chat.composer.message": "پیغام",
@@ -57633,6 +58082,34 @@ const viUiCanvas = {
57633
58082
  "ui.canvas.files.prepareError": "Không chuẩn bị được bản sao cục bộ cho thao tác này",
57634
58083
  "ui.canvas.files.pathCopyNote": "Các thao tác mở tệp, mở thư mục và thao tác với đường dẫn sẽ tạo bản sao cục bộ trong thư mục nháp của cuộc trò chuyện này."
57635
58084
  };
58085
+ const viUiChatAsks = {
58086
+ "ui.chat.asks.context.messages_since": "{count, plural, other {# tin nhắn của bạn kể từ khi câu hỏi này được đưa ra}} (tin nhắn gần nhất lúc {time})",
58087
+ "ui.chat.asks.dismiss.answered_in_chat.note": "bạn đã trả lời trong cuộc trò chuyện",
58088
+ "ui.chat.asks.dismiss.answered_in_chat.title": "Đã trả lời trong cuộc trò chuyện",
58089
+ "ui.chat.asks.dismiss.cancel": "Hủy",
58090
+ "ui.chat.asks.dismiss.heading": "Bỏ qua câu hỏi này",
58091
+ "ui.chat.asks.dismiss.in_flight": "Đang bỏ qua…",
58092
+ "ui.chat.asks.dismiss.moot.note": "tác nhân sẽ không chờ câu trả lời nữa",
58093
+ "ui.chat.asks.dismiss.moot.title": "Không còn cần nữa",
58094
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "Đã bỏ qua — đã giải quyết trong cuộc trò chuyện",
58095
+ "ui.chat.asks.dismiss.receipt.moot": "Đã bỏ qua — không còn cần nữa",
58096
+ "ui.chat.asks.dismiss.refused": "Không thể bỏ qua câu hỏi này — không có gì được gửi đi.",
58097
+ "ui.chat.asks.dismiss.trigger": "Bỏ qua…"
58098
+ };
58099
+ const viUiChatAttachments = {
58100
+ "ui.chat.attachments.pending_caption": "Chưa được gửi",
58101
+ "ui.chat.attachments.file_meta": "{type} · {size}",
58102
+ "ui.chat.attachments.file_missing": "Đã di chuyển hoặc bị xóa",
58103
+ "ui.chat.attachments.file_retained": "Vẫn được lưu trong kho tệp đính kèm ({digest})",
58104
+ "ui.chat.attachments.file_unnamed": "Tệp đính kèm",
58105
+ "ui.chat.attachments.copy_path": "Sao chép đường dẫn",
58106
+ "ui.chat.attachments.path_copied": "Đã sao chép đường dẫn",
58107
+ "ui.chat.attachments.file_missing_recovery": "Tệp không còn ở đường dẫn này.",
58108
+ "ui.chat.attachments.file_type_unknown": "Tệp",
58109
+ "ui.chat.attachments.copy_saved_path": "Sao chép đường dẫn bản sao đã lưu",
58110
+ "ui.chat.attachments.saved_path_copied": "Đã sao chép đường dẫn bản sao đã lưu",
58111
+ "ui.chat.attachments.saved_copy_label": "Bản sao đã lưu"
58112
+ };
57636
58113
  const viUiChatComposer = {
57637
58114
  "ui.chat.composer.clear_message": "Xóa tin nhắn",
57638
58115
  "ui.chat.composer.message": "Tin nhắn",
@@ -61061,6 +61538,34 @@ const zhCNUiCanvas = {
61061
61538
  "ui.canvas.files.prepareError": "无法为此操作准备本地副本",
61062
61539
  "ui.canvas.files.pathCopyNote": "打开文件、打开文件夹及路径相关操作会在此对话的暂存区中创建本地副本。"
61063
61540
  };
61541
+ const zhCNUiChatAsks = {
61542
+ "ui.chat.asks.context.messages_since": "{count, plural, other {自提出这个请求以来你发来了#条消息}}(最后一条消息于{time})",
61543
+ "ui.chat.asks.dismiss.answered_in_chat.note": "你已在对话中回复过",
61544
+ "ui.chat.asks.dismiss.answered_in_chat.title": "已在对话中回答",
61545
+ "ui.chat.asks.dismiss.cancel": "取消",
61546
+ "ui.chat.asks.dismiss.heading": "关闭此请求",
61547
+ "ui.chat.asks.dismiss.in_flight": "正在关闭……",
61548
+ "ui.chat.asks.dismiss.moot.note": "无需继续等待",
61549
+ "ui.chat.asks.dismiss.moot.title": "不再需要",
61550
+ "ui.chat.asks.dismiss.receipt.answered_in_chat": "已关闭——已在对话中解决",
61551
+ "ui.chat.asks.dismiss.receipt.moot": "已关闭——不再需要",
61552
+ "ui.chat.asks.dismiss.refused": "无法关闭此请求——未发送任何内容。",
61553
+ "ui.chat.asks.dismiss.trigger": "关闭……"
61554
+ };
61555
+ const zhCNUiChatAttachments = {
61556
+ "ui.chat.attachments.pending_caption": "尚未发送",
61557
+ "ui.chat.attachments.file_meta": "{type} · {size}",
61558
+ "ui.chat.attachments.file_missing": "已移动或删除",
61559
+ "ui.chat.attachments.file_retained": "仍保留在附件存储中({digest})",
61560
+ "ui.chat.attachments.file_unnamed": "附件",
61561
+ "ui.chat.attachments.copy_path": "复制路径",
61562
+ "ui.chat.attachments.path_copied": "路径已复制",
61563
+ "ui.chat.attachments.file_missing_recovery": "该文件已不在这个路径。",
61564
+ "ui.chat.attachments.file_type_unknown": "文件",
61565
+ "ui.chat.attachments.copy_saved_path": "复制已保存副本的路径",
61566
+ "ui.chat.attachments.saved_path_copied": "已复制保存副本的路径",
61567
+ "ui.chat.attachments.saved_copy_label": "保存的副本"
61568
+ };
61064
61569
  const zhCNUiChatComposer = {
61065
61570
  "ui.chat.composer.clear_message": "清空消息",
61066
61571
  "ui.chat.composer.message": "消息",
@@ -64091,6 +64596,8 @@ const bundledEnglish = {
64091
64596
  ...enUiBrowser,
64092
64597
  ...enUiCanvas,
64093
64598
  ...enUiChatAnalytics,
64599
+ ...enUiChatAsks,
64600
+ ...enUiChatAttachments,
64094
64601
  ...enUiChatCanonical,
64095
64602
  ...enUiChatCommentaryActions,
64096
64603
  ...enUiChatComposer,
@@ -64165,6 +64672,8 @@ const bundledCatalogues = {
64165
64672
  ...esUiBrowserChrome,
64166
64673
  ...esUiBrowser,
64167
64674
  ...esUiCanvas,
64675
+ ...esUiChatAsks,
64676
+ ...esUiChatAttachments,
64168
64677
  ...esUiChatComposer,
64169
64678
  ...esUiChatComposerMedia,
64170
64679
  ...esUiChatDialogs,
@@ -64229,6 +64738,8 @@ const bundledCatalogues = {
64229
64738
  ...frUiBrowserChrome,
64230
64739
  ...frUiBrowser,
64231
64740
  ...frUiCanvas,
64741
+ ...frUiChatAsks,
64742
+ ...frUiChatAttachments,
64232
64743
  ...frUiChatComposer,
64233
64744
  ...frUiChatComposerMedia,
64234
64745
  ...frUiChatDialogs,
@@ -64293,6 +64804,8 @@ const bundledCatalogues = {
64293
64804
  ...hiUiBrowserChrome,
64294
64805
  ...hiUiBrowser,
64295
64806
  ...hiUiCanvas,
64807
+ ...hiUiChatAsks,
64808
+ ...hiUiChatAttachments,
64296
64809
  ...hiUiChatComposer,
64297
64810
  ...hiUiChatComposerMedia,
64298
64811
  ...hiUiChatDialogs,
@@ -64354,6 +64867,8 @@ const bundledCatalogues = {
64354
64867
  ...ruUiBrowserChrome,
64355
64868
  ...ruUiBrowser,
64356
64869
  ...ruUiCanvas,
64870
+ ...ruUiChatAsks,
64871
+ ...ruUiChatAttachments,
64357
64872
  ...ruUiChatComposer,
64358
64873
  ...ruUiChatComposerMedia,
64359
64874
  ...ruUiChatDialogs,
@@ -64416,6 +64931,8 @@ const bundledCatalogues = {
64416
64931
  ...urUiBrowserChrome,
64417
64932
  ...urUiBrowser,
64418
64933
  ...urUiCanvas,
64934
+ ...urUiChatAsks,
64935
+ ...urUiChatAttachments,
64419
64936
  ...urUiChatComposer,
64420
64937
  ...urUiChatComposerMedia,
64421
64938
  ...urUiChatDialogs,
@@ -64478,6 +64995,8 @@ const bundledCatalogues = {
64478
64995
  ...viUiBrowserChrome,
64479
64996
  ...viUiBrowser,
64480
64997
  ...viUiCanvas,
64998
+ ...viUiChatAsks,
64999
+ ...viUiChatAttachments,
64481
65000
  ...viUiChatComposer,
64482
65001
  ...viUiChatComposerMedia,
64483
65002
  ...viUiChatDialogs,
@@ -64539,6 +65058,8 @@ const bundledCatalogues = {
64539
65058
  ...zhCNUiBrowserChrome,
64540
65059
  ...zhCNUiBrowser,
64541
65060
  ...zhCNUiCanvas,
65061
+ ...zhCNUiChatAsks,
65062
+ ...zhCNUiChatAttachments,
64542
65063
  ...zhCNUiChatComposer,
64543
65064
  ...zhCNUiChatComposerMedia,
64544
65065
  ...zhCNUiChatDialogs,
@@ -64929,6 +65450,7 @@ function matches(haystack, needle, substring) {
64929
65450
  if (!right) return false;
64930
65451
  return substring ? left.includes(right) : left === right;
64931
65452
  }
65453
+ const NEVER_TARGETED = /* @__PURE__ */ new Set(["StaticText", "InlineTextBox", "none", "generic"]);
64932
65454
  function candidateNodes(nodes) {
64933
65455
  return nodes.filter((node) => !node.ignored && node.backendDOMNodeId !== void 0);
64934
65456
  }
@@ -64943,11 +65465,11 @@ function resolveLocator(nodes, locator) {
64943
65465
  }
64944
65466
  return matches(name, locator.name, locator.substring);
64945
65467
  };
64946
- const collect = (accept) => {
65468
+ const collect = (accept2) => {
64947
65469
  for (const node of pool) {
64948
65470
  const role = String(node.role?.value ?? "");
64949
65471
  const name = normalise(node.name?.value);
64950
- if (!accept(role)) continue;
65472
+ if (!accept2(role)) continue;
64951
65473
  if (!consider(role, name)) continue;
64952
65474
  hits.push({ backendNodeId: node.backendDOMNodeId, role, name, matched: 0 });
64953
65475
  }
@@ -64965,9 +65487,9 @@ function resolveLocator(nodes, locator) {
64965
65487
  if (!first) return null;
64966
65488
  return { ...first, matched: hits.length };
64967
65489
  }
64968
- function locatorSuggestions(nodes, query, limit = 5) {
64969
- const wanted = normalise(query).toLowerCase();
64970
- const parsed = parseLocator(query);
65490
+ function locatorSuggestions(nodes, query2, limit = 5) {
65491
+ const wanted = normalise(query2).toLowerCase();
65492
+ const parsed = parseLocator(query2);
64971
65493
  const term = parsed ? parsed.name.toLowerCase() : wanted;
64972
65494
  const words = term.split(/[^a-z0-9]+/).filter((word) => word.length > 1);
64973
65495
  const wantedRole = parsed && parsed.kind === "role" ? parsed.role : "";
@@ -64976,13 +65498,14 @@ function locatorSuggestions(nodes, query, limit = 5) {
64976
65498
  const role = String(node.role?.value ?? "");
64977
65499
  const name = normalise(node.name?.value);
64978
65500
  if (!name) continue;
65501
+ if (NEVER_TARGETED.has(role)) continue;
64979
65502
  const lowerName = name.toLowerCase();
64980
65503
  let score = 0;
64981
65504
  if (term && lowerName === term) score += 100;
64982
65505
  else if (term && lowerName.includes(term)) score += 60;
64983
65506
  for (const word of words) if (lowerName.includes(word)) score += 8;
64984
65507
  if (wantedRole && role.toLowerCase() === wantedRole) score += 25;
64985
- if (CLICKABLE.has(role)) score += 4;
65508
+ if (CLICKABLE.has(role)) score += 12;
64986
65509
  if (!score) continue;
64987
65510
  scored.push({ score, role, name });
64988
65511
  }
@@ -65876,11 +66399,32 @@ async function nodeIdForSelector(ctx, view, selector) {
65876
66399
  if (!queried?.nodeId) {
65877
66400
  throw new BridgeCommandError(
65878
66401
  "element_not_found",
65879
- `selector ${selector} matched nothing`
66402
+ `selector ${selector} matched nothing`,
66403
+ { candidates: await missCandidates(ctx, view, selector) }
65880
66404
  );
65881
66405
  }
65882
66406
  return queried.nodeId;
65883
66407
  }
66408
+ async function readAccessibilityTree(ctx, contents) {
66409
+ await ctx.cdp.send(contents, "Accessibility.enable", {});
66410
+ try {
66411
+ const tree = await ctx.cdp.send(
66412
+ contents,
66413
+ "Accessibility.getFullAXTree",
66414
+ {}
66415
+ );
66416
+ return Array.isArray(tree?.nodes) ? tree.nodes : [];
66417
+ } finally {
66418
+ await ctx.cdp.send(contents, "Accessibility.disable", {}).catch(() => {
66419
+ });
66420
+ }
66421
+ }
66422
+ async function missCandidates(ctx, view, selector) {
66423
+ const nodes = await readAccessibilityTree(ctx, view.webContents).catch(
66424
+ () => []
66425
+ );
66426
+ return locatorSuggestions(nodes, selector);
66427
+ }
65884
66428
  async function backendNodeIdForSelector(ctx, view, selector) {
65885
66429
  const nodeId = await nodeIdForSelector(ctx, view, selector);
65886
66430
  const described = await ctx.cdp.send(
@@ -66008,20 +66552,6 @@ function resolvedFields(node) {
66008
66552
  function frameFields(node) {
66009
66553
  return node.frame ? { frame_origin: node.frame.origin ?? "" } : {};
66010
66554
  }
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
- }
66025
66555
  async function resolveNode(ctx, record, target2) {
66026
66556
  const view = record.view;
66027
66557
  const contents = view.webContents;
@@ -66455,6 +66985,7 @@ function clampTimeout(requested) {
66455
66985
  const READ_STYLES_SOURCE = '(selector, properties) => {\n const DEFAULTS = [\n "display",\n "position",\n "visibility",\n "opacity",\n "z-index",\n "transform",\n "transform-origin",\n "top",\n "right",\n "bottom",\n "left",\n "width",\n "height",\n "contain",\n "filter",\n "will-change",\n "overflow",\n "overflow-x",\n "overflow-y",\n "pointer-events"\n ];\n const MAX_MATCHES = 5;\n const MAX_STYLES = 30;\n const MAX_INLINE = 30;\n const MAX_IDENTITY = 120;\n const MAX_VALUE = 200;\n const all = document.querySelectorAll(selector);\n if (!all || all.length === 0) return null;\n const names = DEFAULTS.slice();\n if (Array.isArray(properties)) {\n for (let i = 0; i < properties.length && names.length < MAX_STYLES; i++) {\n const name = String(properties[i] ?? "").trim();\n if (name && names.indexOf(name) === -1) names.push(name);\n }\n }\n const round2 = (value) => {\n const rounded = Math.round(value * 100) / 100;\n return rounded === 0 ? 0 : rounded;\n };\n const clip = (value, limit) => value.length > limit ? value.slice(0, limit - 1) + "\\u2026" : value;\n const rectOf = (el) => {\n const r = el.getBoundingClientRect();\n return {\n x: round2(r.x),\n y: round2(r.y),\n top: round2(r.top),\n right: round2(r.right),\n bottom: round2(r.bottom),\n width: round2(r.width),\n height: round2(r.height)\n };\n };\n const attrOf = (el, name) => clip(el.getAttribute(name) || "", MAX_IDENTITY);\n const matches = [];\n const first = Array.from(all).slice(0, MAX_MATCHES);\n for (const el of first) {\n const computed = getComputedStyle(el);\n const styles = {};\n for (const name of names) {\n styles[name] = clip(String(computed.getPropertyValue(name) || "").trim(), MAX_VALUE);\n }\n const inline = {};\n const declaration = el.style;\n let inlineCount = 0;\n for (let j = 0; j < declaration.length && inlineCount < MAX_INLINE; j++) {\n const name = declaration.item(j);\n if (name && name.indexOf("--") === 0) {\n const key = clip(name, MAX_IDENTITY);\n if (!(key in inline)) {\n inline[key] = clip(\n String(declaration.getPropertyValue(name) || "").trim(),\n MAX_VALUE\n );\n inlineCount += 1;\n }\n }\n }\n matches.push({\n tag: clip(el.tagName.toLowerCase(), MAX_IDENTITY),\n id: attrOf(el, "id"),\n role: attrOf(el, "role"),\n className: attrOf(el, "class"),\n rect: rectOf(el),\n styles,\n inline\n });\n }\n return { count: matches.length, matches, truncated: all.length > matches.length };\n}';
66456
66986
  const HIT_TEST_SOURCE = '(x, y) => {\n const PROPS = ["display", "position", "visibility", "opacity", "z-index", "pointer-events"];\n const MAX_ELEMENTS = 8;\n const MAX_IDENTITY = 120;\n const MAX_VALUE = 200;\n const px = Number(x);\n const py = Number(y);\n if (!Number.isFinite(px) || !Number.isFinite(py)) return null;\n const stack = document.elementsFromPoint(px, py);\n if (!stack || stack.length === 0) return null;\n const round2 = (value) => {\n const rounded = Math.round(value * 100) / 100;\n return rounded === 0 ? 0 : rounded;\n };\n const clip = (value, limit) => value.length > limit ? value.slice(0, limit - 1) + "\\u2026" : value;\n const attrOf = (el, name) => clip(el.getAttribute(name) || "", MAX_IDENTITY);\n const elements = [];\n for (const el of stack.slice(0, MAX_ELEMENTS)) {\n const computed = getComputedStyle(el);\n const styles = {};\n for (const name of PROPS) {\n styles[name] = clip(String(computed.getPropertyValue(name) || "").trim(), MAX_VALUE);\n }\n const r = el.getBoundingClientRect();\n elements.push({\n tag: clip(el.tagName.toLowerCase(), MAX_IDENTITY),\n id: attrOf(el, "id"),\n role: attrOf(el, "role"),\n className: attrOf(el, "class"),\n rect: {\n x: round2(r.x),\n y: round2(r.y),\n top: round2(r.top),\n right: round2(r.right),\n bottom: round2(r.bottom),\n width: round2(r.width),\n height: round2(r.height)\n },\n styles\n });\n }\n return { count: elements.length, elements };\n}';
66457
66987
  const ANCESTORS_SOURCE = '(selector, depth) => {\n const PROPS = [\n "display",\n "position",\n "visibility",\n "overflow",\n "overflow-x",\n "overflow-y",\n "transform",\n "transform-origin",\n "contain",\n "filter",\n "will-change",\n "z-index",\n "isolation",\n "top",\n "left"\n ];\n const DEFAULT_DEPTH = 12;\n const MAX_DEPTH = 16;\n const MAX_IDENTITY = 120;\n const MAX_VALUE = 200;\n const el = document.querySelector(selector);\n if (!el) return null;\n const wanted = typeof depth === "number" && Number.isFinite(depth) ? Math.floor(depth) : DEFAULT_DEPTH;\n const bound = Math.max(1, Math.min(MAX_DEPTH, wanted));\n const round2 = (value) => {\n const rounded = Math.round(value * 100) / 100;\n return rounded === 0 ? 0 : rounded;\n };\n const clip = (value, limit) => value.length > limit ? value.slice(0, limit - 1) + "\\u2026" : value;\n const attrOf = (el2, name) => clip(el2.getAttribute(name) || "", MAX_IDENTITY);\n const chain = [];\n let node = el;\n while (node && chain.length < bound) {\n const computed = getComputedStyle(node);\n const styles = {};\n for (const name of PROPS) {\n styles[name] = clip(String(computed.getPropertyValue(name) || "").trim(), MAX_VALUE);\n }\n const r = node.getBoundingClientRect();\n chain.push({\n tag: clip(node.tagName.toLowerCase(), MAX_IDENTITY),\n id: attrOf(node, "id"),\n role: attrOf(node, "role"),\n className: attrOf(node, "class"),\n rect: {\n x: round2(r.x),\n y: round2(r.y),\n top: round2(r.top),\n right: round2(r.right),\n bottom: round2(r.bottom),\n width: round2(r.width),\n height: round2(r.height)\n },\n styles\n });\n if (node === document.documentElement) break;\n node = node.parentElement;\n }\n return { count: chain.length, chain };\n}';
66988
+ const QUERY_SOURCE = '(selector, limit) => {\n const MAX_ELEMENTS = 50;\n const MAX_IDENTITY = 120;\n const MAX_TEXT = 120;\n const MAX_VALUE = 120;\n if (typeof selector !== "string" || !selector.trim()) return null;\n const wanted = typeof limit === "number" && Number.isFinite(limit) ? Math.floor(limit) : 20;\n const bound = Math.max(1, Math.min(MAX_ELEMENTS, wanted));\n const round2 = (value) => {\n const rounded = Math.round(value * 100) / 100;\n return rounded === 0 ? 0 : rounded;\n };\n const clip = (value, cap) => value.length > cap ? `${value.slice(0, cap - 1)}\\u2026` : value;\n const attrOf = (el, name) => clip(String(el.getAttribute(name) || ""), MAX_IDENTITY);\n const visibleOf = (el, rect) => {\n if (rect.width <= 0 || rect.height <= 0) return false;\n const computed = getComputedStyle(el);\n if (computed.display === "none" || computed.visibility === "hidden") return false;\n return computed.contentVisibility !== "hidden";\n };\n let nodes;\n try {\n nodes = Array.from(document.querySelectorAll(selector));\n } catch {\n return { count: 0, truncated: false, matches: [], error: "invalid_selector" };\n }\n const viewport = {\n width: document.documentElement.clientWidth || window.innerWidth || 0,\n height: document.documentElement.clientHeight || window.innerHeight || 0\n };\n const matches = [];\n for (const el of nodes.slice(0, bound)) {\n const rect = el.getBoundingClientRect();\n const tag = clip(String(el.tagName || "").toLowerCase(), MAX_IDENTITY);\n const type = attrOf(el, "type").toLowerCase();\n const isPassword = tag === "input" && type === "password";\n const rawValue = el.value;\n const checkable = tag === "input" && (type === "checkbox" || type === "radio");\n const checked = checkable ? Boolean(el.checked) : null;\n matches.push({\n tag,\n id: attrOf(el, "id"),\n name: attrOf(el, "name"),\n role: attrOf(el, "role"),\n ariaLabel: attrOf(el, "aria-label"),\n // `innerText` is the RENDERED text (a hidden node reports ""), which is\n // what an agent reading a page means by "the text"; `textContent` would\n // report text nobody can see, including inside a collapsed section.\n text: clip(String(el.innerText || "").replace(/\\s+/g, " ").trim(), MAX_TEXT),\n type,\n visible: visibleOf(el, rect),\n inView: rect.top < viewport.height && rect.bottom > 0 && rect.left < viewport.width && rect.right > 0,\n disabled: el.hasAttribute("disabled") || el.disabled === true,\n checked,\n value: isPassword || rawValue === void 0 || rawValue === null ? "" : clip(String(rawValue), MAX_VALUE),\n rect: {\n x: round2(rect.x),\n y: round2(rect.y),\n width: round2(rect.width),\n height: round2(rect.height)\n }\n });\n }\n return { count: nodes.length, truncated: nodes.length > matches.length, matches };\n}';
66458
66989
  const MAX_REQUESTED_PROPERTIES = 20;
66459
66990
  const DEFAULT_DEPTH = 12;
66460
66991
  const MAX_DEPTH = 16;
@@ -66581,6 +67112,51 @@ async function ancestors(ctx, params) {
66581
67112
  ...pageOf(record.view)
66582
67113
  };
66583
67114
  }
67115
+ const DEFAULT_LIMIT = 20;
67116
+ const MAX_LIMIT = 50;
67117
+ async function query(ctx, params) {
67118
+ const record = ctx.registry.requireSurface(params.tab);
67119
+ const selector = stringParam(params, "selector");
67120
+ if (!selector) {
67121
+ throw new BridgeCommandError("element_not_found", "selector is required");
67122
+ }
67123
+ const requested = numberParam(params, "limit") ?? DEFAULT_LIMIT;
67124
+ const limit = Math.max(1, Math.min(MAX_LIMIT, Math.floor(requested)));
67125
+ const code = `(${QUERY_SOURCE})(${JSON.stringify(selector)}, ${JSON.stringify(limit)})`;
67126
+ let result;
67127
+ try {
67128
+ result = await deadline(
67129
+ record.view.webContents.executeJavaScriptInIsolatedWorld(
67130
+ ISOLATED_WORLD_ID,
67131
+ [{ code }]
67132
+ ),
67133
+ SCRIPTING_DEADLINE_MS,
67134
+ `query(${record.tabId})`
67135
+ );
67136
+ } catch (error) {
67137
+ if (error instanceof Error && INVALID_SELECTOR.test(error.message)) {
67138
+ throw new BridgeCommandError(
67139
+ "element_not_found",
67140
+ `selector ${selector} is not valid`
67141
+ );
67142
+ }
67143
+ throw error;
67144
+ }
67145
+ if (typeof result !== "object" || result === null) {
67146
+ throw new BridgeCommandError(
67147
+ "internal",
67148
+ "the page returned no structured query result"
67149
+ );
67150
+ }
67151
+ if (result.error === "invalid_selector") {
67152
+ throw new BridgeCommandError(
67153
+ "element_not_found",
67154
+ `selector ${selector} is not valid`
67155
+ );
67156
+ }
67157
+ ctx.registry.touch(record);
67158
+ return { ...result, ...pageOf(record.view) };
67159
+ }
66584
67160
  const MAX_AGENT_TABS = 8;
66585
67161
  const BACKGROUND_VIEWPORT = {
66586
67162
  x: 0,
@@ -67468,7 +68044,7 @@ async function upload(ctx, params) {
67468
68044
  { selector, frame_origin: node.frame.origin ?? "" }
67469
68045
  );
67470
68046
  }
67471
- const accept = await acceptsOf(ctx, record, node.nodeId);
68047
+ const accept2 = await acceptsOf(ctx, record, node.nodeId);
67472
68048
  await ctx.cdp.send(contents, "DOM.setFileInputFiles", {
67473
68049
  files: paths,
67474
68050
  nodeId: node.nodeId
@@ -67476,7 +68052,7 @@ async function upload(ctx, params) {
67476
68052
  if (!/not a file input/i.test(String(error))) throw error;
67477
68053
  throw new BridgeCommandError("element_not_found", NOT_A_FILE_INPUT, {
67478
68054
  selector,
67479
- accept
68055
+ accept: accept2
67480
68056
  });
67481
68057
  });
67482
68058
  let held = null;
@@ -67490,10 +68066,10 @@ async function upload(ctx, params) {
67490
68066
  if (!held) {
67491
68067
  throw new BridgeCommandError("element_not_found", NOT_A_FILE_INPUT, {
67492
68068
  selector,
67493
- accept
68069
+ accept: accept2
67494
68070
  });
67495
68071
  }
67496
- assertHolds(paths, held, selector, accept);
68072
+ assertHolds(paths, held, selector, accept2);
67497
68073
  }
67498
68074
  ctx.registry.touch(record);
67499
68075
  const facts = paths.map(factOf);
@@ -67574,7 +68150,7 @@ async function readBack(ctx, record, objectId) {
67574
68150
  });
67575
68151
  return answer?.result?.value ?? null;
67576
68152
  }
67577
- function assertHolds(paths, held, selector, accept) {
68153
+ function assertHolds(paths, held, selector, accept2) {
67578
68154
  const expected = paths.map((path2) => path$1.basename(path2));
67579
68155
  const mismatch = held.count !== expected.length || expected.some((name, index) => held.names[index] !== name) || paths.some((path2, index) => sizeOf(path2) !== held.sizes[index]);
67580
68156
  if (!mismatch) return;
@@ -67585,7 +68161,7 @@ function assertHolds(paths, held, selector, accept) {
67585
68161
  selector,
67586
68162
  attached: expected,
67587
68163
  held: held.names,
67588
- accept,
68164
+ accept: accept2,
67589
68165
  reason: "read_back_mismatch"
67590
68166
  }
67591
68167
  );
@@ -67740,7 +68316,7 @@ function collectAddressHistory(tabs2, activeTabId) {
67740
68316
  function foldAscii(value) {
67741
68317
  return value.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
67742
68318
  }
67743
- function mergeAddressHistory(tabEntries, historyEntries, query, limit) {
68319
+ function mergeAddressHistory(tabEntries, historyEntries, query2, limit) {
67744
68320
  const cap = Math.max(0, Math.floor(limit));
67745
68321
  if (cap === 0) return [];
67746
68322
  const seen = /* @__PURE__ */ new Set();
@@ -67758,7 +68334,7 @@ function mergeAddressHistory(tabEntries, historyEntries, query, limit) {
67758
68334
  source: "history"
67759
68335
  });
67760
68336
  }
67761
- const needle = foldAscii(query.trim());
68337
+ const needle = foldAscii(query2.trim());
67762
68338
  for (const entry of tabEntries) {
67763
68339
  if (merged.length >= cap) break;
67764
68340
  if (seen.has(entry.url)) continue;
@@ -68192,25 +68768,25 @@ class PageControls {
68192
68768
  };
68193
68769
  active.view.webContents.on("found-in-page", this.listener);
68194
68770
  }
68195
- search(active, query, forward, next) {
68771
+ search(active, query2, forward, next) {
68196
68772
  this.open(active);
68197
68773
  if (!this.find || this.record !== active) return;
68198
68774
  this.stopTimer();
68199
- const same = this.find.query === query;
68775
+ const same = this.find.query === query2;
68200
68776
  const continuing = same && next && this.requestId !== null && !this.find.unreported;
68201
68777
  this.requestId = null;
68202
68778
  this.find = {
68203
68779
  ...this.find,
68204
- query,
68205
- pending: query.length > 0,
68780
+ query: query2,
68781
+ pending: query2.length > 0,
68206
68782
  unreported: false,
68207
68783
  ...same ? {} : { ordinal: 0, matches: 0 }
68208
68784
  };
68209
- if (!query) {
68785
+ if (!query2) {
68210
68786
  active.view.webContents.stopFindInPage?.("clearSelection");
68211
68787
  return;
68212
68788
  }
68213
- this.requestId = active.view.webContents.findInPage?.(query, {
68789
+ this.requestId = active.view.webContents.findInPage?.(query2, {
68214
68790
  forward,
68215
68791
  // Electron's misleading name means NEW SESSION (44.3 native maps
68216
68792
  // it to options->new_session), not "advance". Initial/changed/retry
@@ -68365,6 +68941,12 @@ const DOCUMENT_SCOPED = /* @__PURE__ */ new Set([
68365
68941
  "hit_test",
68366
68942
  "ancestors",
68367
68943
  "snapshot",
68944
+ // `query` is a read of the CURRENT document's DOM (CSS in, descriptors out),
68945
+ // so it is authorized against that document on entry and again on the result
68946
+ // exactly as `read` is: an answer that raced a navigation it did not cause
68947
+ // must be discarded, not reported as the new page's (agent review round 2 on
68948
+ // the query slice — the action was missing from BOTH sets).
68949
+ "query",
68368
68950
  "screenshot",
68369
68951
  "click",
68370
68952
  "type",
@@ -68395,6 +68977,7 @@ const TAB_SCOPED = /* @__PURE__ */ new Set([
68395
68977
  "hit_test",
68396
68978
  "ancestors",
68397
68979
  "snapshot",
68980
+ "query",
68398
68981
  "screenshot",
68399
68982
  "click",
68400
68983
  "type",
@@ -68612,6 +69195,8 @@ class BrowserHost {
68612
69195
  return hitTest(this, params);
68613
69196
  case "ancestors":
68614
69197
  return ancestors(this, params);
69198
+ case "query":
69199
+ return query(this, params);
68615
69200
  case "snapshot":
68616
69201
  return snapshot(this, params);
68617
69202
  case "scroll":
@@ -69023,7 +69608,7 @@ class BrowserHost {
69023
69608
  onChordFocusChanged;
69024
69609
  /** An explicit tab id fences queued chrome intents: a switch between key
69025
69610
  * delivery and IPC must never search/zoom the newly active tab instead. */
69026
- async controlPage(tabId, action, query = "", forward = true, next = false) {
69611
+ async controlPage(tabId, action, query2 = "", forward = true, next = false) {
69027
69612
  return this.registry.lane(tabId, async () => {
69028
69613
  const active = this.registry.activeTab;
69029
69614
  if (!active || active.tabId !== tabId || !active.presented || active.view.webContents.isDestroyed())
@@ -69032,7 +69617,7 @@ class BrowserHost {
69032
69617
  else if (action === "print") this.pageControls.print(active);
69033
69618
  else if (action === "close") this.pageControls.clear();
69034
69619
  else if (action === "search")
69035
- this.pageControls.search(active, query, forward, next);
69620
+ this.pageControls.search(active, query2, forward, next);
69036
69621
  else this.pageControls.zoom(active, action);
69037
69622
  this.onChanged();
69038
69623
  return this.chromeState();
@@ -70682,18 +71267,18 @@ function registerBrowserIpc(options) {
70682
71267
  });
70683
71268
  electron.ipcMain.handle(
70684
71269
  "browser-page-control",
70685
- (event, tabId, action, query, forward, next) => {
71270
+ (event, tabId, action, query2, forward, next) => {
70686
71271
  const host = authorize(event);
70687
71272
  if (typeof action !== "string" || !["open", "close", "search", "print", "in", "out", "reset"].includes(
70688
71273
  action
70689
71274
  ))
70690
71275
  throw new Error("Invalid page control action.");
70691
- if (typeof query !== "string" || query.length > 4096 || typeof forward !== "boolean" || typeof next !== "boolean")
71276
+ if (typeof query2 !== "string" || query2.length > 4096 || typeof forward !== "boolean" || typeof next !== "boolean")
70692
71277
  throw new Error("Invalid page search input.");
70693
71278
  return host.controlPage(
70694
71279
  numberOrThrow(tabId, "tabId"),
70695
71280
  action,
70696
- query,
71281
+ query2,
70697
71282
  forward,
70698
71283
  next
70699
71284
  );
@@ -70903,14 +71488,14 @@ function addressHistoryRequestOrThrow(value) {
70903
71488
  if (typeof request.query !== "string") {
70904
71489
  throw new Error("The address history query must be a string.");
70905
71490
  }
70906
- const query = request.query;
70907
- if (query.length > ADDRESS_HISTORY_MAX_QUERY_LENGTH || CONTROL_CHARS.test(query)) {
71491
+ const query2 = request.query;
71492
+ if (query2.length > ADDRESS_HISTORY_MAX_QUERY_LENGTH || CONTROL_CHARS.test(query2)) {
70908
71493
  throw new Error("The address history query is invalid.");
70909
71494
  }
70910
71495
  if (typeof request.limit !== "number" || !Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > ADDRESS_HISTORY_MAX_LIMIT) {
70911
71496
  throw new Error("The address history limit is invalid.");
70912
71497
  }
70913
- return { requestId: requestId2, expectedTabId, query, limit: request.limit };
71498
+ return { requestId: requestId2, expectedTabId, query: query2, limit: request.limit };
70914
71499
  }
70915
71500
  function closeTabsIntentOrThrow(value) {
70916
71501
  if (!value || typeof value !== "object") {
@@ -74744,6 +75329,41 @@ class DesktopNotifier {
74744
75329
  notification.show();
74745
75330
  }
74746
75331
  }
75332
+ const ATTACH_FLAG = "--attach";
75333
+ function readAttachArguments(argv) {
75334
+ const paths = [];
75335
+ const problems = [];
75336
+ for (let index = 0; index < argv.length; index += 1) {
75337
+ const argument = argv[index];
75338
+ if (argument === ATTACH_FLAG) {
75339
+ const value = argv[index + 1];
75340
+ if (!value || value.startsWith("--")) {
75341
+ problems.push(`${ATTACH_FLAG} needs an absolute path`);
75342
+ continue;
75343
+ }
75344
+ index += 1;
75345
+ accept(value, paths, problems);
75346
+ continue;
75347
+ }
75348
+ if (argument.startsWith(`${ATTACH_FLAG}=`)) {
75349
+ accept(argument.slice(ATTACH_FLAG.length + 1), paths, problems);
75350
+ }
75351
+ }
75352
+ return { paths, problems };
75353
+ }
75354
+ function accept(value, paths, problems) {
75355
+ if (!value.trim()) {
75356
+ problems.push(`${ATTACH_FLAG} needs an absolute path`);
75357
+ return;
75358
+ }
75359
+ if (!path$1.isAbsolute(value)) {
75360
+ problems.push(
75361
+ `${ATTACH_FLAG} takes an absolute path (got ${JSON.stringify(value)})`
75362
+ );
75363
+ return;
75364
+ }
75365
+ paths.push(value);
75366
+ }
74747
75367
  const FRAME_LABEL = /^[a-z0-9][a-z0-9_-]{0,63}$/;
74748
75368
  function registerDevDriverIPC(options) {
74749
75369
  const { window, expectedUrl, outDir, identity: identity2 } = options;
@@ -84260,18 +84880,18 @@ function frameNavigationVerdict(input, trustedRendererUrls) {
84260
84880
  return ALLOW;
84261
84881
  return deny(`a child frame may not navigate to ${url.protocol}`);
84262
84882
  }
84263
- function permissionVerdict(query, trustedRendererUrls) {
84264
- if (!query.isMainFrame) return false;
84883
+ function permissionVerdict(query2, trustedRendererUrls) {
84884
+ if (!query2.isMainFrame) return false;
84265
84885
  if (!trustedRendererUrls.some(
84266
- (trusted) => trustedDesktopFrame(query.requestingUrl, trusted)
84886
+ (trusted) => trustedDesktopFrame(query2.requestingUrl, trusted)
84267
84887
  ))
84268
84888
  return false;
84269
- if (query.permission === "clipboard-sanitized-write" || query.permission === "fullscreen")
84889
+ if (query2.permission === "clipboard-sanitized-write" || query2.permission === "fullscreen")
84270
84890
  return true;
84271
- if (query.permission !== "media") return false;
84272
- if (query.mediaTypes)
84273
- return query.mediaTypes.length > 0 && query.mediaTypes.every((type2) => type2 === "audio");
84274
- return query.mediaType === "audio";
84891
+ if (query2.permission !== "media") return false;
84892
+ if (query2.mediaTypes)
84893
+ return query2.mediaTypes.length > 0 && query2.mediaTypes.every((type2) => type2 === "audio");
84894
+ return query2.mediaType === "audio";
84275
84895
  }
84276
84896
  function decodedPathname(pathname) {
84277
84897
  let current = pathname;
@@ -85089,6 +85709,13 @@ const devDriverArming = resolveDevDriverArming({
85089
85709
  });
85090
85710
  const devDriverLine = describeDevDriverArming(devDriverArming);
85091
85711
  if (devDriverLine) console.log(devDriverLine);
85712
+ const attachQueue = devDriverArming.armed ? readAttachArguments(process.argv) : { paths: [], problems: [] };
85713
+ for (const problem of attachQueue.problems)
85714
+ console.error(`[dev-driver] ${problem}`);
85715
+ if (devDriverArming.armed && attachQueue.paths.length > 0)
85716
+ console.log(
85717
+ `[dev-driver] attach queue: ${attachQueue.paths.length} path(s) will answer the next file dialog`
85718
+ );
85092
85719
  const addressOverlayGate = resolveAddressOverlayGate({
85093
85720
  env: launchEnv,
85094
85721
  devDriverArmed: devDriverArming.armed,
@@ -85914,6 +86541,24 @@ electron.app.whenReady().then(async () => {
85914
86541
  }
85915
86542
  }
85916
86543
  );
86544
+ electron.ipcMain.handle(
86545
+ "upload-attachment",
86546
+ async (event, source) => {
86547
+ if (!isAdmittedSender(event, trustedLocalFileSenders())) {
86548
+ return {
86549
+ success: false,
86550
+ code: "unreadable",
86551
+ error: "This window cannot read local files."
86552
+ };
86553
+ }
86554
+ const resolved = source.kind === "path" ? { ...source, path: resolveUserPath(source.path) } : source;
86555
+ return uploadAttachment({
86556
+ source: resolved,
86557
+ backendUrl: backendService.getBackendUrl(),
86558
+ token: backendService.getDesktopToken()
86559
+ });
86560
+ }
86561
+ );
85917
86562
  electron.ipcMain.handle("open-external", async (_, url) => openExternalVetted(url));
85918
86563
  electron.ipcMain.handle(
85919
86564
  "show-item-in-folder",
@@ -85959,6 +86604,13 @@ electron.app.whenReady().then(async () => {
85959
86604
  }
85960
86605
  });
85961
86606
  electron.ipcMain.handle("show-open-dialog", async (event, options) => {
86607
+ if (attachQueue.paths.length > 0) {
86608
+ const filePaths = attachQueue.paths.splice(0);
86609
+ console.log(
86610
+ `[dev-driver] answered the file dialog with ${filePaths.length} queued path(s)`
86611
+ );
86612
+ return { canceled: false, filePaths };
86613
+ }
85962
86614
  const parent = electron.BrowserWindow.fromWebContents(event.sender) ?? mainWindow;
85963
86615
  if (!parent) {
85964
86616
  logger.error(