local-operator-ui 0.41.1 → 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.
- package/out/main/index.js +1242 -226
- package/out/preload/index.js +102 -4
- package/out/renderer/assets/{_basePickBy-BP7Q8i4W.js → _basePickBy-KfApUmWE.js} +1 -1
- package/out/renderer/assets/{_baseUniq-D36dAcoY.js → _baseUniq-DXd1h_x3.js} +1 -1
- package/out/renderer/assets/{agent-details-page-D3ljlPdf.js → agent-details-page-D-oKoyjm.js} +2 -2
- package/out/renderer/assets/{agent-hub-page-BMyIHnNM.js → agent-hub-page-CMbCN_Bg.js} +2 -2
- package/out/renderer/assets/agents-page-COpZu9CS.js +7 -0
- package/out/renderer/assets/{arc-GVvow4so.js → arc-Dim07OWx.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-IEHRJDOE-BjGwXAtH.js → architectureDiagram-IEHRJDOE-BdwEpGi5.js} +1 -1
- package/out/renderer/assets/{blockDiagram-JOT3LUYC-BTuigKlt.js → blockDiagram-JOT3LUYC-BcLFfkMT.js} +1 -1
- package/out/renderer/assets/{book-open-C1uak1LZ.js → book-open-C2DZijqP.js} +1 -1
- package/out/renderer/assets/browser-page-DzwNid1n.js +1 -0
- package/out/renderer/assets/{browser-webauthn-prompt-CzYoJfO4.js → browser-webauthn-prompt-C4aaSeT0.js} +1 -1
- package/out/renderer/assets/{building-2-Bpz1qaDa.js → building-2-DfFTqKaJ.js} +1 -1
- package/out/renderer/assets/{c4Diagram-VJAJSXHY-DK7eaKE8.js → c4Diagram-VJAJSXHY-Dm38eTOl.js} +1 -1
- package/out/renderer/assets/channel-CefUnWw7.js +1 -0
- package/out/renderer/assets/{chunk-4BMEZGHF-DkQrsDhM.js → chunk-4BMEZGHF-94enK1_-.js} +1 -1
- package/out/renderer/assets/{chunk-A2AXSNBT-guh0INPR.js → chunk-A2AXSNBT-YiigwCRa.js} +1 -1
- package/out/renderer/assets/{chunk-AEK57VVT-DvgIx6-r.js → chunk-AEK57VVT-Bo9PQDfg.js} +1 -1
- package/out/renderer/assets/{chunk-D6G4REZN-FNdvnFYo.js → chunk-D6G4REZN-vwOZoeTn.js} +1 -1
- package/out/renderer/assets/{chunk-RZ5BOZE2-CgCQC9Mn.js → chunk-RZ5BOZE2-BY9NQkOq.js} +1 -1
- package/out/renderer/assets/{chunk-XZIHB7SX-D1VRTTc4.js → chunk-XZIHB7SX-D31wKKrQ.js} +1 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-BKByQj4B.js +1 -0
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-BKByQj4B.js +1 -0
- package/out/renderer/assets/clone-DpeVXG90.js +1 -0
- package/out/renderer/assets/{console-mirror-DRkz3vUY.js → console-mirror-ClsQ7RUr.js} +1 -1
- package/out/renderer/assets/{consoleCapture-BJfSUatx.js → consoleCapture-DHR2J1Z2.js} +1 -1
- package/out/renderer/assets/{conversation-input-sync-CJU5GIzR.js → conversation-input-sync-CxT2etWK.js} +271 -251
- package/out/renderer/assets/{dagre-OKDRZEBW-DeeYQh6O.js → dagre-OKDRZEBW-DV8UoEV8.js} +1 -1
- package/out/renderer/assets/{diagram-SSKATNLV-DD-xNxKH.js → diagram-SSKATNLV-KF8nQEWd.js} +1 -1
- package/out/renderer/assets/{diagram-VNBRO52H-YAoPlXaR.js → diagram-VNBRO52H-P7VEv-Kl.js} +1 -1
- package/out/renderer/assets/{erDiagram-Q7BY3M3F-OKzGXyMI.js → erDiagram-Q7BY3M3F-B17XYgVW.js} +1 -1
- package/out/renderer/assets/{error-boundary-ZYkSCpZC.js → error-boundary-DBgLhXDJ.js} +1 -1
- package/out/renderer/assets/{flowDiagram-4HSFHLVR-BG-3pPqS.js → flowDiagram-4HSFHLVR-BuuUG-g9.js} +1 -1
- package/out/renderer/assets/{ganttDiagram-APWFNJXF-CRyD5vsE.js → ganttDiagram-APWFNJXF-D8R9R-AO.js} +1 -1
- package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-aly2C__q.js → gitGraphDiagram-7IBYFJ6S-fr4ArrNz.js} +1 -1
- package/out/renderer/assets/{graph-CCWwMmhg.js → graph-nV36Izm2.js} +1 -1
- package/out/renderer/assets/{hash-BN0ECl3H.js → hash-0qLX32ng.js} +1 -1
- package/out/renderer/assets/{heart-tKYqMVIH.js → heart-DFAcW-lm.js} +1 -1
- package/out/renderer/assets/{index-DaCf2W9T.js → index-BKg4FYjW.js} +1 -1
- package/out/renderer/assets/index-BlshO0D3.css +1 -0
- package/out/renderer/assets/{index-BaNzqqGN.js → index-BmixXvR4.js} +1 -1
- package/out/renderer/assets/index-D6Di-Q2H.js +57 -0
- package/out/renderer/assets/index-DQKtrmMo.js +830 -0
- package/out/renderer/assets/{infoDiagram-PH2N3AL5-BY536sF5.js → infoDiagram-PH2N3AL5-DmrijSS0.js} +1 -1
- package/out/renderer/assets/{installer-Dw1P6j8q.js → installer-4TSvERLS.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-U35MCT3I-DGvx__t6.js → journeyDiagram-U35MCT3I-BwwXu0up.js} +1 -1
- package/out/renderer/assets/{kanban-definition-NDS4AKOZ-CG2Lgkpw.js → kanban-definition-NDS4AKOZ-CDbDK3QO.js} +1 -1
- package/out/renderer/assets/{layout-vpRrwE7T.js → layout-B7RIhnQw.js} +1 -1
- package/out/renderer/assets/{legacy-agents-page-D6Yma1Gm.js → legacy-agents-page-DFGXD5LW.js} +6 -6
- package/out/renderer/assets/library-page-DPid0cmw.js +157 -0
- package/out/renderer/assets/{mermaid.core-COeGB8I0.js → mermaid.core-DcMJPeY9.js} +5 -5
- package/out/renderer/assets/{mesh-page-PabU05tN.js → mesh-page-CIV9irJF.js} +1 -1
- package/out/renderer/assets/{mindmap-definition-ALO5MXBD-B0hkjZLY.js → mindmap-definition-ALO5MXBD-aLvI45Tt.js} +1 -1
- package/out/renderer/assets/mini-leTyoKhc.js +1 -0
- package/out/renderer/assets/{notebook-pen-C3CwzwGA.js → notebook-pen-ClukfLau.js} +1 -1
- package/out/renderer/assets/{org-access-BacMtLkn.js → org-access-BmjQJdOO.js} +1 -1
- package/out/renderer/assets/{org-surface-gate-tkB025lu.js → org-surface-gate-B66nUFl-.js} +1 -1
- package/out/renderer/assets/{page-header-6mrV9W-E.js → page-header-C8bsR5wI.js} +1 -1
- package/out/renderer/assets/path-utils-DbnynqGJ.js +58 -0
- package/out/renderer/assets/{pieDiagram-IB7DONF6-DfFtQXU5.js → pieDiagram-IB7DONF6-DvzUPikw.js} +1 -1
- package/out/renderer/assets/projects-page-4Cv9HMNh.js +45 -0
- package/out/renderer/assets/{publication-validation-B0Mf3mmP.js → publication-validation-BlKeNjlY.js} +1 -1
- package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-C4eDJWaK.js → quadrantDiagram-7GDLP6J5-DFsFogdr.js} +1 -1
- package/out/renderer/assets/{radar-MK3ICKWK-BEv1HS9Q.js → radar-MK3ICKWK-YGPF88zl.js} +1 -1
- package/out/renderer/assets/{radient-auth-buttons-BX5vf982.js → radient-auth-buttons-syGP58Ed.js} +1 -1
- package/out/renderer/assets/{requirementDiagram-KVF5MWMF-B7f3qUcB.js → requirementDiagram-KVF5MWMF-x2D5VXdu.js} +1 -1
- package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-xM7E-74l.js → sankeyDiagram-QLVOVGJD-DA4pKMXD.js} +1 -1
- package/out/renderer/assets/{schedules-page-5q7pvL1H.js → schedules-page-CLrwsPcv.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-upwR02kU.js → sequenceDiagram-X6HHIX6F-BUX2Yk2J.js} +1 -1
- package/out/renderer/assets/{settings-page-DcnGr-GP.js → settings-page-BAVKJQXi.js} +9 -9
- package/out/renderer/assets/{smartart-CYnMNs5u.js → smartart-ipuU9VIr.js} +1 -1
- package/out/renderer/assets/{stateDiagram-DGXRK772-BqTri7Q-.js → stateDiagram-DGXRK772-BsVvaiaW.js} +1 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-BvVuptXT.js +1 -0
- package/out/renderer/assets/team-bridge-page-DU_d4Yfc.js +16 -0
- package/out/renderer/assets/{timeline-definition-BDJGKUSR-Bi2is17s.js → timeline-definition-BDJGKUSR-Doja7siy.js} +1 -1
- package/out/renderer/assets/{use-download-agent-mutation-PHtokPlg.js → use-download-agent-mutation-CH4V_o78.js} +2 -2
- package/out/renderer/assets/{use-session-snapshot-B5sxthdQ.js → use-session-snapshot-7A4rQnOH.js} +1 -1
- package/out/renderer/assets/{xychartDiagram-VJFVF3MP-B0TrjzLJ.js → xychartDiagram-VJFVF3MP-D2e6wZz8.js} +1 -1
- package/out/renderer/console-capture.html +5 -5
- package/out/renderer/index.html +7 -7
- package/out/renderer/installer.html +4 -4
- package/out/renderer/mini.html +7 -7
- package/package.json +4 -3
- package/out/renderer/assets/agents-page-mMqgQd2V.js +0 -7
- package/out/renderer/assets/browser-page-B3mjDx8k.js +0 -1
- package/out/renderer/assets/channel-B05rL6In.js +0 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-DpB8-8cT.js +0 -1
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-DpB8-8cT.js +0 -1
- package/out/renderer/assets/clone-BHHjv3HP.js +0 -1
- package/out/renderer/assets/index-BDzV3bGH.js +0 -57
- package/out/renderer/assets/index-CRjnV9wx.js +0 -835
- package/out/renderer/assets/index-ZovyVTxQ.css +0 -1
- package/out/renderer/assets/library-page-B0gC-rRh.js +0 -157
- package/out/renderer/assets/mini-Df5C4rpd.js +0 -1
- package/out/renderer/assets/path-utils-Ct0VTUZS.js +0 -58
- package/out/renderer/assets/projects-page-CoHTKLZH.js +0 -45
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-D8Sl1QhX.js +0 -1
- package/out/renderer/assets/team-bridge-page-vnNJdCi3.js +0 -16
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(
|
|
218
|
+
function appendJournalOrderIds(query2, path2, ids) {
|
|
217
219
|
let bytes = new TextEncoder().encode(
|
|
218
|
-
`${path2}${
|
|
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
|
-
|
|
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"),
|
|
@@ -2423,6 +2467,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
2423
2467
|
}).strict(),
|
|
2424
2468
|
zod.z.object({
|
|
2425
2469
|
op: zod.z.literal("team_bridge.conversations.create"),
|
|
2470
|
+
expected_account_id: id$1.optional(),
|
|
2426
2471
|
tenant_id: id$1.optional(),
|
|
2427
2472
|
kind: zod.z.enum(["dm", "group", "channel"]),
|
|
2428
2473
|
name: zod.z.string().min(1).max(128).optional(),
|
|
@@ -2440,6 +2485,8 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
2440
2485
|
}).strict(),
|
|
2441
2486
|
zod.z.object({
|
|
2442
2487
|
op: zod.z.literal("team_bridge.conversations.lifecycle"),
|
|
2488
|
+
expected_account_id: id$1.optional(),
|
|
2489
|
+
tenant_id: id$1.optional(),
|
|
2443
2490
|
conversation_id: id$1,
|
|
2444
2491
|
action: zod.z.enum(["archive", "unarchive", "join", "leave"])
|
|
2445
2492
|
}).strict(),
|
|
@@ -2456,17 +2503,20 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
2456
2503
|
*/
|
|
2457
2504
|
zod.z.object({
|
|
2458
2505
|
op: zod.z.literal("team_bridge.conversations.join"),
|
|
2506
|
+
expected_account_id: id$1.optional(),
|
|
2459
2507
|
conversation_id: id$1,
|
|
2460
2508
|
tenant_id: id$1.optional()
|
|
2461
2509
|
}).strict(),
|
|
2462
2510
|
zod.z.object({
|
|
2463
2511
|
op: zod.z.literal("team_bridge.conversations.notify"),
|
|
2512
|
+
expected_account_id: id$1.optional(),
|
|
2464
2513
|
conversation_id: id$1,
|
|
2465
2514
|
tenant_id: id$1.optional(),
|
|
2466
2515
|
notify: zod.z.enum(["all", "mention", "mute"])
|
|
2467
2516
|
}).strict(),
|
|
2468
2517
|
zod.z.object({
|
|
2469
2518
|
op: zod.z.literal("team_bridge.conversations.members.add"),
|
|
2519
|
+
expected_account_id: id$1.optional(),
|
|
2470
2520
|
conversation_id: id$1,
|
|
2471
2521
|
tenant_id: id$1.optional(),
|
|
2472
2522
|
members: zod.z.array(
|
|
@@ -2480,11 +2530,14 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
2480
2530
|
}).strict(),
|
|
2481
2531
|
zod.z.object({
|
|
2482
2532
|
op: zod.z.literal("team_bridge.conversations.members.remove"),
|
|
2533
|
+
expected_account_id: id$1.optional(),
|
|
2534
|
+
tenant_id: id$1.optional(),
|
|
2483
2535
|
conversation_id: id$1,
|
|
2484
2536
|
account_id: id$1
|
|
2485
2537
|
}).strict(),
|
|
2486
2538
|
zod.z.object({
|
|
2487
2539
|
op: zod.z.literal("team_bridge.conversations.consent"),
|
|
2540
|
+
expected_account_id: id$1.optional(),
|
|
2488
2541
|
conversation_id: id$1,
|
|
2489
2542
|
account_id: id$1,
|
|
2490
2543
|
decision: zod.z.enum(["accept", "decline"]),
|
|
@@ -2509,6 +2562,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
2509
2562
|
}).strict(),
|
|
2510
2563
|
zod.z.object({
|
|
2511
2564
|
op: zod.z.literal("team_bridge.messages.send"),
|
|
2565
|
+
expected_account_id: id$1.optional(),
|
|
2512
2566
|
conversation_id: id$1,
|
|
2513
2567
|
tenant_id: id$1.optional(),
|
|
2514
2568
|
client_ref: id$1,
|
|
@@ -2531,6 +2585,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
2531
2585
|
}).strict(),
|
|
2532
2586
|
zod.z.object({
|
|
2533
2587
|
op: zod.z.literal("team_bridge.read"),
|
|
2588
|
+
expected_account_id: id$1.optional(),
|
|
2534
2589
|
conversation_id: id$1,
|
|
2535
2590
|
tenant_id: id$1.optional(),
|
|
2536
2591
|
seq: zod.z.number().int().nonnegative().optional(),
|
|
@@ -3058,6 +3113,14 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
3058
3113
|
]);
|
|
3059
3114
|
const desktopRequestSchema = desktopRequestUnion.superRefine(
|
|
3060
3115
|
(request, ctx) => {
|
|
3116
|
+
if (request.op.startsWith("team_bridge.") && "expected_account_id" in request && request.expected_account_id && (!("tenant_id" in request) || !request.tenant_id)) {
|
|
3117
|
+
ctx.addIssue({
|
|
3118
|
+
code: zod.z.ZodIssueCode.custom,
|
|
3119
|
+
path: ["tenant_id"],
|
|
3120
|
+
message: "Guarded conversation writes require an explicit tenant"
|
|
3121
|
+
});
|
|
3122
|
+
return;
|
|
3123
|
+
}
|
|
3061
3124
|
if (request.op === "hub.skillPull" || request.op === "hub.skillSubscribe" || request.op === "hub.skillPublish") {
|
|
3062
3125
|
if (request.visibility === "public" && request.tenantId !== null || request.visibility === "org" && !request.tenantId) {
|
|
3063
3126
|
ctx.addIssue({
|
|
@@ -3147,7 +3210,22 @@ const desktopRequestSchema = desktopRequestUnion.superRefine(
|
|
|
3147
3210
|
message: "ask_id must be a non-empty string",
|
|
3148
3211
|
path: ["askId"]
|
|
3149
3212
|
});
|
|
3150
|
-
if (request.
|
|
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)
|
|
3151
3229
|
ctx.addIssue({
|
|
3152
3230
|
code: zod.z.ZodIssueCode.custom,
|
|
3153
3231
|
message: "A queued-ask answer needs answers or decline",
|
|
@@ -3191,6 +3269,18 @@ const desktopRequestSchema = desktopRequestUnion.superRefine(
|
|
|
3191
3269
|
message: "revise applies to a queued ask",
|
|
3192
3270
|
path: ["revise"]
|
|
3193
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
|
+
});
|
|
3194
3284
|
return;
|
|
3195
3285
|
}
|
|
3196
3286
|
if (request.op === "sessions.create" && request.purpose === void 0) {
|
|
@@ -3631,6 +3721,13 @@ function harnessImportBody(request) {
|
|
|
3631
3721
|
...request.maxSessions === void 0 ? {} : { max_sessions: request.maxSessions }
|
|
3632
3722
|
};
|
|
3633
3723
|
}
|
|
3724
|
+
function conversationOwnerQuery(request) {
|
|
3725
|
+
const query2 = new URLSearchParams();
|
|
3726
|
+
if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
|
|
3727
|
+
if (request.expected_account_id)
|
|
3728
|
+
query2.set("expected_account_id", request.expected_account_id);
|
|
3729
|
+
return query2.size ? `?${query2.toString()}` : "";
|
|
3730
|
+
}
|
|
3634
3731
|
function tenantQuery(tenantId) {
|
|
3635
3732
|
return tenantId === void 0 ? "" : `?tenant_id=${encodeURIComponent(tenantId)}`;
|
|
3636
3733
|
}
|
|
@@ -3732,10 +3829,10 @@ function desktopEndpoint(request) {
|
|
|
3732
3829
|
case "imports.sources":
|
|
3733
3830
|
return { path: "/v1/desktop/imports/sources", method: "GET" };
|
|
3734
3831
|
case "imports.sessions": {
|
|
3735
|
-
const
|
|
3736
|
-
if (request.includeSubagents)
|
|
3832
|
+
const query2 = new URLSearchParams({ source: request.source });
|
|
3833
|
+
if (request.includeSubagents) query2.set("include_subagents", "true");
|
|
3737
3834
|
return {
|
|
3738
|
-
path: `/v1/desktop/imports/sessions?${
|
|
3835
|
+
path: `/v1/desktop/imports/sessions?${query2.toString()}`,
|
|
3739
3836
|
method: "GET"
|
|
3740
3837
|
};
|
|
3741
3838
|
}
|
|
@@ -4000,13 +4097,13 @@ function desktopEndpoint(request) {
|
|
|
4000
4097
|
method: "POST"
|
|
4001
4098
|
};
|
|
4002
4099
|
case "sessions.search": {
|
|
4003
|
-
const
|
|
4100
|
+
const query2 = new URLSearchParams({
|
|
4004
4101
|
q: request.q,
|
|
4005
4102
|
limit: String(request.limit ?? SESSION_SEARCH_DEFAULT_LIMIT)
|
|
4006
4103
|
});
|
|
4007
|
-
if (request.include_archived)
|
|
4104
|
+
if (request.include_archived) query2.set("include_archived", "true");
|
|
4008
4105
|
return {
|
|
4009
|
-
path: `/v1/desktop/sessions/search?${
|
|
4106
|
+
path: `/v1/desktop/sessions/search?${query2}`,
|
|
4010
4107
|
method: "GET"
|
|
4011
4108
|
};
|
|
4012
4109
|
}
|
|
@@ -4086,23 +4183,23 @@ function desktopEndpoint(request) {
|
|
|
4086
4183
|
}
|
|
4087
4184
|
};
|
|
4088
4185
|
case "sessions.get": {
|
|
4089
|
-
const
|
|
4186
|
+
const query2 = new URLSearchParams();
|
|
4090
4187
|
if (request.journalOrder) {
|
|
4091
|
-
|
|
4092
|
-
if (request.peerJournalSource)
|
|
4188
|
+
query2.set("journal_order", "1");
|
|
4189
|
+
if (request.peerJournalSource) query2.set("peer_journal_source", "1");
|
|
4093
4190
|
appendJournalOrderIds(
|
|
4094
|
-
|
|
4191
|
+
query2,
|
|
4095
4192
|
`/v1/desktop/sessions/${request.sessionId}`,
|
|
4096
4193
|
request.orderIds ?? []
|
|
4097
4194
|
);
|
|
4098
4195
|
}
|
|
4099
4196
|
return {
|
|
4100
|
-
path: `/v1/desktop/sessions/${request.sessionId}${
|
|
4197
|
+
path: `/v1/desktop/sessions/${request.sessionId}${query2.size ? `?${query2}` : ""}`,
|
|
4101
4198
|
method: "GET"
|
|
4102
4199
|
};
|
|
4103
4200
|
}
|
|
4104
4201
|
case "sessions.files": {
|
|
4105
|
-
const
|
|
4202
|
+
const query2 = new URLSearchParams({
|
|
4106
4203
|
limit: String(request.limit ?? 200)
|
|
4107
4204
|
});
|
|
4108
4205
|
for (const key of [
|
|
@@ -4114,10 +4211,10 @@ function desktopEndpoint(request) {
|
|
|
4114
4211
|
"cursor"
|
|
4115
4212
|
]) {
|
|
4116
4213
|
const value = request[key];
|
|
4117
|
-
if (value !== void 0)
|
|
4214
|
+
if (value !== void 0) query2.set(key, value);
|
|
4118
4215
|
}
|
|
4119
4216
|
return {
|
|
4120
|
-
path: `/v1/desktop/sessions/${encodeURIComponent(request.sessionId)}/files?${
|
|
4217
|
+
path: `/v1/desktop/sessions/${encodeURIComponent(request.sessionId)}/files?${query2}`,
|
|
4121
4218
|
method: "GET"
|
|
4122
4219
|
};
|
|
4123
4220
|
}
|
|
@@ -4127,34 +4224,34 @@ function desktopEndpoint(request) {
|
|
|
4127
4224
|
method: "POST"
|
|
4128
4225
|
};
|
|
4129
4226
|
case "sessions.history": {
|
|
4130
|
-
const
|
|
4227
|
+
const query2 = new URLSearchParams({
|
|
4131
4228
|
limit: String(request.limit ?? 100)
|
|
4132
4229
|
});
|
|
4133
|
-
if (request.beforeId)
|
|
4230
|
+
if (request.beforeId) query2.set("before_id", request.beforeId);
|
|
4134
4231
|
if (request.openFrame) {
|
|
4135
|
-
|
|
4136
|
-
|
|
4232
|
+
query2.set("open_frame", "1");
|
|
4233
|
+
query2.set("supplements", "1");
|
|
4137
4234
|
}
|
|
4138
4235
|
if (request.journalOrder) {
|
|
4139
|
-
|
|
4140
|
-
if (request.peerJournalSource)
|
|
4236
|
+
query2.set("journal_order", "1");
|
|
4237
|
+
if (request.peerJournalSource) query2.set("peer_journal_source", "1");
|
|
4141
4238
|
if (request.sourceRead === "metadata")
|
|
4142
|
-
|
|
4239
|
+
query2.set("source_read", "metadata");
|
|
4143
4240
|
else if (request.sourceRead === "payload" && request.expectedJournalGeneration)
|
|
4144
|
-
|
|
4241
|
+
query2.set("source_read", "payload");
|
|
4145
4242
|
if (request.expectedJournalGeneration)
|
|
4146
|
-
|
|
4243
|
+
query2.set(
|
|
4147
4244
|
"expected_journal_generation",
|
|
4148
4245
|
request.expectedJournalGeneration
|
|
4149
4246
|
);
|
|
4150
4247
|
appendJournalOrderIds(
|
|
4151
|
-
|
|
4248
|
+
query2,
|
|
4152
4249
|
`/v1/desktop/sessions/${request.sessionId}/history`,
|
|
4153
4250
|
request.orderIds ?? []
|
|
4154
4251
|
);
|
|
4155
4252
|
}
|
|
4156
4253
|
return {
|
|
4157
|
-
path: `/v1/desktop/sessions/${request.sessionId}/history?${
|
|
4254
|
+
path: `/v1/desktop/sessions/${request.sessionId}/history?${query2}`,
|
|
4158
4255
|
method: "GET"
|
|
4159
4256
|
};
|
|
4160
4257
|
}
|
|
@@ -4179,22 +4276,22 @@ function desktopEndpoint(request) {
|
|
|
4179
4276
|
}
|
|
4180
4277
|
};
|
|
4181
4278
|
case "sessions.find": {
|
|
4182
|
-
const
|
|
4279
|
+
const query2 = new URLSearchParams({
|
|
4183
4280
|
q: request.q,
|
|
4184
4281
|
limit: String(request.limit ?? THREAD_FIND_DEFAULT_LIMIT)
|
|
4185
4282
|
});
|
|
4186
4283
|
return {
|
|
4187
|
-
path: `/v1/desktop/sessions/${request.sessionId}/find?${
|
|
4284
|
+
path: `/v1/desktop/sessions/${request.sessionId}/find?${query2}`,
|
|
4188
4285
|
method: "GET"
|
|
4189
4286
|
};
|
|
4190
4287
|
}
|
|
4191
4288
|
case "subagents.transcript": {
|
|
4192
|
-
const
|
|
4289
|
+
const query2 = new URLSearchParams({
|
|
4193
4290
|
limit: String(request.limit ?? 100)
|
|
4194
4291
|
});
|
|
4195
|
-
if (request.beforeId)
|
|
4292
|
+
if (request.beforeId) query2.set("before_id", request.beforeId);
|
|
4196
4293
|
return {
|
|
4197
|
-
path: `/v1/desktop/sessions/${request.sessionId}/children/${request.childId}/transcript?${
|
|
4294
|
+
path: `/v1/desktop/sessions/${request.sessionId}/children/${request.childId}/transcript?${query2}`,
|
|
4198
4295
|
method: "GET"
|
|
4199
4296
|
};
|
|
4200
4297
|
}
|
|
@@ -4206,6 +4303,7 @@ function desktopEndpoint(request) {
|
|
|
4206
4303
|
request_id: request.requestId,
|
|
4207
4304
|
text: request.text,
|
|
4208
4305
|
images: request.images ?? [],
|
|
4306
|
+
...request.files?.length ? { files: request.files } : {},
|
|
4209
4307
|
mode: request.mode ?? "prompt",
|
|
4210
4308
|
/*
|
|
4211
4309
|
* ABSENT, not empty, when the app has nothing to say: an older harness
|
|
@@ -4246,7 +4344,16 @@ function desktopEndpoint(request) {
|
|
|
4246
4344
|
* body that carried `revise: false` on every ordinary submit would be
|
|
4247
4345
|
* asserting an intent it does not have.
|
|
4248
4346
|
*/
|
|
4249
|
-
...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
|
+
} : {}
|
|
4250
4357
|
}
|
|
4251
4358
|
};
|
|
4252
4359
|
return {
|
|
@@ -4424,12 +4531,12 @@ function desktopEndpoint(request) {
|
|
|
4424
4531
|
method: "DELETE"
|
|
4425
4532
|
};
|
|
4426
4533
|
case "legacy.models": {
|
|
4427
|
-
const
|
|
4428
|
-
if (request.provider)
|
|
4429
|
-
if (request.sort)
|
|
4430
|
-
if (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);
|
|
4431
4538
|
return {
|
|
4432
|
-
path:
|
|
4539
|
+
path: query2.size > 0 ? `/v1/models?${query2}` : "/v1/models",
|
|
4433
4540
|
method: "GET"
|
|
4434
4541
|
};
|
|
4435
4542
|
}
|
|
@@ -4444,12 +4551,12 @@ function desktopEndpoint(request) {
|
|
|
4444
4551
|
return { path: `/v1/agents/${request.agentId}/upload`, method: "POST" };
|
|
4445
4552
|
case "agent.publish": {
|
|
4446
4553
|
assertPairedPublicationTarget(request);
|
|
4447
|
-
const
|
|
4554
|
+
const query2 = new URLSearchParams();
|
|
4448
4555
|
if (request.visibility === "org" && request.tenantId) {
|
|
4449
|
-
|
|
4450
|
-
|
|
4556
|
+
query2.set("visibility", "org");
|
|
4557
|
+
query2.set("tenant_id", request.tenantId);
|
|
4451
4558
|
}
|
|
4452
|
-
const search =
|
|
4559
|
+
const search = query2.toString();
|
|
4453
4560
|
return {
|
|
4454
4561
|
path: `/v1/agents/${request.agentId}/publish${search ? `?${search}` : ""}`,
|
|
4455
4562
|
method: "POST",
|
|
@@ -4466,12 +4573,12 @@ function desktopEndpoint(request) {
|
|
|
4466
4573
|
}
|
|
4467
4574
|
case "agent.republish": {
|
|
4468
4575
|
assertPairedPublicationTarget(request);
|
|
4469
|
-
const
|
|
4576
|
+
const query2 = new URLSearchParams();
|
|
4470
4577
|
if (request.visibility === "org" && request.tenantId) {
|
|
4471
|
-
|
|
4472
|
-
|
|
4578
|
+
query2.set("visibility", "org");
|
|
4579
|
+
query2.set("tenant_id", request.tenantId);
|
|
4473
4580
|
}
|
|
4474
|
-
const search =
|
|
4581
|
+
const search = query2.toString();
|
|
4475
4582
|
return {
|
|
4476
4583
|
path: `/v1/agents/${request.agentId}/publish${search ? `?${search}` : ""}`,
|
|
4477
4584
|
method: "PUT",
|
|
@@ -4485,49 +4592,49 @@ function desktopEndpoint(request) {
|
|
|
4485
4592
|
}
|
|
4486
4593
|
case "team.publish": {
|
|
4487
4594
|
assertPairedPublicationTarget(request);
|
|
4488
|
-
const
|
|
4595
|
+
const query2 = new URLSearchParams();
|
|
4489
4596
|
if (request.visibility === "org" && request.tenantId) {
|
|
4490
|
-
|
|
4491
|
-
|
|
4597
|
+
query2.set("visibility", "org");
|
|
4598
|
+
query2.set("tenant_id", request.tenantId);
|
|
4492
4599
|
}
|
|
4493
4600
|
return {
|
|
4494
|
-
path: `/v1/teams/${request.teamId}/publish${
|
|
4601
|
+
path: `/v1/teams/${request.teamId}/publish${query2.size ? `?${query2}` : ""}`,
|
|
4495
4602
|
method: "POST",
|
|
4496
4603
|
body: publicationPolicyBody(request)
|
|
4497
4604
|
};
|
|
4498
4605
|
}
|
|
4499
4606
|
case "team.pull": {
|
|
4500
|
-
const
|
|
4501
|
-
if (request.tenantId)
|
|
4502
|
-
const search =
|
|
4607
|
+
const query2 = new URLSearchParams();
|
|
4608
|
+
if (request.tenantId) query2.set("tenant_id", request.tenantId);
|
|
4609
|
+
const search = query2.toString();
|
|
4503
4610
|
return {
|
|
4504
4611
|
path: `/v1/teams/pull/${request.teamId}${search ? `?${search}` : ""}`,
|
|
4505
4612
|
method: "GET"
|
|
4506
4613
|
};
|
|
4507
4614
|
}
|
|
4508
4615
|
case "agent.nameAvailability": {
|
|
4509
|
-
const
|
|
4510
|
-
return { path: `/v1/agent-name-availability?${
|
|
4616
|
+
const query2 = new URLSearchParams({ name: request.name });
|
|
4617
|
+
return { path: `/v1/agent-name-availability?${query2}`, method: "GET" };
|
|
4511
4618
|
}
|
|
4512
4619
|
case "legacy.agents.list": {
|
|
4513
|
-
const
|
|
4620
|
+
const query2 = new URLSearchParams({
|
|
4514
4621
|
page: String(request.page ?? 1),
|
|
4515
4622
|
per_page: String(request.perPage ?? 10)
|
|
4516
4623
|
});
|
|
4517
|
-
if (request.name)
|
|
4518
|
-
if (request.sort)
|
|
4519
|
-
if (request.direction)
|
|
4520
|
-
return { path: `/v1/agents?${
|
|
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" };
|
|
4521
4628
|
}
|
|
4522
4629
|
case "legacy.agent.get":
|
|
4523
4630
|
return { path: `/v1/agents/${request.agentId}`, method: "GET" };
|
|
4524
4631
|
case "legacy.agent.history": {
|
|
4525
|
-
const
|
|
4632
|
+
const query2 = new URLSearchParams({
|
|
4526
4633
|
page: String(request.page ?? 1),
|
|
4527
4634
|
per_page: String(request.perPage ?? 10)
|
|
4528
4635
|
});
|
|
4529
4636
|
return {
|
|
4530
|
-
path: `/v1/agents/${request.agentId}/history?${
|
|
4637
|
+
path: `/v1/agents/${request.agentId}/history?${query2}`,
|
|
4531
4638
|
method: "GET"
|
|
4532
4639
|
};
|
|
4533
4640
|
}
|
|
@@ -4537,13 +4644,13 @@ function desktopEndpoint(request) {
|
|
|
4537
4644
|
* what the backend's models declare.
|
|
4538
4645
|
*/
|
|
4539
4646
|
case "wakes.list": {
|
|
4540
|
-
const
|
|
4647
|
+
const query2 = new URLSearchParams();
|
|
4541
4648
|
if (request.limit !== void 0)
|
|
4542
|
-
|
|
4649
|
+
query2.set("limit", String(request.limit));
|
|
4543
4650
|
if (request.includeDormant !== void 0)
|
|
4544
|
-
|
|
4651
|
+
query2.set("include_dormant", String(request.includeDormant));
|
|
4545
4652
|
return {
|
|
4546
|
-
path:
|
|
4653
|
+
path: query2.size > 0 ? `/v1/desktop/wakes?${query2}` : "/v1/desktop/wakes",
|
|
4547
4654
|
method: "GET"
|
|
4548
4655
|
};
|
|
4549
4656
|
}
|
|
@@ -4600,30 +4707,30 @@ function desktopEndpoint(request) {
|
|
|
4600
4707
|
method: "POST"
|
|
4601
4708
|
};
|
|
4602
4709
|
case "legacy.jobs.list": {
|
|
4603
|
-
const
|
|
4604
|
-
if (request.agentId)
|
|
4605
|
-
if (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);
|
|
4606
4713
|
return {
|
|
4607
|
-
path:
|
|
4714
|
+
path: query2.size > 0 ? `/v1/jobs?${query2}` : "/v1/jobs",
|
|
4608
4715
|
method: "GET"
|
|
4609
4716
|
};
|
|
4610
4717
|
}
|
|
4611
4718
|
case "legacy.job.get":
|
|
4612
4719
|
return { path: `/v1/jobs/${request.jobId}`, method: "GET" };
|
|
4613
4720
|
case "legacy.schedules.list": {
|
|
4614
|
-
const
|
|
4721
|
+
const query2 = new URLSearchParams({
|
|
4615
4722
|
page: String(request.page ?? 1),
|
|
4616
4723
|
per_page: String(request.perPage ?? 10)
|
|
4617
4724
|
});
|
|
4618
|
-
return { path: `/v1/schedules?${
|
|
4725
|
+
return { path: `/v1/schedules?${query2}`, method: "GET" };
|
|
4619
4726
|
}
|
|
4620
4727
|
case "legacy.agent.schedules.list": {
|
|
4621
|
-
const
|
|
4728
|
+
const query2 = new URLSearchParams({
|
|
4622
4729
|
page: String(request.page ?? 1),
|
|
4623
4730
|
per_page: String(request.perPage ?? 10)
|
|
4624
4731
|
});
|
|
4625
4732
|
return {
|
|
4626
|
-
path: `/v1/agents/${request.agentId}/schedules?${
|
|
4733
|
+
path: `/v1/agents/${request.agentId}/schedules?${query2}`,
|
|
4627
4734
|
method: "GET"
|
|
4628
4735
|
};
|
|
4629
4736
|
}
|
|
@@ -4688,29 +4795,29 @@ function desktopEndpoint(request) {
|
|
|
4688
4795
|
};
|
|
4689
4796
|
}
|
|
4690
4797
|
case "usage.get": {
|
|
4691
|
-
const
|
|
4798
|
+
const query2 = new URLSearchParams({
|
|
4692
4799
|
live: String(request.live ?? false),
|
|
4693
4800
|
refresh: String(request.refresh ?? false)
|
|
4694
4801
|
});
|
|
4695
|
-
if (request.provider)
|
|
4696
|
-
return { path: `/v1/desktop/usage?${
|
|
4802
|
+
if (request.provider) query2.set("provider", request.provider);
|
|
4803
|
+
return { path: `/v1/desktop/usage?${query2}`, method: "GET" };
|
|
4697
4804
|
}
|
|
4698
4805
|
case "quota.notice": {
|
|
4699
|
-
const
|
|
4806
|
+
const query2 = new URLSearchParams({
|
|
4700
4807
|
refresh: String(request.refresh ?? false)
|
|
4701
4808
|
});
|
|
4702
|
-
if (request.provider)
|
|
4703
|
-
if (request.model)
|
|
4704
|
-
return { path: `/v1/desktop/quota-notice?${
|
|
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" };
|
|
4705
4812
|
}
|
|
4706
4813
|
case "analytics.get": {
|
|
4707
|
-
const
|
|
4708
|
-
if (request.sessionId)
|
|
4814
|
+
const query2 = new URLSearchParams({ days: String(request.days ?? 30) });
|
|
4815
|
+
if (request.sessionId) query2.set("session_id", request.sessionId);
|
|
4709
4816
|
if (request.sinceMs !== void 0)
|
|
4710
|
-
|
|
4817
|
+
query2.set("since_ms", String(request.sinceMs));
|
|
4711
4818
|
if (request.untilMs !== void 0)
|
|
4712
|
-
|
|
4713
|
-
return { path: `/v1/desktop/analytics?${
|
|
4819
|
+
query2.set("until_ms", String(request.untilMs));
|
|
4820
|
+
return { path: `/v1/desktop/analytics?${query2}`, method: "GET" };
|
|
4714
4821
|
}
|
|
4715
4822
|
/*
|
|
4716
4823
|
* `/analytics/models`, NOT `/analytics?models=1`.
|
|
@@ -4723,31 +4830,31 @@ function desktopEndpoint(request) {
|
|
|
4723
4830
|
* the server resolves one window from either.
|
|
4724
4831
|
*/
|
|
4725
4832
|
case "analytics.models": {
|
|
4726
|
-
const
|
|
4727
|
-
if (request.sessionId)
|
|
4833
|
+
const query2 = new URLSearchParams({ days: String(request.days ?? 30) });
|
|
4834
|
+
if (request.sessionId) query2.set("session_id", request.sessionId);
|
|
4728
4835
|
if (request.sinceMs !== void 0)
|
|
4729
|
-
|
|
4836
|
+
query2.set("since_ms", String(request.sinceMs));
|
|
4730
4837
|
if (request.untilMs !== void 0)
|
|
4731
|
-
|
|
4732
|
-
return { path: `/v1/desktop/analytics/models?${
|
|
4838
|
+
query2.set("until_ms", String(request.untilMs));
|
|
4839
|
+
return { path: `/v1/desktop/analytics/models?${query2}`, method: "GET" };
|
|
4733
4840
|
}
|
|
4734
4841
|
case "info.get":
|
|
4735
4842
|
return { path: "/v1/desktop/info", method: "GET" };
|
|
4736
4843
|
case "sessions.report": {
|
|
4737
|
-
const
|
|
4844
|
+
const query2 = new URLSearchParams({
|
|
4738
4845
|
recent_limit: String(request.recentLimit ?? 12)
|
|
4739
4846
|
});
|
|
4740
4847
|
return {
|
|
4741
|
-
path: `/v1/desktop/sessions/${request.sessionId}/report?${
|
|
4848
|
+
path: `/v1/desktop/sessions/${request.sessionId}/report?${query2}`,
|
|
4742
4849
|
method: "GET"
|
|
4743
4850
|
};
|
|
4744
4851
|
}
|
|
4745
4852
|
case "skills.list": {
|
|
4746
|
-
const
|
|
4747
|
-
if (request.sessionId)
|
|
4748
|
-
if (request.cwd)
|
|
4749
|
-
if (request.name)
|
|
4750
|
-
const encoded =
|
|
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();
|
|
4751
4858
|
return {
|
|
4752
4859
|
path: `/v1/desktop/skills${encoded ? `?${encoded}` : ""}`,
|
|
4753
4860
|
method: "GET"
|
|
@@ -4852,10 +4959,10 @@ function desktopEndpoint(request) {
|
|
|
4852
4959
|
body: request.control
|
|
4853
4960
|
};
|
|
4854
4961
|
case "mcp.catalog": {
|
|
4855
|
-
const
|
|
4856
|
-
if (request.cwd)
|
|
4857
|
-
if (request.sessionId)
|
|
4858
|
-
const suffix =
|
|
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();
|
|
4859
4966
|
return {
|
|
4860
4967
|
path: suffix ? `/v1/desktop/mcp?${suffix}` : "/v1/desktop/mcp",
|
|
4861
4968
|
method: "GET"
|
|
@@ -5003,14 +5110,14 @@ function desktopEndpoint(request) {
|
|
|
5003
5110
|
}
|
|
5004
5111
|
};
|
|
5005
5112
|
case "team_bridge.conversations.list": {
|
|
5006
|
-
const
|
|
5007
|
-
if (request.scope === "account")
|
|
5008
|
-
if (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);
|
|
5009
5116
|
if (request.limit !== void 0)
|
|
5010
|
-
|
|
5011
|
-
if (request.cursor)
|
|
5012
|
-
if (request.before)
|
|
5013
|
-
const suffix =
|
|
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()}` : "";
|
|
5014
5121
|
return {
|
|
5015
5122
|
path: `/v1/desktop/team-bridge/conversations${suffix}`,
|
|
5016
5123
|
method: "GET"
|
|
@@ -5026,6 +5133,7 @@ function desktopEndpoint(request) {
|
|
|
5026
5133
|
path: "/v1/desktop/team-bridge/conversations",
|
|
5027
5134
|
method: "POST",
|
|
5028
5135
|
body: {
|
|
5136
|
+
...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
|
|
5029
5137
|
...request.tenant_id ? { tenant_id: request.tenant_id } : {},
|
|
5030
5138
|
kind: request.kind,
|
|
5031
5139
|
...request.name ? { name: request.name } : {},
|
|
@@ -5037,14 +5145,25 @@ function desktopEndpoint(request) {
|
|
|
5037
5145
|
};
|
|
5038
5146
|
case "team_bridge.conversations.lifecycle":
|
|
5039
5147
|
return {
|
|
5040
|
-
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/${request.action}`,
|
|
5041
|
-
method: "POST"
|
|
5148
|
+
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/${request.action}${request.action === "join" ? "" : conversationOwnerQuery(request)}`,
|
|
5149
|
+
method: "POST",
|
|
5150
|
+
...request.action === "join" && (request.tenant_id || request.expected_account_id) ? {
|
|
5151
|
+
body: {
|
|
5152
|
+
...request.tenant_id ? { tenant_id: request.tenant_id } : {},
|
|
5153
|
+
...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {}
|
|
5154
|
+
}
|
|
5155
|
+
} : {}
|
|
5042
5156
|
};
|
|
5043
5157
|
case "team_bridge.conversations.join":
|
|
5044
5158
|
return {
|
|
5045
5159
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/join`,
|
|
5046
5160
|
method: "POST",
|
|
5047
|
-
...request.tenant_id
|
|
5161
|
+
...request.tenant_id || request.expected_account_id ? {
|
|
5162
|
+
body: {
|
|
5163
|
+
...request.tenant_id ? { tenant_id: request.tenant_id } : {},
|
|
5164
|
+
...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {}
|
|
5165
|
+
}
|
|
5166
|
+
} : {}
|
|
5048
5167
|
};
|
|
5049
5168
|
case "team_bridge.conversations.notify":
|
|
5050
5169
|
return {
|
|
@@ -5053,14 +5172,17 @@ function desktopEndpoint(request) {
|
|
|
5053
5172
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/read`,
|
|
5054
5173
|
method: "POST",
|
|
5055
5174
|
body: {
|
|
5175
|
+
...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
|
|
5056
5176
|
...request.tenant_id ? { tenant_id: request.tenant_id } : {},
|
|
5057
5177
|
notify: request.notify
|
|
5058
5178
|
}
|
|
5059
5179
|
};
|
|
5060
5180
|
case "team_bridge.conversations.members.add": {
|
|
5061
|
-
const
|
|
5062
|
-
if (request.tenant_id)
|
|
5063
|
-
|
|
5181
|
+
const query2 = new URLSearchParams();
|
|
5182
|
+
if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
|
|
5183
|
+
if (request.expected_account_id)
|
|
5184
|
+
query2.set("expected_account_id", request.expected_account_id);
|
|
5185
|
+
const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
|
|
5064
5186
|
return {
|
|
5065
5187
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members${suffix}`,
|
|
5066
5188
|
method: "POST",
|
|
@@ -5069,7 +5191,7 @@ function desktopEndpoint(request) {
|
|
|
5069
5191
|
}
|
|
5070
5192
|
case "team_bridge.conversations.members.remove":
|
|
5071
5193
|
return {
|
|
5072
|
-
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members/${encodeURIComponent(request.account_id)}`,
|
|
5194
|
+
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members/${encodeURIComponent(request.account_id)}${conversationOwnerQuery(request)}`,
|
|
5073
5195
|
method: "DELETE"
|
|
5074
5196
|
};
|
|
5075
5197
|
case "team_bridge.conversations.consent":
|
|
@@ -5077,20 +5199,21 @@ function desktopEndpoint(request) {
|
|
|
5077
5199
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/members/${encodeURIComponent(request.account_id)}/consent`,
|
|
5078
5200
|
method: "POST",
|
|
5079
5201
|
body: {
|
|
5202
|
+
...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
|
|
5080
5203
|
...request.tenant_id ? { tenant_id: request.tenant_id } : {},
|
|
5081
5204
|
decision: request.decision,
|
|
5082
5205
|
consent_version: request.consent_version
|
|
5083
5206
|
}
|
|
5084
5207
|
};
|
|
5085
5208
|
case "team_bridge.messages.list": {
|
|
5086
|
-
const
|
|
5087
|
-
if (request.tenant_id)
|
|
5209
|
+
const query2 = new URLSearchParams();
|
|
5210
|
+
if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
|
|
5088
5211
|
if (request.limit !== void 0)
|
|
5089
|
-
|
|
5212
|
+
query2.set("limit", String(request.limit));
|
|
5090
5213
|
if (request.before_seq !== void 0)
|
|
5091
|
-
|
|
5092
|
-
if (request.endpoint_id)
|
|
5093
|
-
const suffix =
|
|
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()}` : "";
|
|
5094
5217
|
return {
|
|
5095
5218
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/messages${suffix}`,
|
|
5096
5219
|
method: "GET"
|
|
@@ -5112,6 +5235,7 @@ function desktopEndpoint(request) {
|
|
|
5112
5235
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/messages`,
|
|
5113
5236
|
method: "POST",
|
|
5114
5237
|
body: {
|
|
5238
|
+
...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
|
|
5115
5239
|
...request.tenant_id ? { tenant_id: request.tenant_id } : {},
|
|
5116
5240
|
client_ref: request.client_ref,
|
|
5117
5241
|
body: request.body,
|
|
@@ -5120,13 +5244,13 @@ function desktopEndpoint(request) {
|
|
|
5120
5244
|
}
|
|
5121
5245
|
};
|
|
5122
5246
|
case "team_bridge.messages.replies": {
|
|
5123
|
-
const
|
|
5124
|
-
if (request.tenant_id)
|
|
5247
|
+
const query2 = new URLSearchParams();
|
|
5248
|
+
if (request.tenant_id) query2.set("tenant_id", request.tenant_id);
|
|
5125
5249
|
if (request.limit !== void 0)
|
|
5126
|
-
|
|
5250
|
+
query2.set("limit", String(request.limit));
|
|
5127
5251
|
if (request.after_seq !== void 0)
|
|
5128
|
-
|
|
5129
|
-
const suffix =
|
|
5252
|
+
query2.set("after_seq", String(request.after_seq));
|
|
5253
|
+
const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
|
|
5130
5254
|
return {
|
|
5131
5255
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/messages/${encodeURIComponent(request.message_id)}/replies${suffix}`,
|
|
5132
5256
|
method: "GET"
|
|
@@ -5137,16 +5261,17 @@ function desktopEndpoint(request) {
|
|
|
5137
5261
|
path: `/v1/desktop/team-bridge/conversations/${encodeURIComponent(request.conversation_id)}/read`,
|
|
5138
5262
|
method: "POST",
|
|
5139
5263
|
body: {
|
|
5264
|
+
...request.expected_account_id ? { expected_account_id: request.expected_account_id } : {},
|
|
5140
5265
|
...request.tenant_id ? { tenant_id: request.tenant_id } : {},
|
|
5141
5266
|
...request.seq === void 0 ? {} : { seq: request.seq },
|
|
5142
5267
|
...request.muted === void 0 ? {} : { muted: request.muted }
|
|
5143
5268
|
}
|
|
5144
5269
|
};
|
|
5145
5270
|
case "team_bridge.unread": {
|
|
5146
|
-
const
|
|
5147
|
-
if (request.scope === "account")
|
|
5148
|
-
else if (request.tenant_id)
|
|
5149
|
-
const suffix =
|
|
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()}` : "";
|
|
5150
5275
|
return {
|
|
5151
5276
|
path: `/v1/desktop/team-bridge/unread${suffix}`,
|
|
5152
5277
|
method: "GET"
|
|
@@ -5174,9 +5299,9 @@ function desktopEndpoint(request) {
|
|
|
5174
5299
|
* op would emit for a missing value.
|
|
5175
5300
|
*/
|
|
5176
5301
|
case "team_bridge.status": {
|
|
5177
|
-
const
|
|
5178
|
-
if (request.boundary)
|
|
5179
|
-
const suffix =
|
|
5302
|
+
const query2 = new URLSearchParams();
|
|
5303
|
+
if (request.boundary) query2.set("boundary", request.boundary);
|
|
5304
|
+
const suffix = query2.size > 0 ? `?${query2.toString()}` : "";
|
|
5180
5305
|
return {
|
|
5181
5306
|
path: `/v1/desktop/team-bridge/status${suffix}`,
|
|
5182
5307
|
method: "GET"
|
|
@@ -5235,29 +5360,29 @@ function desktopEndpoint(request) {
|
|
|
5235
5360
|
* `op` because that key already names the desktop operation.
|
|
5236
5361
|
*/
|
|
5237
5362
|
case "library.list": {
|
|
5238
|
-
const
|
|
5239
|
-
if (request.scope)
|
|
5240
|
-
if (request.q)
|
|
5241
|
-
if (request.category)
|
|
5242
|
-
if (request.kind)
|
|
5243
|
-
if (request.origin_group)
|
|
5244
|
-
if (request.origin)
|
|
5245
|
-
if (request.tag)
|
|
5246
|
-
if (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);
|
|
5247
5372
|
if (request.highlighted !== void 0)
|
|
5248
|
-
|
|
5373
|
+
query2.set("highlighted", request.highlighted ? "1" : "0");
|
|
5249
5374
|
if (request.organized !== void 0)
|
|
5250
|
-
|
|
5375
|
+
query2.set("organized", request.organized ? "1" : "0");
|
|
5251
5376
|
if (request.favorite !== void 0)
|
|
5252
|
-
|
|
5253
|
-
if (request.session)
|
|
5254
|
-
if (request.session_id)
|
|
5255
|
-
if (request.sort)
|
|
5256
|
-
if (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);
|
|
5257
5382
|
if (request.limit !== void 0)
|
|
5258
|
-
|
|
5259
|
-
if (request.cursor)
|
|
5260
|
-
const suffix =
|
|
5383
|
+
query2.set("limit", String(request.limit));
|
|
5384
|
+
if (request.cursor) query2.set("cursor", request.cursor);
|
|
5385
|
+
const suffix = query2.toString();
|
|
5261
5386
|
return {
|
|
5262
5387
|
path: `/v1/desktop/library/assets${suffix ? `?${suffix}` : ""}`,
|
|
5263
5388
|
method: "GET"
|
|
@@ -5418,12 +5543,12 @@ function desktopEndpoint(request) {
|
|
|
5418
5543
|
method: "POST"
|
|
5419
5544
|
};
|
|
5420
5545
|
case "projects.search": {
|
|
5421
|
-
const
|
|
5546
|
+
const query2 = new URLSearchParams({
|
|
5422
5547
|
q: request.q,
|
|
5423
5548
|
limit: String(request.limit ?? PROJECTS_SEARCH_DEFAULT_LIMIT)
|
|
5424
5549
|
});
|
|
5425
5550
|
return {
|
|
5426
|
-
path: `/v1/desktop/projects/search?${
|
|
5551
|
+
path: `/v1/desktop/projects/search?${query2}`,
|
|
5427
5552
|
method: "GET"
|
|
5428
5553
|
};
|
|
5429
5554
|
}
|
|
@@ -5823,6 +5948,187 @@ function windowGlassArgument(state2, scheme) {
|
|
|
5823
5948
|
const { settings, capability } = state2;
|
|
5824
5949
|
return `${WINDOW_GLASS_ARG}=${capability.mechanism}:${settings.coverage}:${settings.intensity}:${settings.material}:${scheme}`;
|
|
5825
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
|
+
}
|
|
5826
6132
|
const SERVE_RUN_DIRNAME = "run/serve";
|
|
5827
6133
|
const REAPED_DIRNAME = "reaped";
|
|
5828
6134
|
const REAPED_MAX_FILES = 200;
|
|
@@ -9422,25 +9728,25 @@ class DesktopStreamRelay {
|
|
|
9422
9728
|
const streamId = node_crypto.randomBytes(16).toString("hex");
|
|
9423
9729
|
const controller = new AbortController();
|
|
9424
9730
|
this.streams.set(streamId, controller);
|
|
9425
|
-
const
|
|
9426
|
-
if (args.epoch)
|
|
9731
|
+
const query2 = new URLSearchParams();
|
|
9732
|
+
if (args.epoch) query2.set("epoch", args.epoch);
|
|
9427
9733
|
if (args.afterSeq !== void 0)
|
|
9428
|
-
|
|
9429
|
-
|
|
9430
|
-
if (args.openFrame === true)
|
|
9734
|
+
query2.set("after_seq", String(args.afterSeq));
|
|
9735
|
+
query2.set("frontend_replace", "1");
|
|
9736
|
+
if (args.openFrame === true) query2.set("open_frame", "1");
|
|
9431
9737
|
if (args.journalOrder === true) {
|
|
9432
|
-
|
|
9738
|
+
query2.set("journal_order", "1");
|
|
9433
9739
|
if (args.peerJournalSource === true)
|
|
9434
|
-
|
|
9740
|
+
query2.set("peer_journal_source", "1");
|
|
9435
9741
|
}
|
|
9436
|
-
|
|
9742
|
+
query2.set("supplements", "1");
|
|
9437
9743
|
if (args.journalOrder === true)
|
|
9438
9744
|
appendJournalOrderIds(
|
|
9439
|
-
|
|
9745
|
+
query2,
|
|
9440
9746
|
`/v1/desktop/sessions/${args.sessionId}/events`,
|
|
9441
9747
|
args.orderIds ?? []
|
|
9442
9748
|
);
|
|
9443
|
-
const suffix =
|
|
9749
|
+
const suffix = query2.size > 0 ? `?${query2}` : "";
|
|
9444
9750
|
const url = new URL(
|
|
9445
9751
|
`/v1/desktop/sessions/${args.sessionId}/events${suffix}`,
|
|
9446
9752
|
this.backendUrl
|
|
@@ -14694,6 +15000,20 @@ class BackendServiceManager {
|
|
|
14694
15000
|
getBackendUrl() {
|
|
14695
15001
|
return this.backendUrl;
|
|
14696
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
|
+
}
|
|
14697
15017
|
/**
|
|
14698
15018
|
* Check if the backend service is using an external backend
|
|
14699
15019
|
* @returns True if using an external backend, false if we started our own
|
|
@@ -14839,12 +15159,12 @@ const REASON_LIMIT = 240;
|
|
|
14839
15159
|
function installFailureReason(stdout, stderr) {
|
|
14840
15160
|
const lines = `${stderr}
|
|
14841
15161
|
${stdout}`.split(/\r?\n/);
|
|
14842
|
-
const pick = (
|
|
15162
|
+
const pick = (accept2) => {
|
|
14843
15163
|
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
14844
15164
|
const line = lines[index].trim();
|
|
14845
15165
|
if (line.length === 0) continue;
|
|
14846
15166
|
if (NOISE.some((pattern) => pattern.test(line))) continue;
|
|
14847
|
-
if (!
|
|
15167
|
+
if (!accept2(line)) continue;
|
|
14848
15168
|
return line.length > REASON_LIMIT ? `${line.slice(0, REASON_LIMIT - 1).trimEnd()}…` : line;
|
|
14849
15169
|
}
|
|
14850
15170
|
return null;
|
|
@@ -16725,6 +17045,10 @@ const METHODS$1 = [
|
|
|
16725
17045
|
"styles",
|
|
16726
17046
|
"hit_test",
|
|
16727
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",
|
|
16728
17052
|
"request_access",
|
|
16729
17053
|
"await_access",
|
|
16730
17054
|
"cancel_access",
|
|
@@ -16789,6 +17113,7 @@ const HOST_CAPABILITIES = [
|
|
|
16789
17113
|
"styles",
|
|
16790
17114
|
"hit_test",
|
|
16791
17115
|
"ancestors",
|
|
17116
|
+
"query",
|
|
16792
17117
|
"download",
|
|
16793
17118
|
"upload"
|
|
16794
17119
|
];
|
|
@@ -28089,7 +28414,7 @@ function nativeCapacityProbe(trustedPython) {
|
|
|
28089
28414
|
let ptyMax = null;
|
|
28090
28415
|
let stopped = false;
|
|
28091
28416
|
const children = /* @__PURE__ */ new Set();
|
|
28092
|
-
function readNumber(executable, args,
|
|
28417
|
+
function readNumber(executable, args, accept2) {
|
|
28093
28418
|
const child = node_child_process.execFile(
|
|
28094
28419
|
executable,
|
|
28095
28420
|
args,
|
|
@@ -28104,7 +28429,7 @@ function nativeCapacityProbe(trustedPython) {
|
|
|
28104
28429
|
children.delete(child);
|
|
28105
28430
|
if (stopped || error) return;
|
|
28106
28431
|
const value = Number(stdout.trim());
|
|
28107
|
-
if (Number.isSafeInteger(value) && value > 0)
|
|
28432
|
+
if (Number.isSafeInteger(value) && value > 0) accept2(value);
|
|
28108
28433
|
}
|
|
28109
28434
|
);
|
|
28110
28435
|
children.add(child);
|
|
@@ -35690,6 +36015,34 @@ const enUiChatAnalytics = {
|
|
|
35690
36015
|
"ui.chat.analytics.toolbar.refreshing": "Refreshing",
|
|
35691
36016
|
"ui.chat.analytics.toolbar.this_session_only": "This session only"
|
|
35692
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
|
+
};
|
|
35693
36046
|
const enUiChatCanonical = {
|
|
35694
36047
|
"ui.chat.canonical.sound.batch_attachment_unavailable": "Audio attachment unavailable.",
|
|
35695
36048
|
"ui.chat.canonical.sound.player_failed": "This sound could not be played",
|
|
@@ -39470,6 +39823,34 @@ const esUiCanvas = {
|
|
|
39470
39823
|
"ui.canvas.files.prepareError": "No se pudo preparar una copia local para esta acción",
|
|
39471
39824
|
"ui.canvas.files.pathCopyNote": "Las acciones de abrir, carpeta y ruta crean una copia local en el scratchpad de esta conversación."
|
|
39472
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
|
+
};
|
|
39473
39854
|
const esUiChatComposer = {
|
|
39474
39855
|
"ui.chat.composer.clear_message": "Borrar mensaje",
|
|
39475
39856
|
"ui.chat.composer.message": "Mensaje",
|
|
@@ -43111,6 +43492,34 @@ const frUiCanvas = {
|
|
|
43111
43492
|
"ui.canvas.files.prepareError": "Impossible de préparer une copie locale pour cette action",
|
|
43112
43493
|
"ui.canvas.files.pathCopyNote": "Les actions Ouvrir, Dossier et Chemin créent une copie locale dans le dossier de travail de cette conversation."
|
|
43113
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
|
+
};
|
|
43114
43523
|
const frUiChatComposer = {
|
|
43115
43524
|
"ui.chat.composer.clear_message": "Effacer le message",
|
|
43116
43525
|
"ui.chat.composer.message": "Message",
|
|
@@ -46752,6 +47161,34 @@ const hiUiCanvas = {
|
|
|
46752
47161
|
"ui.canvas.files.prepareError": "इस कार्रवाई के लिए स्थानीय कॉपी तैयार नहीं हो सकी",
|
|
46753
47162
|
"ui.canvas.files.pathCopyNote": "खोलने, फ़ोल्डर और पाथ की कार्रवाइयाँ इस बातचीत के स्क्रैचपैड में एक स्थानीय कॉपी बनाती हैं।"
|
|
46754
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
|
+
};
|
|
46755
47192
|
const hiUiChatComposer = {
|
|
46756
47193
|
"ui.chat.composer.clear_message": "संदेश मिटाएँ",
|
|
46757
47194
|
"ui.chat.composer.message": "संदेश",
|
|
@@ -50351,6 +50788,34 @@ const ruUiCanvas = {
|
|
|
50351
50788
|
"ui.canvas.files.videos": "Видео",
|
|
50352
50789
|
"ui.canvas.files.working": "Рабочие файлы"
|
|
50353
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
|
+
};
|
|
50354
50819
|
const ruUiChatComposer = {
|
|
50355
50820
|
"ui.chat.composer.ask_aside": "Спросить отдельно",
|
|
50356
50821
|
"ui.chat.composer.attach_file": "Прикрепить файл",
|
|
@@ -53970,6 +54435,34 @@ const urUiCanvas = {
|
|
|
53970
54435
|
"ui.canvas.files.prepareError": "اس عمل کے لیے مقامی نقل تیار نہیں ہو سکی",
|
|
53971
54436
|
"ui.canvas.files.pathCopyNote": "کھولنے، فولڈر اور راستے کے اعمال اس گفتگو کے اسکریچ پیڈ میں مقامی نقل بناتے ہیں۔"
|
|
53972
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
|
+
};
|
|
53973
54466
|
const urUiChatComposer = {
|
|
53974
54467
|
"ui.chat.composer.clear_message": "پیغام صاف کریں",
|
|
53975
54468
|
"ui.chat.composer.message": "پیغام",
|
|
@@ -57589,6 +58082,34 @@ const viUiCanvas = {
|
|
|
57589
58082
|
"ui.canvas.files.prepareError": "Không chuẩn bị được bản sao cục bộ cho thao tác này",
|
|
57590
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."
|
|
57591
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
|
+
};
|
|
57592
58113
|
const viUiChatComposer = {
|
|
57593
58114
|
"ui.chat.composer.clear_message": "Xóa tin nhắn",
|
|
57594
58115
|
"ui.chat.composer.message": "Tin nhắn",
|
|
@@ -61017,6 +61538,34 @@ const zhCNUiCanvas = {
|
|
|
61017
61538
|
"ui.canvas.files.prepareError": "无法为此操作准备本地副本",
|
|
61018
61539
|
"ui.canvas.files.pathCopyNote": "打开文件、打开文件夹及路径相关操作会在此对话的暂存区中创建本地副本。"
|
|
61019
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
|
+
};
|
|
61020
61569
|
const zhCNUiChatComposer = {
|
|
61021
61570
|
"ui.chat.composer.clear_message": "清空消息",
|
|
61022
61571
|
"ui.chat.composer.message": "消息",
|
|
@@ -64047,6 +64596,8 @@ const bundledEnglish = {
|
|
|
64047
64596
|
...enUiBrowser,
|
|
64048
64597
|
...enUiCanvas,
|
|
64049
64598
|
...enUiChatAnalytics,
|
|
64599
|
+
...enUiChatAsks,
|
|
64600
|
+
...enUiChatAttachments,
|
|
64050
64601
|
...enUiChatCanonical,
|
|
64051
64602
|
...enUiChatCommentaryActions,
|
|
64052
64603
|
...enUiChatComposer,
|
|
@@ -64121,6 +64672,8 @@ const bundledCatalogues = {
|
|
|
64121
64672
|
...esUiBrowserChrome,
|
|
64122
64673
|
...esUiBrowser,
|
|
64123
64674
|
...esUiCanvas,
|
|
64675
|
+
...esUiChatAsks,
|
|
64676
|
+
...esUiChatAttachments,
|
|
64124
64677
|
...esUiChatComposer,
|
|
64125
64678
|
...esUiChatComposerMedia,
|
|
64126
64679
|
...esUiChatDialogs,
|
|
@@ -64185,6 +64738,8 @@ const bundledCatalogues = {
|
|
|
64185
64738
|
...frUiBrowserChrome,
|
|
64186
64739
|
...frUiBrowser,
|
|
64187
64740
|
...frUiCanvas,
|
|
64741
|
+
...frUiChatAsks,
|
|
64742
|
+
...frUiChatAttachments,
|
|
64188
64743
|
...frUiChatComposer,
|
|
64189
64744
|
...frUiChatComposerMedia,
|
|
64190
64745
|
...frUiChatDialogs,
|
|
@@ -64249,6 +64804,8 @@ const bundledCatalogues = {
|
|
|
64249
64804
|
...hiUiBrowserChrome,
|
|
64250
64805
|
...hiUiBrowser,
|
|
64251
64806
|
...hiUiCanvas,
|
|
64807
|
+
...hiUiChatAsks,
|
|
64808
|
+
...hiUiChatAttachments,
|
|
64252
64809
|
...hiUiChatComposer,
|
|
64253
64810
|
...hiUiChatComposerMedia,
|
|
64254
64811
|
...hiUiChatDialogs,
|
|
@@ -64310,6 +64867,8 @@ const bundledCatalogues = {
|
|
|
64310
64867
|
...ruUiBrowserChrome,
|
|
64311
64868
|
...ruUiBrowser,
|
|
64312
64869
|
...ruUiCanvas,
|
|
64870
|
+
...ruUiChatAsks,
|
|
64871
|
+
...ruUiChatAttachments,
|
|
64313
64872
|
...ruUiChatComposer,
|
|
64314
64873
|
...ruUiChatComposerMedia,
|
|
64315
64874
|
...ruUiChatDialogs,
|
|
@@ -64372,6 +64931,8 @@ const bundledCatalogues = {
|
|
|
64372
64931
|
...urUiBrowserChrome,
|
|
64373
64932
|
...urUiBrowser,
|
|
64374
64933
|
...urUiCanvas,
|
|
64934
|
+
...urUiChatAsks,
|
|
64935
|
+
...urUiChatAttachments,
|
|
64375
64936
|
...urUiChatComposer,
|
|
64376
64937
|
...urUiChatComposerMedia,
|
|
64377
64938
|
...urUiChatDialogs,
|
|
@@ -64434,6 +64995,8 @@ const bundledCatalogues = {
|
|
|
64434
64995
|
...viUiBrowserChrome,
|
|
64435
64996
|
...viUiBrowser,
|
|
64436
64997
|
...viUiCanvas,
|
|
64998
|
+
...viUiChatAsks,
|
|
64999
|
+
...viUiChatAttachments,
|
|
64437
65000
|
...viUiChatComposer,
|
|
64438
65001
|
...viUiChatComposerMedia,
|
|
64439
65002
|
...viUiChatDialogs,
|
|
@@ -64495,6 +65058,8 @@ const bundledCatalogues = {
|
|
|
64495
65058
|
...zhCNUiBrowserChrome,
|
|
64496
65059
|
...zhCNUiBrowser,
|
|
64497
65060
|
...zhCNUiCanvas,
|
|
65061
|
+
...zhCNUiChatAsks,
|
|
65062
|
+
...zhCNUiChatAttachments,
|
|
64498
65063
|
...zhCNUiChatComposer,
|
|
64499
65064
|
...zhCNUiChatComposerMedia,
|
|
64500
65065
|
...zhCNUiChatDialogs,
|
|
@@ -64806,6 +65371,160 @@ function pageOf(view) {
|
|
|
64806
65371
|
title: view.webContents.isDestroyed() ? "" : view.webContents.getTitle()
|
|
64807
65372
|
};
|
|
64808
65373
|
}
|
|
65374
|
+
const LABELLABLE = /* @__PURE__ */ new Set([
|
|
65375
|
+
"checkbox",
|
|
65376
|
+
"radio",
|
|
65377
|
+
"switch",
|
|
65378
|
+
"textbox",
|
|
65379
|
+
"searchbox",
|
|
65380
|
+
"combobox",
|
|
65381
|
+
"listbox",
|
|
65382
|
+
"spinbutton",
|
|
65383
|
+
"slider",
|
|
65384
|
+
"button"
|
|
65385
|
+
]);
|
|
65386
|
+
const CLICKABLE = /* @__PURE__ */ new Set([
|
|
65387
|
+
"button",
|
|
65388
|
+
"link",
|
|
65389
|
+
"menuitem",
|
|
65390
|
+
"menuitemcheckbox",
|
|
65391
|
+
"menuitemradio",
|
|
65392
|
+
"tab",
|
|
65393
|
+
"option",
|
|
65394
|
+
"treeitem",
|
|
65395
|
+
"DisclosureTriangle",
|
|
65396
|
+
"checkbox",
|
|
65397
|
+
"radio",
|
|
65398
|
+
"switch"
|
|
65399
|
+
]);
|
|
65400
|
+
function normalise(value) {
|
|
65401
|
+
return String(value ?? "").replace(/\s+/g, " ").trim();
|
|
65402
|
+
}
|
|
65403
|
+
function readValue(raw) {
|
|
65404
|
+
const text = raw.trim();
|
|
65405
|
+
if (!text) return null;
|
|
65406
|
+
const quote = text[0];
|
|
65407
|
+
if (quote === '"' || quote === "'") {
|
|
65408
|
+
let value = "";
|
|
65409
|
+
for (let index = 1; index < text.length; index += 1) {
|
|
65410
|
+
const char = text[index] ?? "";
|
|
65411
|
+
if (char === "\\" && index + 1 < text.length) {
|
|
65412
|
+
value += text[index + 1] ?? "";
|
|
65413
|
+
index += 1;
|
|
65414
|
+
continue;
|
|
65415
|
+
}
|
|
65416
|
+
if (char === quote) {
|
|
65417
|
+
return index === text.length - 1 ? value : null;
|
|
65418
|
+
}
|
|
65419
|
+
value += char;
|
|
65420
|
+
}
|
|
65421
|
+
return null;
|
|
65422
|
+
}
|
|
65423
|
+
if (/[\[\]]/.test(text) || text.startsWith("*")) return null;
|
|
65424
|
+
return text;
|
|
65425
|
+
}
|
|
65426
|
+
function parseLocator(value) {
|
|
65427
|
+
const text = value.trim();
|
|
65428
|
+
const match = /^(role|label|text)(\*?)=([\s\S]+)$/i.exec(text);
|
|
65429
|
+
if (!match) return null;
|
|
65430
|
+
const kind = (match[1] ?? "").toLowerCase();
|
|
65431
|
+
const prefixSubstring = match[2] === "*";
|
|
65432
|
+
const rest = (match[3] ?? "").trim();
|
|
65433
|
+
if (kind === "role") {
|
|
65434
|
+
const roleMatch = /^([A-Za-z][A-Za-z0-9_-]*)\s*(?:\[\s*name(\*?)=\s*([\s\S]+?)\s*\])?$/.exec(rest);
|
|
65435
|
+
if (!roleMatch) return null;
|
|
65436
|
+
const role = roleMatch[1] ?? "";
|
|
65437
|
+
const substring = roleMatch[2] === "*";
|
|
65438
|
+
const rawName = roleMatch[3];
|
|
65439
|
+
const name2 = rawName === void 0 ? "" : readValue(rawName);
|
|
65440
|
+
if (name2 === null) return null;
|
|
65441
|
+
return { kind: "role", role: role.toLowerCase(), name: name2, substring };
|
|
65442
|
+
}
|
|
65443
|
+
const name = readValue(rest);
|
|
65444
|
+
if (name === null) return null;
|
|
65445
|
+
return { kind: kind === "label" ? "label" : "text", name, substring: prefixSubstring };
|
|
65446
|
+
}
|
|
65447
|
+
function matches(haystack, needle, substring) {
|
|
65448
|
+
const left = normalise(haystack).toLowerCase();
|
|
65449
|
+
const right = normalise(needle).toLowerCase();
|
|
65450
|
+
if (!right) return false;
|
|
65451
|
+
return substring ? left.includes(right) : left === right;
|
|
65452
|
+
}
|
|
65453
|
+
const NEVER_TARGETED = /* @__PURE__ */ new Set(["StaticText", "InlineTextBox", "none", "generic"]);
|
|
65454
|
+
function candidateNodes(nodes) {
|
|
65455
|
+
return nodes.filter((node) => !node.ignored && node.backendDOMNodeId !== void 0);
|
|
65456
|
+
}
|
|
65457
|
+
function resolveLocator(nodes, locator) {
|
|
65458
|
+
const pool = candidateNodes(nodes);
|
|
65459
|
+
const hits = [];
|
|
65460
|
+
const consider = (role, name) => {
|
|
65461
|
+
if (locator.kind === "role") {
|
|
65462
|
+
if (role.toLowerCase() !== locator.role) return false;
|
|
65463
|
+
if (locator.name && !matches(name, locator.name, locator.substring)) return false;
|
|
65464
|
+
return true;
|
|
65465
|
+
}
|
|
65466
|
+
return matches(name, locator.name, locator.substring);
|
|
65467
|
+
};
|
|
65468
|
+
const collect = (accept2) => {
|
|
65469
|
+
for (const node of pool) {
|
|
65470
|
+
const role = String(node.role?.value ?? "");
|
|
65471
|
+
const name = normalise(node.name?.value);
|
|
65472
|
+
if (!accept2(role)) continue;
|
|
65473
|
+
if (!consider(role, name)) continue;
|
|
65474
|
+
hits.push({ backendNodeId: node.backendDOMNodeId, role, name, matched: 0 });
|
|
65475
|
+
}
|
|
65476
|
+
};
|
|
65477
|
+
if (locator.kind === "role") {
|
|
65478
|
+
collect(() => true);
|
|
65479
|
+
} else if (locator.kind === "label") {
|
|
65480
|
+
collect((role) => LABELLABLE.has(role));
|
|
65481
|
+
if (!hits.length) collect((role) => CLICKABLE.has(role));
|
|
65482
|
+
} else {
|
|
65483
|
+
collect((role) => CLICKABLE.has(role));
|
|
65484
|
+
if (!hits.length) collect(() => true);
|
|
65485
|
+
}
|
|
65486
|
+
const first = hits[0];
|
|
65487
|
+
if (!first) return null;
|
|
65488
|
+
return { ...first, matched: hits.length };
|
|
65489
|
+
}
|
|
65490
|
+
function locatorSuggestions(nodes, query2, limit = 5) {
|
|
65491
|
+
const wanted = normalise(query2).toLowerCase();
|
|
65492
|
+
const parsed = parseLocator(query2);
|
|
65493
|
+
const term = parsed ? parsed.name.toLowerCase() : wanted;
|
|
65494
|
+
const words = term.split(/[^a-z0-9]+/).filter((word) => word.length > 1);
|
|
65495
|
+
const wantedRole = parsed && parsed.kind === "role" ? parsed.role : "";
|
|
65496
|
+
const scored = [];
|
|
65497
|
+
for (const node of candidateNodes(nodes)) {
|
|
65498
|
+
const role = String(node.role?.value ?? "");
|
|
65499
|
+
const name = normalise(node.name?.value);
|
|
65500
|
+
if (!name) continue;
|
|
65501
|
+
if (NEVER_TARGETED.has(role)) continue;
|
|
65502
|
+
const lowerName = name.toLowerCase();
|
|
65503
|
+
let score = 0;
|
|
65504
|
+
if (term && lowerName === term) score += 100;
|
|
65505
|
+
else if (term && lowerName.includes(term)) score += 60;
|
|
65506
|
+
for (const word of words) if (lowerName.includes(word)) score += 8;
|
|
65507
|
+
if (wantedRole && role.toLowerCase() === wantedRole) score += 25;
|
|
65508
|
+
if (CLICKABLE.has(role)) score += 12;
|
|
65509
|
+
if (!score) continue;
|
|
65510
|
+
scored.push({ score, role, name });
|
|
65511
|
+
}
|
|
65512
|
+
scored.sort((left, right) => right.score - left.score || left.name.localeCompare(right.name));
|
|
65513
|
+
const seen = /* @__PURE__ */ new Set();
|
|
65514
|
+
const out = [];
|
|
65515
|
+
for (const entry of scored) {
|
|
65516
|
+
const key = `${entry.role}\0${entry.name}`;
|
|
65517
|
+
if (seen.has(key)) continue;
|
|
65518
|
+
seen.add(key);
|
|
65519
|
+
out.push({ role: entry.role, name: entry.name, locator: locatorFor(entry.role, entry.name) });
|
|
65520
|
+
if (out.length >= limit) break;
|
|
65521
|
+
}
|
|
65522
|
+
return out;
|
|
65523
|
+
}
|
|
65524
|
+
function locatorFor(role, name) {
|
|
65525
|
+
const quoted = name.includes('"') && !name.includes("'") ? `'${name.replace(/\\/g, "\\\\")}'` : JSON.stringify(name);
|
|
65526
|
+
return role && /^[A-Za-z][A-Za-z0-9_-]*$/.test(role) ? `role=${role}[name=${quoted}]` : `text=${quoted}`;
|
|
65527
|
+
}
|
|
64809
65528
|
const FRAME_HOP = ">>>";
|
|
64810
65529
|
const MAX_FRAME_DEPTH = 3;
|
|
64811
65530
|
const MAX_FRAMES_SEARCHED = 20;
|
|
@@ -65056,7 +65775,7 @@ async function resolveHops(ctx, contents, hops) {
|
|
|
65056
65775
|
return { scope, nodeId };
|
|
65057
65776
|
}
|
|
65058
65777
|
async function searchFrames(ctx, contents, selector) {
|
|
65059
|
-
const
|
|
65778
|
+
const matches2 = [];
|
|
65060
65779
|
const walk = await listFrames(ctx, contents);
|
|
65061
65780
|
for (const scope of walk.frames) {
|
|
65062
65781
|
const nodeId = await queryIn(ctx, contents, scope, selector).catch(
|
|
@@ -65065,9 +65784,9 @@ async function searchFrames(ctx, contents, selector) {
|
|
|
65065
65784
|
return 0;
|
|
65066
65785
|
}
|
|
65067
65786
|
);
|
|
65068
|
-
if (nodeId)
|
|
65787
|
+
if (nodeId) matches2.push({ scope, nodeId });
|
|
65069
65788
|
}
|
|
65070
|
-
return { matches, walk };
|
|
65789
|
+
return { matches: matches2, walk };
|
|
65071
65790
|
}
|
|
65072
65791
|
async function listFrames(ctx, contents) {
|
|
65073
65792
|
const walk = {
|
|
@@ -65202,24 +65921,46 @@ async function editableInFrame(ctx, contents, scope, target2) {
|
|
|
65202
65921
|
}
|
|
65203
65922
|
const LANDMARKS = /* @__PURE__ */ new Set(["banner", "main", "navigation", "complementary", "contentinfo", "form", "region"]);
|
|
65204
65923
|
const INTERACTIVE = /* @__PURE__ */ new Set(["button", "link", "textbox", "checkbox", "radio", "combobox", "menuitem", "tab", "switch", "slider", "spinbutton"]);
|
|
65205
|
-
function
|
|
65924
|
+
function stateSuffix(node) {
|
|
65925
|
+
const truthy = (value) => value === true || value === "true";
|
|
65926
|
+
const falsy = (value) => value === false || value === "false";
|
|
65927
|
+
const property = (name) => node.properties?.find((entry) => entry.name === name)?.value.value;
|
|
65928
|
+
const markers = [];
|
|
65929
|
+
if (falsy(property("expanded"))) markers.push("collapsed");
|
|
65930
|
+
const checked = property("checked");
|
|
65931
|
+
if (truthy(checked)) markers.push("checked");
|
|
65932
|
+
else if (checked === "mixed") markers.push("mixed");
|
|
65933
|
+
if (truthy(property("disabled"))) markers.push("disabled");
|
|
65934
|
+
return markers.length ? ` [${markers.join("] [")}]` : "";
|
|
65935
|
+
}
|
|
65936
|
+
function compactAX(nodes, epoch, options = {}) {
|
|
65206
65937
|
const byId = new Map(nodes.map((node) => [node.nodeId, node]));
|
|
65207
65938
|
const refs = {};
|
|
65208
65939
|
const lines = [];
|
|
65209
65940
|
let sequence = 0;
|
|
65941
|
+
const scopeId = options.rootBackendNodeId;
|
|
65942
|
+
let scopeAt = null;
|
|
65943
|
+
let framesInScope = 0;
|
|
65210
65944
|
const visited = /* @__PURE__ */ new Set();
|
|
65211
65945
|
function visit2(node, depth) {
|
|
65212
65946
|
if (visited.has(node.nodeId)) return;
|
|
65213
65947
|
visited.add(node.nodeId);
|
|
65948
|
+
const savedScope = scopeAt;
|
|
65949
|
+
if (scopeAt === null && scopeId !== void 0 && node.backendDOMNodeId === scopeId) {
|
|
65950
|
+
scopeAt = depth;
|
|
65951
|
+
}
|
|
65952
|
+
const inside2 = scopeId === void 0 || scopeAt !== null && depth >= scopeAt;
|
|
65214
65953
|
if (node.ignored) {
|
|
65215
65954
|
for (const child of node.childIds ?? []) {
|
|
65216
65955
|
const found = byId.get(child);
|
|
65217
65956
|
if (found) visit2(found, depth);
|
|
65218
65957
|
}
|
|
65958
|
+
scopeAt = savedScope;
|
|
65219
65959
|
return;
|
|
65220
65960
|
}
|
|
65221
65961
|
const role = String(node.role?.value ?? "");
|
|
65222
65962
|
const name = String(node.name?.value ?? "").trim();
|
|
65963
|
+
if (inside2 && role === "Iframe") framesInScope += 1;
|
|
65223
65964
|
const focusable = node.properties?.some((property) => property.name === "focusable" && property.value.value === true);
|
|
65224
65965
|
const interesting = INTERACTIVE.has(role) || LANDMARKS.has(role) || focusable || Boolean(name && role !== "StaticText");
|
|
65225
65966
|
if (interesting) {
|
|
@@ -65228,16 +65969,54 @@ function compactAX(nodes, epoch) {
|
|
|
65228
65969
|
ref = `e${++sequence}`;
|
|
65229
65970
|
refs[ref] = { backendNodeId: node.backendDOMNodeId, epoch };
|
|
65230
65971
|
}
|
|
65231
|
-
|
|
65972
|
+
if (inside2) {
|
|
65973
|
+
const shown = depth - (scopeAt ?? 0);
|
|
65974
|
+
lines.push(`${" ".repeat(shown)}- ${role || "node"}${name ? ` ${JSON.stringify(name)}` : ""}${ref ? ` [${ref}]` : ""}${stateSuffix(node)}`);
|
|
65975
|
+
}
|
|
65232
65976
|
}
|
|
65233
65977
|
for (const child of node.childIds ?? []) {
|
|
65234
65978
|
const found = byId.get(child);
|
|
65235
65979
|
if (found) visit2(found, interesting ? depth + 1 : depth);
|
|
65236
65980
|
}
|
|
65981
|
+
scopeAt = savedScope;
|
|
65982
|
+
}
|
|
65983
|
+
const scopedRoot = scopeId === void 0 ? void 0 : nodes.find((node) => node.backendDOMNodeId === scopeId);
|
|
65984
|
+
if (scopeId !== void 0 && scopedRoot === void 0) {
|
|
65985
|
+
return { snapshot: "", refs, framesInScope: 0, totalLines: 0, scoped: false };
|
|
65237
65986
|
}
|
|
65238
65987
|
const childIds = new Set(nodes.flatMap((node) => node.childIds ?? []));
|
|
65239
65988
|
for (const root of nodes.filter((node) => !childIds.has(node.nodeId))) visit2(root, 0);
|
|
65240
|
-
return {
|
|
65989
|
+
return {
|
|
65990
|
+
snapshot: lines.join("\n"),
|
|
65991
|
+
refs,
|
|
65992
|
+
// Unscoped means "the whole page", and every frame is then read by the
|
|
65993
|
+
// caller's own frame walk: the count exists only to explain a SCOPE.
|
|
65994
|
+
framesInScope: scopeId === void 0 ? 0 : framesInScope,
|
|
65995
|
+
totalLines: lines.length,
|
|
65996
|
+
scoped: scopeId !== void 0
|
|
65997
|
+
};
|
|
65998
|
+
}
|
|
65999
|
+
function windowSnapshot(text, options = {}) {
|
|
66000
|
+
const lines = text ? text.split("\n").filter((line) => line.length > 0) : [];
|
|
66001
|
+
const totalLines = lines.length;
|
|
66002
|
+
const search = String(options.search ?? "").trim();
|
|
66003
|
+
const matched = search ? lines.filter((line) => line.toLowerCase().includes(search.toLowerCase())) : lines;
|
|
66004
|
+
const matchedLines = matched.length;
|
|
66005
|
+
const requested = Number(options.start ?? 1);
|
|
66006
|
+
const start = Number.isFinite(requested) && requested >= 1 ? Math.floor(requested) : 1;
|
|
66007
|
+
const rawLimit = Number(options.limit ?? 0);
|
|
66008
|
+
const limit = Number.isFinite(rawLimit) && rawLimit > 0 ? Math.floor(rawLimit) : 0;
|
|
66009
|
+
const end = limit ? start - 1 + limit : matchedLines;
|
|
66010
|
+
const page = matched.slice(start - 1, end);
|
|
66011
|
+
return {
|
|
66012
|
+
text: page.join("\n"),
|
|
66013
|
+
totalLines,
|
|
66014
|
+
matchedLines,
|
|
66015
|
+
returnedLines: page.length,
|
|
66016
|
+
start,
|
|
66017
|
+
limit,
|
|
66018
|
+
search
|
|
66019
|
+
};
|
|
65241
66020
|
}
|
|
65242
66021
|
const PAGE_OVERLAP_PX = 80;
|
|
65243
66022
|
function defaultScrollExpression() {
|
|
@@ -65317,6 +66096,8 @@ async function read(ctx, params) {
|
|
|
65317
66096
|
async function snapshot(ctx, params) {
|
|
65318
66097
|
const record = ctx.registry.requireSurface(params.tab);
|
|
65319
66098
|
const contents = record.view.webContents;
|
|
66099
|
+
const scope = stringParam(params, "selector");
|
|
66100
|
+
const rootBackendNodeId = scope ? await backendNodeIdForSelector(ctx, record.view, scope) : void 0;
|
|
65320
66101
|
await ctx.cdp.send(contents, "Accessibility.enable", {});
|
|
65321
66102
|
let nodes = [];
|
|
65322
66103
|
try {
|
|
@@ -65330,22 +66111,49 @@ async function snapshot(ctx, params) {
|
|
|
65330
66111
|
await ctx.cdp.send(contents, "Accessibility.disable", {}).catch(() => {
|
|
65331
66112
|
});
|
|
65332
66113
|
}
|
|
65333
|
-
const {
|
|
65334
|
-
|
|
65335
|
-
|
|
65336
|
-
|
|
66114
|
+
const {
|
|
66115
|
+
snapshot: topRendered,
|
|
66116
|
+
refs: topRefs,
|
|
66117
|
+
scoped,
|
|
66118
|
+
framesInScope
|
|
66119
|
+
} = compactAX(nodes, record.epoch, { rootBackendNodeId });
|
|
66120
|
+
if (rootBackendNodeId !== void 0 && !scoped) {
|
|
66121
|
+
throw new BridgeCommandError(
|
|
66122
|
+
"element_not_found",
|
|
66123
|
+
`selector ${scope} matched an element with no accessibility subtree (hidden, aria-hidden, or inside a collapsed section); expand it first, then snapshot again`
|
|
66124
|
+
);
|
|
66125
|
+
}
|
|
65337
66126
|
const refs = { ...topRefs };
|
|
65338
66127
|
let rendered = topRendered;
|
|
65339
|
-
if (nodes.some(isFrameNode)) {
|
|
66128
|
+
if (!scope && nodes.some(isFrameNode)) {
|
|
65340
66129
|
const blocks = await frameSnapshots(ctx, record, nodes, refs);
|
|
65341
66130
|
if (blocks.length) rendered = [rendered, ...blocks].join("\n");
|
|
65342
66131
|
}
|
|
65343
66132
|
record.refs = refs;
|
|
65344
66133
|
ctx.registry.touch(record);
|
|
66134
|
+
let note = "";
|
|
66135
|
+
if (scope && framesInScope > 0) {
|
|
66136
|
+
const frames = framesInScope;
|
|
66137
|
+
note = `
|
|
66138
|
+
- (a scoped snapshot does not read frames: this section contains ${frames} frame${frames === 1 ? "" : "s"}; snapshot without selector= for their contents)`;
|
|
66139
|
+
}
|
|
66140
|
+
const page = windowSnapshot(rendered, {
|
|
66141
|
+
search: stringParam(params, "search"),
|
|
66142
|
+
start: numberParam(params, "start") ?? 1,
|
|
66143
|
+
limit: numberParam(params, "limit") ?? 0
|
|
66144
|
+
});
|
|
65345
66145
|
return {
|
|
65346
|
-
snapshot:
|
|
66146
|
+
snapshot: page.text + note,
|
|
65347
66147
|
refs: Object.keys(refs).length,
|
|
65348
66148
|
epoch: record.epoch,
|
|
66149
|
+
scoped,
|
|
66150
|
+
frames_in_scope: framesInScope,
|
|
66151
|
+
total_lines: page.totalLines,
|
|
66152
|
+
matched_lines: page.matchedLines,
|
|
66153
|
+
returned_lines: page.returnedLines,
|
|
66154
|
+
start: page.start,
|
|
66155
|
+
limit: page.limit,
|
|
66156
|
+
search: page.search,
|
|
65349
66157
|
...pageOf(record.view)
|
|
65350
66158
|
};
|
|
65351
66159
|
}
|
|
@@ -65591,11 +66399,48 @@ async function nodeIdForSelector(ctx, view, selector) {
|
|
|
65591
66399
|
if (!queried?.nodeId) {
|
|
65592
66400
|
throw new BridgeCommandError(
|
|
65593
66401
|
"element_not_found",
|
|
65594
|
-
`selector ${selector} matched nothing
|
|
66402
|
+
`selector ${selector} matched nothing`,
|
|
66403
|
+
{ candidates: await missCandidates(ctx, view, selector) }
|
|
65595
66404
|
);
|
|
65596
66405
|
}
|
|
65597
66406
|
return queried.nodeId;
|
|
65598
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
|
+
}
|
|
66428
|
+
async function backendNodeIdForSelector(ctx, view, selector) {
|
|
66429
|
+
const nodeId = await nodeIdForSelector(ctx, view, selector);
|
|
66430
|
+
const described = await ctx.cdp.send(
|
|
66431
|
+
view.webContents,
|
|
66432
|
+
"DOM.describeNode",
|
|
66433
|
+
{ nodeId, depth: 0 }
|
|
66434
|
+
);
|
|
66435
|
+
const backendNodeId = described?.node?.backendNodeId;
|
|
66436
|
+
if (backendNodeId === void 0) {
|
|
66437
|
+
throw new BridgeCommandError(
|
|
66438
|
+
"element_not_found",
|
|
66439
|
+
`selector ${selector} has no backend node id`
|
|
66440
|
+
);
|
|
66441
|
+
}
|
|
66442
|
+
return backendNodeId;
|
|
66443
|
+
}
|
|
65599
66444
|
const CLICK_FUNCTION = `function () {
|
|
65600
66445
|
const r = this.getBoundingClientRect();
|
|
65601
66446
|
const cx = r.left + r.width / 2, cy = r.top + r.height / 2;
|
|
@@ -65694,6 +66539,16 @@ const READ_VALUE_FUNCTION = `function () {
|
|
|
65694
66539
|
return String(this.textContent || '');
|
|
65695
66540
|
}`;
|
|
65696
66541
|
const SNAPSHOT_REF = /^e\d+$/;
|
|
66542
|
+
function resolvedFields(node) {
|
|
66543
|
+
return node.resolvedBy === "locator" ? {
|
|
66544
|
+
resolved: {
|
|
66545
|
+
by: "locator",
|
|
66546
|
+
role: node.role ?? "",
|
|
66547
|
+
name: node.name ?? "",
|
|
66548
|
+
matched: node.matched ?? 1
|
|
66549
|
+
}
|
|
66550
|
+
} : {};
|
|
66551
|
+
}
|
|
65697
66552
|
function frameFields(node) {
|
|
65698
66553
|
return node.frame ? { frame_origin: node.frame.origin ?? "" } : {};
|
|
65699
66554
|
}
|
|
@@ -65721,6 +66576,39 @@ async function resolveNode(ctx, record, target2) {
|
|
|
65721
66576
|
}
|
|
65722
66577
|
return finishTop(ctx, contents, target2, pushedId, ref.frameOrigin);
|
|
65723
66578
|
}
|
|
66579
|
+
const locator = parseLocator(target2);
|
|
66580
|
+
if (locator) {
|
|
66581
|
+
const nodes = await readAccessibilityTree(ctx, contents);
|
|
66582
|
+
const hit = resolveLocator(nodes, locator);
|
|
66583
|
+
if (!hit) {
|
|
66584
|
+
throw new BridgeCommandError(
|
|
66585
|
+
"element_not_found",
|
|
66586
|
+
`no element matches ${target2}`,
|
|
66587
|
+
{ candidates: locatorSuggestions(nodes, target2), matched: 0 }
|
|
66588
|
+
);
|
|
66589
|
+
}
|
|
66590
|
+
await ctx.cdp.send(contents, "DOM.getDocument", { depth: 0 });
|
|
66591
|
+
const pushed = await ctx.cdp.send(
|
|
66592
|
+
contents,
|
|
66593
|
+
"DOM.pushNodesByBackendIdsToFrontend",
|
|
66594
|
+
{ backendNodeIds: [hit.backendNodeId] }
|
|
66595
|
+
);
|
|
66596
|
+
const nodeId2 = pushed?.nodeIds?.[0];
|
|
66597
|
+
if (nodeId2 === void 0) {
|
|
66598
|
+
throw new BridgeCommandError(
|
|
66599
|
+
"element_not_found",
|
|
66600
|
+
`${target2} is no longer in the document`
|
|
66601
|
+
);
|
|
66602
|
+
}
|
|
66603
|
+
const resolved = await finishTop(ctx, contents, target2, nodeId2);
|
|
66604
|
+
return {
|
|
66605
|
+
...resolved,
|
|
66606
|
+
resolvedBy: "locator",
|
|
66607
|
+
role: hit.role,
|
|
66608
|
+
name: hit.name,
|
|
66609
|
+
matched: hit.matched
|
|
66610
|
+
};
|
|
66611
|
+
}
|
|
65724
66612
|
const hops = parseFrameHops(target2);
|
|
65725
66613
|
if (hops) {
|
|
65726
66614
|
const hit = await resolveHops(ctx, contents, hops);
|
|
@@ -65733,8 +66621,8 @@ async function resolveNode(ctx, record, target2) {
|
|
|
65733
66621
|
if (!(error instanceof BridgeCommandError) || !TOP_MISS.test(error.message)) {
|
|
65734
66622
|
throw error;
|
|
65735
66623
|
}
|
|
65736
|
-
const { matches, walk } = await searchFrames(ctx, contents, target2);
|
|
65737
|
-
if (
|
|
66624
|
+
const { matches: matches2, walk } = await searchFrames(ctx, contents, target2);
|
|
66625
|
+
if (matches2.length === 0) {
|
|
65738
66626
|
if (!walk.truncated && walk.skipped === 0 && walk.denied === 0)
|
|
65739
66627
|
throw error;
|
|
65740
66628
|
throw new BridgeCommandError(
|
|
@@ -65742,21 +66630,21 @@ async function resolveNode(ctx, record, target2) {
|
|
|
65742
66630
|
`selector ${target2} matched nothing in the page itself or the frames searched (${walkNote(walk)}); address the frame explicitly as <iframe-selector> ${FRAME_HOP} <selector>`
|
|
65743
66631
|
);
|
|
65744
66632
|
}
|
|
65745
|
-
if (
|
|
65746
|
-
const candidate = candidatePath(
|
|
66633
|
+
if (matches2.length === 1 && (walk.truncated || walk.skipped > 0)) {
|
|
66634
|
+
const candidate = candidatePath(matches2[0].scope, target2);
|
|
65747
66635
|
throw new BridgeCommandError(
|
|
65748
66636
|
"element_not_found",
|
|
65749
66637
|
`selector ${target2} matched nothing in the page itself and one element in the frames searched, but not every frame was searched (${walkNote(walk)}), so nothing was done; if this is the one, name it: ${candidate}`,
|
|
65750
66638
|
{ candidates: [candidate] }
|
|
65751
66639
|
);
|
|
65752
66640
|
}
|
|
65753
|
-
if (
|
|
65754
|
-
const candidates =
|
|
66641
|
+
if (matches2.length > 1) {
|
|
66642
|
+
const candidates = matches2.map(
|
|
65755
66643
|
(match) => candidatePath(match.scope, target2)
|
|
65756
66644
|
);
|
|
65757
66645
|
throw new BridgeCommandError(
|
|
65758
66646
|
"element_not_found",
|
|
65759
|
-
`selector ${target2} matched nothing in the page itself and ${
|
|
66647
|
+
`selector ${target2} matched nothing in the page itself and ${matches2.length} elements inside its frames, so nothing was done; name one: ${candidates.join(", ")}`,
|
|
65760
66648
|
{ candidates }
|
|
65761
66649
|
);
|
|
65762
66650
|
}
|
|
@@ -65764,8 +66652,8 @@ async function resolveNode(ctx, record, target2) {
|
|
|
65764
66652
|
ctx,
|
|
65765
66653
|
contents,
|
|
65766
66654
|
target2,
|
|
65767
|
-
|
|
65768
|
-
|
|
66655
|
+
matches2[0].scope,
|
|
66656
|
+
matches2[0].nodeId
|
|
65769
66657
|
);
|
|
65770
66658
|
}
|
|
65771
66659
|
return finishTop(ctx, contents, target2, nodeId);
|
|
@@ -65918,6 +66806,7 @@ async function click(ctx, params) {
|
|
|
65918
66806
|
return {
|
|
65919
66807
|
navigated: navigationSeen || after.url !== before,
|
|
65920
66808
|
...frameFields(node),
|
|
66809
|
+
...resolvedFields(node),
|
|
65921
66810
|
...after
|
|
65922
66811
|
};
|
|
65923
66812
|
}
|
|
@@ -65930,7 +66819,12 @@ async function type(ctx, params) {
|
|
|
65930
66819
|
const typed = await typeInto(ctx, contents, node, text, target2);
|
|
65931
66820
|
if (typed) {
|
|
65932
66821
|
ctx.registry.touch(record);
|
|
65933
|
-
return {
|
|
66822
|
+
return {
|
|
66823
|
+
...typed,
|
|
66824
|
+
...frameFields(node),
|
|
66825
|
+
...resolvedFields(node),
|
|
66826
|
+
...pageOf(record.view)
|
|
66827
|
+
};
|
|
65934
66828
|
}
|
|
65935
66829
|
const frame = await iframeScopeOf(ctx, contents, node);
|
|
65936
66830
|
if (frame) {
|
|
@@ -66091,6 +66985,7 @@ function clampTimeout(requested) {
|
|
|
66091
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}';
|
|
66092
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}';
|
|
66093
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}';
|
|
66094
66989
|
const MAX_REQUESTED_PROPERTIES = 20;
|
|
66095
66990
|
const DEFAULT_DEPTH = 12;
|
|
66096
66991
|
const MAX_DEPTH = 16;
|
|
@@ -66217,6 +67112,51 @@ async function ancestors(ctx, params) {
|
|
|
66217
67112
|
...pageOf(record.view)
|
|
66218
67113
|
};
|
|
66219
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
|
+
}
|
|
66220
67160
|
const MAX_AGENT_TABS = 8;
|
|
66221
67161
|
const BACKGROUND_VIEWPORT = {
|
|
66222
67162
|
x: 0,
|
|
@@ -67104,7 +68044,7 @@ async function upload(ctx, params) {
|
|
|
67104
68044
|
{ selector, frame_origin: node.frame.origin ?? "" }
|
|
67105
68045
|
);
|
|
67106
68046
|
}
|
|
67107
|
-
const
|
|
68047
|
+
const accept2 = await acceptsOf(ctx, record, node.nodeId);
|
|
67108
68048
|
await ctx.cdp.send(contents, "DOM.setFileInputFiles", {
|
|
67109
68049
|
files: paths,
|
|
67110
68050
|
nodeId: node.nodeId
|
|
@@ -67112,7 +68052,7 @@ async function upload(ctx, params) {
|
|
|
67112
68052
|
if (!/not a file input/i.test(String(error))) throw error;
|
|
67113
68053
|
throw new BridgeCommandError("element_not_found", NOT_A_FILE_INPUT, {
|
|
67114
68054
|
selector,
|
|
67115
|
-
accept
|
|
68055
|
+
accept: accept2
|
|
67116
68056
|
});
|
|
67117
68057
|
});
|
|
67118
68058
|
let held = null;
|
|
@@ -67126,10 +68066,10 @@ async function upload(ctx, params) {
|
|
|
67126
68066
|
if (!held) {
|
|
67127
68067
|
throw new BridgeCommandError("element_not_found", NOT_A_FILE_INPUT, {
|
|
67128
68068
|
selector,
|
|
67129
|
-
accept
|
|
68069
|
+
accept: accept2
|
|
67130
68070
|
});
|
|
67131
68071
|
}
|
|
67132
|
-
assertHolds(paths, held, selector,
|
|
68072
|
+
assertHolds(paths, held, selector, accept2);
|
|
67133
68073
|
}
|
|
67134
68074
|
ctx.registry.touch(record);
|
|
67135
68075
|
const facts = paths.map(factOf);
|
|
@@ -67210,7 +68150,7 @@ async function readBack(ctx, record, objectId) {
|
|
|
67210
68150
|
});
|
|
67211
68151
|
return answer?.result?.value ?? null;
|
|
67212
68152
|
}
|
|
67213
|
-
function assertHolds(paths, held, selector,
|
|
68153
|
+
function assertHolds(paths, held, selector, accept2) {
|
|
67214
68154
|
const expected = paths.map((path2) => path$1.basename(path2));
|
|
67215
68155
|
const mismatch = held.count !== expected.length || expected.some((name, index) => held.names[index] !== name) || paths.some((path2, index) => sizeOf(path2) !== held.sizes[index]);
|
|
67216
68156
|
if (!mismatch) return;
|
|
@@ -67221,7 +68161,7 @@ function assertHolds(paths, held, selector, accept) {
|
|
|
67221
68161
|
selector,
|
|
67222
68162
|
attached: expected,
|
|
67223
68163
|
held: held.names,
|
|
67224
|
-
accept,
|
|
68164
|
+
accept: accept2,
|
|
67225
68165
|
reason: "read_back_mismatch"
|
|
67226
68166
|
}
|
|
67227
68167
|
);
|
|
@@ -67376,7 +68316,7 @@ function collectAddressHistory(tabs2, activeTabId) {
|
|
|
67376
68316
|
function foldAscii(value) {
|
|
67377
68317
|
return value.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
|
|
67378
68318
|
}
|
|
67379
|
-
function mergeAddressHistory(tabEntries, historyEntries,
|
|
68319
|
+
function mergeAddressHistory(tabEntries, historyEntries, query2, limit) {
|
|
67380
68320
|
const cap = Math.max(0, Math.floor(limit));
|
|
67381
68321
|
if (cap === 0) return [];
|
|
67382
68322
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -67394,7 +68334,7 @@ function mergeAddressHistory(tabEntries, historyEntries, query, limit) {
|
|
|
67394
68334
|
source: "history"
|
|
67395
68335
|
});
|
|
67396
68336
|
}
|
|
67397
|
-
const needle = foldAscii(
|
|
68337
|
+
const needle = foldAscii(query2.trim());
|
|
67398
68338
|
for (const entry of tabEntries) {
|
|
67399
68339
|
if (merged.length >= cap) break;
|
|
67400
68340
|
if (seen.has(entry.url)) continue;
|
|
@@ -67828,25 +68768,25 @@ class PageControls {
|
|
|
67828
68768
|
};
|
|
67829
68769
|
active.view.webContents.on("found-in-page", this.listener);
|
|
67830
68770
|
}
|
|
67831
|
-
search(active,
|
|
68771
|
+
search(active, query2, forward, next) {
|
|
67832
68772
|
this.open(active);
|
|
67833
68773
|
if (!this.find || this.record !== active) return;
|
|
67834
68774
|
this.stopTimer();
|
|
67835
|
-
const same = this.find.query ===
|
|
68775
|
+
const same = this.find.query === query2;
|
|
67836
68776
|
const continuing = same && next && this.requestId !== null && !this.find.unreported;
|
|
67837
68777
|
this.requestId = null;
|
|
67838
68778
|
this.find = {
|
|
67839
68779
|
...this.find,
|
|
67840
|
-
query,
|
|
67841
|
-
pending:
|
|
68780
|
+
query: query2,
|
|
68781
|
+
pending: query2.length > 0,
|
|
67842
68782
|
unreported: false,
|
|
67843
68783
|
...same ? {} : { ordinal: 0, matches: 0 }
|
|
67844
68784
|
};
|
|
67845
|
-
if (!
|
|
68785
|
+
if (!query2) {
|
|
67846
68786
|
active.view.webContents.stopFindInPage?.("clearSelection");
|
|
67847
68787
|
return;
|
|
67848
68788
|
}
|
|
67849
|
-
this.requestId = active.view.webContents.findInPage?.(
|
|
68789
|
+
this.requestId = active.view.webContents.findInPage?.(query2, {
|
|
67850
68790
|
forward,
|
|
67851
68791
|
// Electron's misleading name means NEW SESSION (44.3 native maps
|
|
67852
68792
|
// it to options->new_session), not "advance". Initial/changed/retry
|
|
@@ -68001,6 +68941,12 @@ const DOCUMENT_SCOPED = /* @__PURE__ */ new Set([
|
|
|
68001
68941
|
"hit_test",
|
|
68002
68942
|
"ancestors",
|
|
68003
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",
|
|
68004
68950
|
"screenshot",
|
|
68005
68951
|
"click",
|
|
68006
68952
|
"type",
|
|
@@ -68031,6 +68977,7 @@ const TAB_SCOPED = /* @__PURE__ */ new Set([
|
|
|
68031
68977
|
"hit_test",
|
|
68032
68978
|
"ancestors",
|
|
68033
68979
|
"snapshot",
|
|
68980
|
+
"query",
|
|
68034
68981
|
"screenshot",
|
|
68035
68982
|
"click",
|
|
68036
68983
|
"type",
|
|
@@ -68248,6 +69195,8 @@ class BrowserHost {
|
|
|
68248
69195
|
return hitTest(this, params);
|
|
68249
69196
|
case "ancestors":
|
|
68250
69197
|
return ancestors(this, params);
|
|
69198
|
+
case "query":
|
|
69199
|
+
return query(this, params);
|
|
68251
69200
|
case "snapshot":
|
|
68252
69201
|
return snapshot(this, params);
|
|
68253
69202
|
case "scroll":
|
|
@@ -68659,7 +69608,7 @@ class BrowserHost {
|
|
|
68659
69608
|
onChordFocusChanged;
|
|
68660
69609
|
/** An explicit tab id fences queued chrome intents: a switch between key
|
|
68661
69610
|
* delivery and IPC must never search/zoom the newly active tab instead. */
|
|
68662
|
-
async controlPage(tabId, action,
|
|
69611
|
+
async controlPage(tabId, action, query2 = "", forward = true, next = false) {
|
|
68663
69612
|
return this.registry.lane(tabId, async () => {
|
|
68664
69613
|
const active = this.registry.activeTab;
|
|
68665
69614
|
if (!active || active.tabId !== tabId || !active.presented || active.view.webContents.isDestroyed())
|
|
@@ -68668,7 +69617,7 @@ class BrowserHost {
|
|
|
68668
69617
|
else if (action === "print") this.pageControls.print(active);
|
|
68669
69618
|
else if (action === "close") this.pageControls.clear();
|
|
68670
69619
|
else if (action === "search")
|
|
68671
|
-
this.pageControls.search(active,
|
|
69620
|
+
this.pageControls.search(active, query2, forward, next);
|
|
68672
69621
|
else this.pageControls.zoom(active, action);
|
|
68673
69622
|
this.onChanged();
|
|
68674
69623
|
return this.chromeState();
|
|
@@ -70318,18 +71267,18 @@ function registerBrowserIpc(options) {
|
|
|
70318
71267
|
});
|
|
70319
71268
|
electron.ipcMain.handle(
|
|
70320
71269
|
"browser-page-control",
|
|
70321
|
-
(event, tabId, action,
|
|
71270
|
+
(event, tabId, action, query2, forward, next) => {
|
|
70322
71271
|
const host = authorize(event);
|
|
70323
71272
|
if (typeof action !== "string" || !["open", "close", "search", "print", "in", "out", "reset"].includes(
|
|
70324
71273
|
action
|
|
70325
71274
|
))
|
|
70326
71275
|
throw new Error("Invalid page control action.");
|
|
70327
|
-
if (typeof
|
|
71276
|
+
if (typeof query2 !== "string" || query2.length > 4096 || typeof forward !== "boolean" || typeof next !== "boolean")
|
|
70328
71277
|
throw new Error("Invalid page search input.");
|
|
70329
71278
|
return host.controlPage(
|
|
70330
71279
|
numberOrThrow(tabId, "tabId"),
|
|
70331
71280
|
action,
|
|
70332
|
-
|
|
71281
|
+
query2,
|
|
70333
71282
|
forward,
|
|
70334
71283
|
next
|
|
70335
71284
|
);
|
|
@@ -70539,14 +71488,14 @@ function addressHistoryRequestOrThrow(value) {
|
|
|
70539
71488
|
if (typeof request.query !== "string") {
|
|
70540
71489
|
throw new Error("The address history query must be a string.");
|
|
70541
71490
|
}
|
|
70542
|
-
const
|
|
70543
|
-
if (
|
|
71491
|
+
const query2 = request.query;
|
|
71492
|
+
if (query2.length > ADDRESS_HISTORY_MAX_QUERY_LENGTH || CONTROL_CHARS.test(query2)) {
|
|
70544
71493
|
throw new Error("The address history query is invalid.");
|
|
70545
71494
|
}
|
|
70546
71495
|
if (typeof request.limit !== "number" || !Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > ADDRESS_HISTORY_MAX_LIMIT) {
|
|
70547
71496
|
throw new Error("The address history limit is invalid.");
|
|
70548
71497
|
}
|
|
70549
|
-
return { requestId: requestId2, expectedTabId, query, limit: request.limit };
|
|
71498
|
+
return { requestId: requestId2, expectedTabId, query: query2, limit: request.limit };
|
|
70550
71499
|
}
|
|
70551
71500
|
function closeTabsIntentOrThrow(value) {
|
|
70552
71501
|
if (!value || typeof value !== "object") {
|
|
@@ -74380,6 +75329,41 @@ class DesktopNotifier {
|
|
|
74380
75329
|
notification.show();
|
|
74381
75330
|
}
|
|
74382
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
|
+
}
|
|
74383
75367
|
const FRAME_LABEL = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
74384
75368
|
function registerDevDriverIPC(options) {
|
|
74385
75369
|
const { window, expectedUrl, outDir, identity: identity2 } = options;
|
|
@@ -83896,18 +84880,18 @@ function frameNavigationVerdict(input, trustedRendererUrls) {
|
|
|
83896
84880
|
return ALLOW;
|
|
83897
84881
|
return deny(`a child frame may not navigate to ${url.protocol}`);
|
|
83898
84882
|
}
|
|
83899
|
-
function permissionVerdict(
|
|
83900
|
-
if (!
|
|
84883
|
+
function permissionVerdict(query2, trustedRendererUrls) {
|
|
84884
|
+
if (!query2.isMainFrame) return false;
|
|
83901
84885
|
if (!trustedRendererUrls.some(
|
|
83902
|
-
(trusted) => trustedDesktopFrame(
|
|
84886
|
+
(trusted) => trustedDesktopFrame(query2.requestingUrl, trusted)
|
|
83903
84887
|
))
|
|
83904
84888
|
return false;
|
|
83905
|
-
if (
|
|
84889
|
+
if (query2.permission === "clipboard-sanitized-write" || query2.permission === "fullscreen")
|
|
83906
84890
|
return true;
|
|
83907
|
-
if (
|
|
83908
|
-
if (
|
|
83909
|
-
return
|
|
83910
|
-
return
|
|
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";
|
|
83911
84895
|
}
|
|
83912
84896
|
function decodedPathname(pathname) {
|
|
83913
84897
|
let current = pathname;
|
|
@@ -84725,6 +85709,13 @@ const devDriverArming = resolveDevDriverArming({
|
|
|
84725
85709
|
});
|
|
84726
85710
|
const devDriverLine = describeDevDriverArming(devDriverArming);
|
|
84727
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
|
+
);
|
|
84728
85719
|
const addressOverlayGate = resolveAddressOverlayGate({
|
|
84729
85720
|
env: launchEnv,
|
|
84730
85721
|
devDriverArmed: devDriverArming.armed,
|
|
@@ -85550,6 +86541,24 @@ electron.app.whenReady().then(async () => {
|
|
|
85550
86541
|
}
|
|
85551
86542
|
}
|
|
85552
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
|
+
);
|
|
85553
86562
|
electron.ipcMain.handle("open-external", async (_, url) => openExternalVetted(url));
|
|
85554
86563
|
electron.ipcMain.handle(
|
|
85555
86564
|
"show-item-in-folder",
|
|
@@ -85595,6 +86604,13 @@ electron.app.whenReady().then(async () => {
|
|
|
85595
86604
|
}
|
|
85596
86605
|
});
|
|
85597
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
|
+
}
|
|
85598
86614
|
const parent = electron.BrowserWindow.fromWebContents(event.sender) ?? mainWindow;
|
|
85599
86615
|
if (!parent) {
|
|
85600
86616
|
logger.error(
|