local-operator-ui 0.34.44 → 0.34.45
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 +948 -66
- package/out/preload/index.js +234 -18
- package/out/renderer/assets/{_basePickBy-C-GwcPo5.js → _basePickBy-AOIZJtmP.js} +1 -1
- package/out/renderer/assets/{_baseUniq-whkmDW6w.js → _baseUniq-6rYoQPQm.js} +1 -1
- package/out/renderer/assets/{agent-details-page-DpCpkTfN.js → agent-details-page-B9MNIwUW.js} +2 -2
- package/out/renderer/assets/agent-hub-page-Bj3VsEfD.js +11 -0
- package/out/renderer/assets/agents-page-y_fPy8cB.js +7 -0
- package/out/renderer/assets/arc-DEIVtaqP.js +1 -0
- package/out/renderer/assets/architectureDiagram-IEHRJDOE-C6lgf3ft.js +36 -0
- package/out/renderer/assets/{blockDiagram-JOT3LUYC-Dp4G8uLX.js → blockDiagram-JOT3LUYC-rUXOYgBS.js} +6 -6
- package/out/renderer/assets/{book-open-C9onOH1C.js → book-open-BWUyDXVa.js} +1 -1
- package/out/renderer/assets/browser-page-BENwHsVf.js +1 -0
- package/out/renderer/assets/browser-webauthn-prompt-BlawzvV4.js +1 -0
- package/out/renderer/assets/{c4Diagram-VJAJSXHY-CnX5ELGv.js → c4Diagram-VJAJSXHY-B5DZCCX3.js} +1 -1
- package/out/renderer/assets/channel-vM9rusk9.js +1 -0
- package/out/renderer/assets/{chunk-4BMEZGHF-DYgqjjvg.js → chunk-4BMEZGHF-LYO-H6gm.js} +1 -1
- package/out/renderer/assets/{chunk-A2AXSNBT-3DoU7E6Y.js → chunk-A2AXSNBT-C-eXpCGB.js} +1 -1
- package/out/renderer/assets/{chunk-AEK57VVT-OX8UcnIV.js → chunk-AEK57VVT-CkjgDW9B.js} +1 -1
- package/out/renderer/assets/{chunk-D6G4REZN-Dbt1r37J.js → chunk-D6G4REZN-hAERljt9.js} +1 -1
- package/out/renderer/assets/{chunk-RZ5BOZE2-CdLKa5S8.js → chunk-RZ5BOZE2-D1aP9fPZ.js} +1 -1
- package/out/renderer/assets/{chunk-XZIHB7SX-B_CjCOio.js → chunk-XZIHB7SX-Chv37Bqx.js} +1 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-BCqIuRq4.js +1 -0
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-BCqIuRq4.js +1 -0
- package/out/renderer/assets/clone-Bj8HwBLn.js +1 -0
- package/out/renderer/assets/{console-mirror-D1YYJxrt.js → console-mirror-DF_IQ1r-.js} +14 -14
- package/out/renderer/assets/consoleCapture-CAbvxCQS.js +1 -0
- package/out/renderer/assets/{conversation-input-sync-BbbcfWqh.js → conversation-input-sync-BdhFw-JY.js} +259 -261
- package/out/renderer/assets/dagre-OKDRZEBW-ClDfyejg.js +4 -0
- package/out/renderer/assets/diagram-SSKATNLV-BECmfn9C.js +43 -0
- package/out/renderer/assets/diagram-VNBRO52H-82BMsx_Z.js +24 -0
- package/out/renderer/assets/{erDiagram-Q7BY3M3F-Cs4yDA7g.js → erDiagram-Q7BY3M3F-BiCriqsZ.js} +1 -1
- package/out/renderer/assets/{error-boundary-YxH9ow-2.js → error-boundary-B4K6A3dS.js} +2 -2
- package/out/renderer/assets/{flowDiagram-4HSFHLVR-BofJ9_8f.js → flowDiagram-4HSFHLVR-D4PQMO6X.js} +1 -1
- package/out/renderer/assets/ganttDiagram-APWFNJXF-Rts_QpVD.js +257 -0
- package/out/renderer/assets/gitGraphDiagram-7IBYFJ6S-B1rxvfyh.js +65 -0
- package/out/renderer/assets/{graph-D3WT1lJS.js → graph-DxQCKx-L.js} +1 -1
- package/out/renderer/assets/index-BJ-AJLyd.js +804 -0
- package/out/renderer/assets/index-BhsV-ipc.js +1 -0
- package/out/renderer/assets/index-C7mMgpwT.css +1 -0
- package/out/renderer/assets/index-XFXAg7sM.js +7 -0
- package/out/renderer/assets/infoDiagram-PH2N3AL5-CDvWuX2O.js +2 -0
- package/out/renderer/assets/{installer-BzSW3GXd.js → installer-B4Bd2pBF.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-U35MCT3I-DVmD515J.js → journeyDiagram-U35MCT3I-CnefKX-i.js} +1 -1
- package/out/renderer/assets/{kanban-definition-NDS4AKOZ-DpiJ7P3i.js → kanban-definition-NDS4AKOZ-Kd7aNO4_.js} +1 -1
- package/out/renderer/assets/{layout-BFA2wwh_.js → layout-CMQ0zdhs.js} +1 -1
- package/out/renderer/assets/legacy-agents-page-PBvD5xd9.js +33 -0
- package/out/renderer/assets/{mermaid.core-C7iGmYcY.js → mermaid.core-x5Fva3t5.js} +5 -5
- package/out/renderer/assets/mesh-page-IOGN512j.js +1 -0
- package/out/renderer/assets/messages-D3mGACg6.js +3 -0
- package/out/renderer/assets/mindmap-definition-ALO5MXBD-DJwQ3wYh.js +95 -0
- package/out/renderer/assets/mini-DHQCkYmb.js +1 -0
- package/out/renderer/assets/{notebook-pen-rCh1XFso.js → notebook-pen-CKFoYavJ.js} +1 -1
- package/out/renderer/assets/org-access-_jPzS_wW.js +1 -0
- package/out/renderer/assets/org-surface-gate-D29XdDTt.js +1 -0
- package/out/renderer/assets/{page-header-DWR3DkBt.js → page-header-D90TvAM5.js} +1 -1
- package/out/renderer/assets/pieDiagram-IB7DONF6-CW-ezwOn.js +30 -0
- package/out/renderer/assets/projects-page-DGLblpIY.js +45 -0
- package/out/renderer/assets/publication-validation-ZquLmMLD.js +1 -0
- package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-u3qKyomE.js → quadrantDiagram-7GDLP6J5-cgwnEsXh.js} +1 -1
- package/out/renderer/assets/{radar-MK3ICKWK-DTXBXOd-.js → radar-MK3ICKWK-DvOkOeQ6.js} +1 -1
- package/out/renderer/assets/radient-auth-buttons-y3JK-yD8.js +1 -0
- package/out/renderer/assets/{requirementDiagram-KVF5MWMF-CIyOJzHO.js → requirementDiagram-KVF5MWMF-DOMWjtoO.js} +1 -1
- package/out/renderer/assets/sankeyDiagram-QLVOVGJD-CE3E7VO5.js +10 -0
- package/out/renderer/assets/{schedules-page-DHwzeRvF.js → schedules-page-ETT8R0wn.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-DCj3Ke6W.js → sequenceDiagram-X6HHIX6F-C4EGcl7U.js} +1 -1
- package/out/renderer/assets/{settings-page-Br0K0YLW.js → settings-page-BZDF6UIV.js} +1 -1
- package/out/renderer/assets/stateDiagram-DGXRK772-wBbKaUQh.js +1 -0
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-Bh0k2Dz3.js +1 -0
- package/out/renderer/assets/{timeline-definition-BDJGKUSR-C4cCAtD2.js → timeline-definition-BDJGKUSR-CgTCOxCY.js} +1 -1
- package/out/renderer/assets/{use-download-agent-mutation-CRmN4Z4O.js → use-download-agent-mutation-DkI3E5yA.js} +4 -4
- package/out/renderer/assets/use-memberships-query-Hv-eprVl.js +1 -0
- package/out/renderer/assets/{use-session-snapshot-DZAAvDEa.js → use-session-snapshot-CfEF5TPK.js} +1 -1
- package/out/renderer/assets/{xychartDiagram-VJFVF3MP-DG9g8Bz_.js → xychartDiagram-VJFVF3MP-G2SxM5sQ.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 +2 -2
- package/out/renderer/assets/agent-hub-page-CUIy_Kx2.js +0 -11
- package/out/renderer/assets/agents-page-2HbuAEbx.js +0 -7
- package/out/renderer/assets/arc-DDs-mKBJ.js +0 -1
- package/out/renderer/assets/architectureDiagram-IEHRJDOE-CPUUDGvU.js +0 -36
- package/out/renderer/assets/browser-page-DYIlDoNt.js +0 -1
- package/out/renderer/assets/browser-webauthn-prompt-BCVHqXb0.js +0 -1
- package/out/renderer/assets/channel-DMF6TPjP.js +0 -1
- package/out/renderer/assets/classDiagram-GIVACNV2-B0EbOHV0.js +0 -1
- package/out/renderer/assets/classDiagram-v2-COTLJTTW-B0EbOHV0.js +0 -1
- package/out/renderer/assets/clone-D1pjaXDr.js +0 -1
- package/out/renderer/assets/consoleCapture-B-w56zDU.js +0 -1
- package/out/renderer/assets/dagre-OKDRZEBW-Di-XleTu.js +0 -4
- package/out/renderer/assets/diagram-SSKATNLV-HX5Tirdq.js +0 -43
- package/out/renderer/assets/diagram-VNBRO52H-BkGCdAFk.js +0 -24
- package/out/renderer/assets/ganttDiagram-APWFNJXF-B8-HoTDC.js +0 -257
- package/out/renderer/assets/gitGraphDiagram-7IBYFJ6S-B72gxYgp.js +0 -65
- package/out/renderer/assets/index-B7VSZn2a.css +0 -1
- package/out/renderer/assets/index-Bo-U0L08.js +0 -804
- package/out/renderer/assets/index-BwwNZ8BB.js +0 -1
- package/out/renderer/assets/index-StPsU3lP.js +0 -7
- package/out/renderer/assets/infoDiagram-PH2N3AL5-ChbJv-y5.js +0 -2
- package/out/renderer/assets/legacy-agents-page-C_w_SC0A.js +0 -33
- package/out/renderer/assets/mesh-page-DMSyd0cL.js +0 -1
- package/out/renderer/assets/mindmap-definition-ALO5MXBD-FgYmOkcR.js +0 -95
- package/out/renderer/assets/mini-B9yZoGaU.js +0 -1
- package/out/renderer/assets/org-surface-gate-CDIyXoCz.js +0 -1
- package/out/renderer/assets/pieDiagram-IB7DONF6-Ahxca-lE.js +0 -30
- package/out/renderer/assets/projects-page-BclfcCc4.js +0 -50
- package/out/renderer/assets/radient-auth-buttons-D6EcW_pf.js +0 -1
- package/out/renderer/assets/sankeyDiagram-QLVOVGJD-DPL4XBFG.js +0 -10
- package/out/renderer/assets/stateDiagram-DGXRK772-C_ILyKXn.js +0 -1
- package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-DgnGm7tu.js +0 -1
- package/out/renderer/assets/ui-preferences-store-lljzccwU.js +0 -1
- package/out/renderer/assets/use-memberships-query-DIOIcGCQ.js +0 -1
- /package/out/renderer/assets/{index-CzjIMcYW.js → index-B-uibf5k.js} +0 -0
package/out/main/index.js
CHANGED
|
@@ -92,6 +92,7 @@ const mcpCatalogCwdPattern = /^(\/|[A-Za-z]:[\\/])/;
|
|
|
92
92
|
const mcpCatalogCwd = zod.z.string().min(1).max(4096).regex(mcpCatalogCwdPattern);
|
|
93
93
|
const SUBSCRIPTION_ID_PATTERN = /^[a-f0-9]{32}$/;
|
|
94
94
|
const requestId = zod.z.string().regex(/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/);
|
|
95
|
+
const definitionRevision = zod.z.string().min(1).max(512).nullish();
|
|
95
96
|
const meshId = zod.z.string().regex(/^[A-Za-z0-9_-]{1,128}$/);
|
|
96
97
|
const approvalId = zod.z.string().regex(/^ap_[0-9a-hjkmnp-tv-z]{1,64}$/);
|
|
97
98
|
const sessionImage = zod.z.object({
|
|
@@ -262,6 +263,12 @@ const publicationDescription = zod.z.string().refine((description) => publicatio
|
|
|
262
263
|
const publicationTools = zod.z.array(zod.z.string()).refine((tools) => publicationToolsRule(tools) === null, {
|
|
263
264
|
message: "That tool list cannot be published."
|
|
264
265
|
});
|
|
266
|
+
const publicationPolicyFields = {
|
|
267
|
+
requestId: requestId.optional(),
|
|
268
|
+
subscribe: zod.z.boolean().optional(),
|
|
269
|
+
autoPush: zod.z.boolean().optional(),
|
|
270
|
+
confirmPublicEgress: zod.z.boolean().optional()
|
|
271
|
+
};
|
|
265
272
|
const publicationDocument = zod.z.object({
|
|
266
273
|
name: publicationName,
|
|
267
274
|
description: publicationDescription,
|
|
@@ -325,6 +332,21 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
325
332
|
zod.z.object({ op: zod.z.literal("runtimes.list") }).strict(),
|
|
326
333
|
zod.z.object({ op: zod.z.literal("profiles.list") }).strict(),
|
|
327
334
|
zod.z.object({ op: zod.z.literal("profiles.get"), name: profileName }).strict(),
|
|
335
|
+
/*
|
|
336
|
+
* Definition CAS (proposed additive wire, b-wire-receipt-definition-cas-and-adopt).
|
|
337
|
+
* `expectedDefinitionRevision` is an opaque echo of the `definition_revision` the
|
|
338
|
+
* editor was opened with; absent/null is the LEGACY unconditional write and is
|
|
339
|
+
* NOT a protected dirty-edit guarantee, so a caller that wants CAS protection
|
|
340
|
+
* must send it. Strict like every field here: a typo must 400, not silently
|
|
341
|
+
* become an unconditional write.
|
|
342
|
+
*/
|
|
343
|
+
zod.z.object({
|
|
344
|
+
op: zod.z.literal("profiles.update"),
|
|
345
|
+
name: profileName,
|
|
346
|
+
requestId,
|
|
347
|
+
fields: profileFields,
|
|
348
|
+
expectedDefinitionRevision: definitionRevision.optional()
|
|
349
|
+
}).strict(),
|
|
328
350
|
zod.z.object({ op: zod.z.literal("profiles.install"), name: profileName, requestId }).strict(),
|
|
329
351
|
zod.z.object({
|
|
330
352
|
op: zod.z.literal("profiles.create"),
|
|
@@ -335,12 +357,6 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
335
357
|
instructions: zod.z.string().min(1).max(8e3)
|
|
336
358
|
})
|
|
337
359
|
}).strict(),
|
|
338
|
-
zod.z.object({
|
|
339
|
-
op: zod.z.literal("profiles.update"),
|
|
340
|
-
name: profileName,
|
|
341
|
-
requestId,
|
|
342
|
-
fields: profileFields
|
|
343
|
-
}).strict(),
|
|
344
360
|
/*
|
|
345
361
|
* THE HUB AUTO-UPDATE PLANE (backend `server/routes/desktop_hub.py`, gated by
|
|
346
362
|
* the `hub_updates` capability). `hub.updates` is a STORE READ on the backend
|
|
@@ -356,20 +372,83 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
356
372
|
* apply-all schema does not offer it.
|
|
357
373
|
*/
|
|
358
374
|
zod.z.object({ op: zod.z.literal("hub.updates") }).strict(),
|
|
375
|
+
// Initial skill publication uses an actual discovered source and managed
|
|
376
|
+
// alias, never a synthetic link ID or a private-directory clone.
|
|
377
|
+
zod.z.object({
|
|
378
|
+
op: zod.z.literal("hub.skillPull"),
|
|
379
|
+
requestId,
|
|
380
|
+
hubId: id$1,
|
|
381
|
+
hubSource: zod.z.string().min(1).max(2048),
|
|
382
|
+
visibility: zod.z.enum(["public", "org"]),
|
|
383
|
+
tenantId: id$1.nullable(),
|
|
384
|
+
localAlias: profileName,
|
|
385
|
+
subscribe: zod.z.boolean().optional(),
|
|
386
|
+
autoPush: zod.z.boolean().optional(),
|
|
387
|
+
confirmPublicEgress: zod.z.boolean().optional()
|
|
388
|
+
}).strict(),
|
|
389
|
+
zod.z.object({
|
|
390
|
+
op: zod.z.literal("hub.skillPublish"),
|
|
391
|
+
requestId,
|
|
392
|
+
dryRun: zod.z.boolean(),
|
|
393
|
+
sourceSkill: profileName,
|
|
394
|
+
localAlias: profileName,
|
|
395
|
+
visibility: zod.z.enum(["public", "org"]),
|
|
396
|
+
tenantId: id$1.nullable(),
|
|
397
|
+
subscribe: zod.z.boolean(),
|
|
398
|
+
autoPush: zod.z.boolean(),
|
|
399
|
+
confirmPublicEgress: zod.z.boolean(),
|
|
400
|
+
previewReceipt: zod.z.string().min(1).max(4096).optional(),
|
|
401
|
+
confirmPublish: zod.z.literal(true).optional()
|
|
402
|
+
}).strict(),
|
|
403
|
+
// Full inventory is additive: old callers still receive pending agents/teams
|
|
404
|
+
// only. Policy revision is required even for a single independent toggle so
|
|
405
|
+
// an intervening direct config edit cannot be silently overwritten.
|
|
406
|
+
zod.z.object({
|
|
407
|
+
op: zod.z.literal("hub.links"),
|
|
408
|
+
kind: zod.z.enum(["agent", "team", "skill"]).optional()
|
|
409
|
+
}).strict(),
|
|
410
|
+
zod.z.object({
|
|
411
|
+
op: zod.z.literal("hub.policy"),
|
|
412
|
+
requestId,
|
|
413
|
+
linkId: zod.z.string().min(1).max(256),
|
|
414
|
+
expectedPolicyRevision: zod.z.string().min(1).max(256),
|
|
415
|
+
subscribe: zod.z.boolean().optional(),
|
|
416
|
+
autoPush: zod.z.boolean().optional(),
|
|
417
|
+
confirmPublicEgress: zod.z.boolean().optional()
|
|
418
|
+
}).strict(),
|
|
359
419
|
zod.z.object({
|
|
360
420
|
op: zod.z.literal("hub.check"),
|
|
361
421
|
requestId,
|
|
422
|
+
linkId: zod.z.string().min(1).max(256).optional(),
|
|
423
|
+
direction: zod.z.enum(["pull", "push"]).optional(),
|
|
362
424
|
kind: hubItemKind.optional(),
|
|
363
425
|
name: profileName.optional()
|
|
364
426
|
}).strict(),
|
|
365
427
|
zod.z.object({
|
|
366
428
|
op: zod.z.literal("hub.apply"),
|
|
367
429
|
requestId,
|
|
368
|
-
|
|
369
|
-
|
|
430
|
+
previewReceipt: zod.z.string().min(1).max(4096).optional(),
|
|
431
|
+
confirmApply: zod.z.literal(true).optional(),
|
|
432
|
+
linkId: zod.z.string().min(1).max(256).optional(),
|
|
433
|
+
direction: zod.z.literal("pull").optional(),
|
|
434
|
+
kind: hubItemKind.optional(),
|
|
435
|
+
name: profileName.optional(),
|
|
370
436
|
prefer: zod.z.enum(["local", "remote"]).optional(),
|
|
371
437
|
acknowledgeUnknownBaseline: zod.z.boolean().optional(),
|
|
372
|
-
dryRun: zod.z.boolean().optional()
|
|
438
|
+
dryRun: zod.z.boolean().optional(),
|
|
439
|
+
/*
|
|
440
|
+
* LEGACY UNKNOWN-ORIGIN SOURCE CONFIRMATION (proposed additive wire,
|
|
441
|
+
* b-wire-receipt §Part 2). An EXPLICIT act that states a destination the
|
|
442
|
+
* caller asserts: it materializes the real baseline identity and scope,
|
|
443
|
+
* it never infers Public or the active organization. `resolve_source`
|
|
444
|
+
* selects the branch; the source/scope triple is REQUIRED with it so a
|
|
445
|
+
* half-stated destination cannot compose a guessed origin. The service
|
|
446
|
+
* refuses a conflicting known scope with `origin-conflict`.
|
|
447
|
+
*/
|
|
448
|
+
resolveSource: zod.z.literal(true).optional(),
|
|
449
|
+
hubSource: zod.z.string().min(1).max(2048).optional(),
|
|
450
|
+
visibility: zod.z.enum(["public", "org"]).optional(),
|
|
451
|
+
tenantId: zod.z.string().min(1).max(128).nullable().optional()
|
|
373
452
|
}).strict(),
|
|
374
453
|
zod.z.object({
|
|
375
454
|
op: zod.z.literal("hub.applyAll"),
|
|
@@ -379,21 +458,38 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
379
458
|
zod.z.object({
|
|
380
459
|
op: zod.z.literal("hub.retry"),
|
|
381
460
|
requestId,
|
|
382
|
-
|
|
383
|
-
|
|
461
|
+
linkId: zod.z.string().min(1).max(256).optional(),
|
|
462
|
+
direction: zod.z.enum(["pull", "push"]).optional(),
|
|
463
|
+
kind: hubItemKind.optional(),
|
|
464
|
+
name: profileName.optional()
|
|
384
465
|
}).strict(),
|
|
385
|
-
zod.z.object({ op: zod.z.literal("teams.list") }).strict(),
|
|
386
|
-
zod.z.object({ op: zod.z.literal("teams.get"), name: profileName }).strict(),
|
|
387
466
|
zod.z.object({
|
|
388
|
-
op: zod.z.literal("
|
|
467
|
+
op: zod.z.literal("hub.push"),
|
|
389
468
|
requestId,
|
|
390
|
-
|
|
469
|
+
linkId: zod.z.string().min(1).max(256),
|
|
470
|
+
direction: zod.z.literal("push"),
|
|
471
|
+
dryRun: zod.z.boolean(),
|
|
472
|
+
previewReceipt: zod.z.string().min(1).max(4096).optional(),
|
|
473
|
+
confirmPublish: zod.z.literal(true).optional()
|
|
391
474
|
}).strict(),
|
|
475
|
+
zod.z.object({ op: zod.z.literal("teams.list") }).strict(),
|
|
476
|
+
zod.z.object({ op: zod.z.literal("teams.get"), name: profileName }).strict(),
|
|
477
|
+
/*
|
|
478
|
+
* Team CAS is the same optional opaque echo as the profile arm: absent/null is
|
|
479
|
+
* the legacy unconditional write, a supplied stale/malformed value is refused
|
|
480
|
+
* 409 `local-concurrent-edit` before any write under the definition lock.
|
|
481
|
+
*/
|
|
392
482
|
zod.z.object({
|
|
393
483
|
op: zod.z.literal("teams.update"),
|
|
394
484
|
name: profileName,
|
|
395
485
|
requestId,
|
|
396
|
-
fields: teamFields
|
|
486
|
+
fields: teamFields,
|
|
487
|
+
expectedDefinitionRevision: definitionRevision.optional()
|
|
488
|
+
}).strict(),
|
|
489
|
+
zod.z.object({
|
|
490
|
+
op: zod.z.literal("teams.create"),
|
|
491
|
+
requestId,
|
|
492
|
+
fields: teamFields.extend({ name: zod.z.string().min(1).max(64) })
|
|
397
493
|
}).strict(),
|
|
398
494
|
zod.z.object({
|
|
399
495
|
op: zod.z.literal("sessions.list"),
|
|
@@ -702,6 +798,24 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
702
798
|
*/
|
|
703
799
|
peerJournalSource: zod.z.boolean().optional()
|
|
704
800
|
}).strict(),
|
|
801
|
+
// The inventory belongs to the backend, not to a renderer filesystem walk.
|
|
802
|
+
// Keep the cursor opaque: its query/revision binding is the service's decision.
|
|
803
|
+
zod.z.object({
|
|
804
|
+
op: zod.z.literal("sessions.files"),
|
|
805
|
+
sessionId,
|
|
806
|
+
scope: zod.z.enum(["family", "self"]).optional(),
|
|
807
|
+
kind: zod.z.string().max(256).optional(),
|
|
808
|
+
q: zod.z.string().max(256).optional(),
|
|
809
|
+
sort: zod.z.enum(["recent", "name", "kind", "modified", "created", "size"]).optional(),
|
|
810
|
+
order: zod.z.enum(["asc", "desc"]).optional(),
|
|
811
|
+
limit: zod.z.number().int().min(1).max(200).optional(),
|
|
812
|
+
cursor: zod.z.string().max(8192).optional()
|
|
813
|
+
}).strict(),
|
|
814
|
+
zod.z.object({
|
|
815
|
+
op: zod.z.literal("sessions.files.materialise"),
|
|
816
|
+
sessionId,
|
|
817
|
+
fileId: zod.z.string().regex(/^[a-f0-9]{16}$/)
|
|
818
|
+
}).strict(),
|
|
705
819
|
zod.z.object({
|
|
706
820
|
op: zod.z.literal("sessions.history"),
|
|
707
821
|
sessionId,
|
|
@@ -1204,6 +1318,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
1204
1318
|
op: zod.z.literal("agent.publish"),
|
|
1205
1319
|
agentId: id$1,
|
|
1206
1320
|
document: publicationDocument.optional(),
|
|
1321
|
+
...publicationPolicyFields,
|
|
1207
1322
|
/*
|
|
1208
1323
|
* The publication TARGET (§4.4/§4.7). Both travel together or neither does,
|
|
1209
1324
|
* and the rule is a `superRefine` on the whole UNION (below) rather than a
|
|
@@ -1235,11 +1350,20 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
1235
1350
|
// republish that did not name one would have to guess which public row to
|
|
1236
1351
|
// overwrite — and guessing here overwrites somebody's listing.
|
|
1237
1352
|
hubAgentId: id$1,
|
|
1353
|
+
expectedRemoteRevision: zod.z.string().min(1).max(512).optional(),
|
|
1238
1354
|
document: publicationDocument.optional(),
|
|
1355
|
+
...publicationPolicyFields,
|
|
1239
1356
|
/** The publication target, on the same terms as `agent.publish` above. */
|
|
1240
1357
|
visibility: zod.z.literal("org").optional(),
|
|
1241
1358
|
tenantId: id$1.optional()
|
|
1242
1359
|
}).strict(),
|
|
1360
|
+
zod.z.object({
|
|
1361
|
+
op: zod.z.literal("team.publish"),
|
|
1362
|
+
teamId: id$1,
|
|
1363
|
+
...publicationPolicyFields,
|
|
1364
|
+
visibility: zod.z.literal("org").optional(),
|
|
1365
|
+
tenantId: id$1.optional()
|
|
1366
|
+
}).strict(),
|
|
1243
1367
|
/*
|
|
1244
1368
|
* Pulling a published organization team into this machine's local registry
|
|
1245
1369
|
* (§4.5/§8.4's "list + pull action").
|
|
@@ -1837,6 +1961,8 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
1837
1961
|
"org_agents.list",
|
|
1838
1962
|
"org_team.get",
|
|
1839
1963
|
"org_teams.list",
|
|
1964
|
+
"org_skills.list",
|
|
1965
|
+
"org_skill.get",
|
|
1840
1966
|
/*
|
|
1841
1967
|
* The verification-email resend (core PR2,
|
|
1842
1968
|
* `feat/quota-notice-resend`): it maps to the upstream's JWT-only
|
|
@@ -1854,6 +1980,7 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
1854
1980
|
agent_id: id$1.optional(),
|
|
1855
1981
|
comment_id: id$1.optional(),
|
|
1856
1982
|
team_id: id$1.optional(),
|
|
1983
|
+
skill_id: id$1.optional(),
|
|
1857
1984
|
query: zod.z.record(zod.z.union([zod.z.string().max(1024), zod.z.number().int()])).optional(),
|
|
1858
1985
|
payload: zod.z.record(zod.z.unknown()).optional(),
|
|
1859
1986
|
confirmed: zod.z.boolean().optional()
|
|
@@ -2239,6 +2366,71 @@ const desktopRequestUnion = zod.z.discriminatedUnion("op", [
|
|
|
2239
2366
|
]);
|
|
2240
2367
|
const desktopRequestSchema = desktopRequestUnion.superRefine(
|
|
2241
2368
|
(request, ctx) => {
|
|
2369
|
+
if (request.op === "hub.skillPull" || request.op === "hub.skillPublish") {
|
|
2370
|
+
if (request.visibility === "public" && request.tenantId !== null || request.visibility === "org" && !request.tenantId) {
|
|
2371
|
+
ctx.addIssue({
|
|
2372
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2373
|
+
message: "A skill destination requires explicit paired scope",
|
|
2374
|
+
path: ["tenantId"]
|
|
2375
|
+
});
|
|
2376
|
+
return;
|
|
2377
|
+
}
|
|
2378
|
+
if (request.op === "hub.skillPublish" && (request.dryRun ? request.previewReceipt !== void 0 || request.confirmPublish !== void 0 : !request.previewReceipt || request.confirmPublish !== true)) {
|
|
2379
|
+
ctx.addIssue({
|
|
2380
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2381
|
+
message: "An initial skill publication requires its reviewed draft receipt",
|
|
2382
|
+
path: ["previewReceipt"]
|
|
2383
|
+
});
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
if (request.op === "hub.check" || request.op === "hub.apply" || request.op === "hub.retry") {
|
|
2388
|
+
const hasLink = request.linkId !== void 0;
|
|
2389
|
+
const hasLegacy = request.kind !== void 0 || request.name !== void 0;
|
|
2390
|
+
if (hasLink && hasLegacy || request.op !== "hub.check" && !hasLink && (!request.kind || !request.name) || request.op === "hub.retry" && hasLink && !request.direction || request.direction === "push" && !hasLink) {
|
|
2391
|
+
ctx.addIssue({
|
|
2392
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2393
|
+
message: "A hub action requires one unambiguous selector and an explicit retry direction",
|
|
2394
|
+
path: ["linkId"]
|
|
2395
|
+
});
|
|
2396
|
+
return;
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
if (request.op === "hub.apply" && (request.previewReceipt !== void 0 || request.confirmApply !== void 0) && (!request.linkId || request.dryRun || !request.previewReceipt || request.confirmApply !== true)) {
|
|
2400
|
+
ctx.addIssue({
|
|
2401
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2402
|
+
message: "A viewed incoming application requires its scoped preview receipt and confirmation",
|
|
2403
|
+
path: ["previewReceipt"]
|
|
2404
|
+
});
|
|
2405
|
+
return;
|
|
2406
|
+
}
|
|
2407
|
+
if (request.op === "hub.apply" && request.resolveSource === true) {
|
|
2408
|
+
const scopePaired = request.visibility === "public" && request.tenantId === null || request.visibility === "org" && typeof request.tenantId === "string" && request.tenantId.length > 0;
|
|
2409
|
+
if (!request.hubSource || !scopePaired || request.acknowledgeUnknownBaseline !== true || request.linkId !== void 0 || request.previewReceipt !== void 0 || request.confirmApply !== void 0 || request.prefer !== void 0) {
|
|
2410
|
+
ctx.addIssue({
|
|
2411
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2412
|
+
message: "Confirming a source requires its exact stated destination and the unknown-baseline acknowledgement, with no link, preview or preference",
|
|
2413
|
+
path: ["hubSource"]
|
|
2414
|
+
});
|
|
2415
|
+
return;
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
if (request.op === "hub.push" && (request.dryRun ? request.previewReceipt !== void 0 || request.confirmPublish !== void 0 : !request.previewReceipt || request.confirmPublish !== true)) {
|
|
2419
|
+
ctx.addIssue({
|
|
2420
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2421
|
+
message: "A confirmed publication requires its reviewed preview receipt",
|
|
2422
|
+
path: ["previewReceipt"]
|
|
2423
|
+
});
|
|
2424
|
+
return;
|
|
2425
|
+
}
|
|
2426
|
+
if (request.op === "hub.policy" && request.subscribe === void 0 && request.autoPush === void 0) {
|
|
2427
|
+
ctx.addIssue({
|
|
2428
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2429
|
+
message: "A hub policy change must name subscribe or autoPush",
|
|
2430
|
+
path: ["subscribe"]
|
|
2431
|
+
});
|
|
2432
|
+
return;
|
|
2433
|
+
}
|
|
2242
2434
|
if (request.op === "sessions.answer") {
|
|
2243
2435
|
if (request.askId !== void 0) {
|
|
2244
2436
|
if (!request.askId)
|
|
@@ -2314,7 +2506,15 @@ const desktopRequestSchema = desktopRequestUnion.superRefine(
|
|
|
2314
2506
|
}
|
|
2315
2507
|
return;
|
|
2316
2508
|
}
|
|
2317
|
-
if (request.op !== "agent.publish" && request.op !== "agent.republish") {
|
|
2509
|
+
if (request.op !== "agent.publish" && request.op !== "agent.republish" && request.op !== "team.publish") {
|
|
2510
|
+
return;
|
|
2511
|
+
}
|
|
2512
|
+
if ((request.subscribe !== void 0 || request.autoPush !== void 0 || request.confirmPublicEgress !== void 0) && !request.requestId) {
|
|
2513
|
+
ctx.addIssue({
|
|
2514
|
+
code: zod.z.ZodIssueCode.custom,
|
|
2515
|
+
message: "Initial link policy needs a durable publication request ID",
|
|
2516
|
+
path: ["requestId"]
|
|
2517
|
+
});
|
|
2318
2518
|
return;
|
|
2319
2519
|
}
|
|
2320
2520
|
if (Boolean(request.visibility === "org") !== Boolean(request.tenantId)) {
|
|
@@ -2436,6 +2636,9 @@ const HUB_APPLY_ALL_DEADLINE_MS = 5 * HUB_ITEM_WRITE_DEADLINE_MS;
|
|
|
2436
2636
|
const HUB_WRITE_OPS = /* @__PURE__ */ new Set([
|
|
2437
2637
|
"hub.apply",
|
|
2438
2638
|
"hub.retry",
|
|
2639
|
+
"hub.push",
|
|
2640
|
+
"hub.skillPublish",
|
|
2641
|
+
"hub.skillPull",
|
|
2439
2642
|
"hub.check",
|
|
2440
2643
|
"hub.applyAll"
|
|
2441
2644
|
]);
|
|
@@ -2443,6 +2646,9 @@ function hubWriteDeadlineMs(op) {
|
|
|
2443
2646
|
switch (op) {
|
|
2444
2647
|
case "hub.apply":
|
|
2445
2648
|
case "hub.retry":
|
|
2649
|
+
case "hub.push":
|
|
2650
|
+
case "hub.skillPublish":
|
|
2651
|
+
case "hub.skillPull":
|
|
2446
2652
|
return HUB_ITEM_WRITE_DEADLINE_MS;
|
|
2447
2653
|
case "hub.check":
|
|
2448
2654
|
return HUB_CHECK_DEADLINE_MS;
|
|
@@ -2475,6 +2681,7 @@ const READ_ONLY_OPS = /* @__PURE__ */ new Set([
|
|
|
2475
2681
|
"config.get",
|
|
2476
2682
|
"credentials.list",
|
|
2477
2683
|
"hub.updates",
|
|
2684
|
+
"hub.links",
|
|
2478
2685
|
"info.get",
|
|
2479
2686
|
"instructions.get",
|
|
2480
2687
|
"legacy.agent.get",
|
|
@@ -2511,6 +2718,7 @@ const READ_ONLY_OPS = /* @__PURE__ */ new Set([
|
|
|
2511
2718
|
"sessions.find",
|
|
2512
2719
|
"sessions.get",
|
|
2513
2720
|
"sessions.history",
|
|
2721
|
+
"sessions.files",
|
|
2514
2722
|
"sessions.list",
|
|
2515
2723
|
"sessions.preview",
|
|
2516
2724
|
"sessions.report",
|
|
@@ -2617,6 +2825,14 @@ function wakeTiming(request) {
|
|
|
2617
2825
|
...request.limit !== void 0 ? { limit: request.limit } : {}
|
|
2618
2826
|
};
|
|
2619
2827
|
}
|
|
2828
|
+
function publicationPolicyBody(request) {
|
|
2829
|
+
return {
|
|
2830
|
+
...request.requestId ? { request_id: request.requestId } : {},
|
|
2831
|
+
...request.subscribe !== void 0 ? { subscribe: request.subscribe } : {},
|
|
2832
|
+
...request.autoPush !== void 0 ? { auto_push: request.autoPush } : {},
|
|
2833
|
+
...request.confirmPublicEgress !== void 0 ? { confirm_public_egress: request.confirmPublicEgress } : {}
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2620
2836
|
function assertPairedPublicationTarget(request) {
|
|
2621
2837
|
if (Boolean(request.visibility === "org") !== Boolean(request.tenantId)) {
|
|
2622
2838
|
throw new Error(
|
|
@@ -2733,16 +2949,81 @@ function desktopEndpoint(request) {
|
|
|
2733
2949
|
return {
|
|
2734
2950
|
path: `/v1/desktop/profiles/${encodeURIComponent(request.name)}`,
|
|
2735
2951
|
method: "PATCH",
|
|
2736
|
-
body: {
|
|
2952
|
+
body: {
|
|
2953
|
+
request_id: request.requestId,
|
|
2954
|
+
...request.fields,
|
|
2955
|
+
/*
|
|
2956
|
+
* The opaque echo travels ALONGSIDE the fields, never inside them: the
|
|
2957
|
+
* edit body is `exclude_unset`-merged on the backend, so a revision
|
|
2958
|
+
* nested in `fields` could be mistaken for an editable property. Sent
|
|
2959
|
+
* only when present, so absence stays the legacy unconditional write.
|
|
2960
|
+
*/
|
|
2961
|
+
...request.expectedDefinitionRevision !== void 0 && request.expectedDefinitionRevision !== null ? {
|
|
2962
|
+
expected_definition_revision: request.expectedDefinitionRevision
|
|
2963
|
+
} : {}
|
|
2964
|
+
}
|
|
2737
2965
|
};
|
|
2738
2966
|
case "hub.updates":
|
|
2739
2967
|
return { path: "/v1/desktop/hub/updates", method: "GET" };
|
|
2968
|
+
case "hub.skillPull":
|
|
2969
|
+
return {
|
|
2970
|
+
path: "/v1/desktop/hub/skills/pull",
|
|
2971
|
+
method: "POST",
|
|
2972
|
+
body: {
|
|
2973
|
+
request_id: request.requestId,
|
|
2974
|
+
hub_id: request.hubId,
|
|
2975
|
+
hub_source: request.hubSource,
|
|
2976
|
+
visibility: request.visibility,
|
|
2977
|
+
tenant_id: request.tenantId,
|
|
2978
|
+
local_alias: request.localAlias,
|
|
2979
|
+
...request.subscribe !== void 0 ? { subscribe: request.subscribe } : {},
|
|
2980
|
+
...request.autoPush !== void 0 ? { auto_push: request.autoPush } : {},
|
|
2981
|
+
...request.confirmPublicEgress !== void 0 ? { confirm_public_egress: request.confirmPublicEgress } : {}
|
|
2982
|
+
}
|
|
2983
|
+
};
|
|
2984
|
+
case "hub.skillPublish":
|
|
2985
|
+
return {
|
|
2986
|
+
path: "/v1/desktop/hub/skills/publish",
|
|
2987
|
+
method: "POST",
|
|
2988
|
+
body: {
|
|
2989
|
+
request_id: request.requestId,
|
|
2990
|
+
dry_run: request.dryRun,
|
|
2991
|
+
source_skill: request.sourceSkill,
|
|
2992
|
+
local_alias: request.localAlias,
|
|
2993
|
+
visibility: request.visibility,
|
|
2994
|
+
tenant_id: request.tenantId,
|
|
2995
|
+
subscribe: request.subscribe,
|
|
2996
|
+
auto_push: request.autoPush,
|
|
2997
|
+
confirm_public_egress: request.confirmPublicEgress,
|
|
2998
|
+
...request.previewReceipt ? { preview_receipt: request.previewReceipt } : {},
|
|
2999
|
+
...request.confirmPublish ? { confirm_publish: true } : {}
|
|
3000
|
+
}
|
|
3001
|
+
};
|
|
3002
|
+
case "hub.links":
|
|
3003
|
+
return {
|
|
3004
|
+
path: `/v1/desktop/hub/links${request.kind ? `?kind=${request.kind}` : ""}`,
|
|
3005
|
+
method: "GET"
|
|
3006
|
+
};
|
|
3007
|
+
case "hub.policy":
|
|
3008
|
+
return {
|
|
3009
|
+
path: `/v1/desktop/hub/links/${encodeURIComponent(request.linkId)}`,
|
|
3010
|
+
method: "PATCH",
|
|
3011
|
+
body: {
|
|
3012
|
+
request_id: request.requestId,
|
|
3013
|
+
expected_policy_revision: request.expectedPolicyRevision,
|
|
3014
|
+
...request.subscribe !== void 0 ? { subscribe: request.subscribe } : {},
|
|
3015
|
+
...request.autoPush !== void 0 ? { auto_push: request.autoPush } : {},
|
|
3016
|
+
...request.confirmPublicEgress !== void 0 ? { confirm_public_egress: request.confirmPublicEgress } : {}
|
|
3017
|
+
}
|
|
3018
|
+
};
|
|
2740
3019
|
case "hub.check":
|
|
2741
3020
|
return {
|
|
2742
3021
|
path: "/v1/desktop/hub/updates/check",
|
|
2743
3022
|
method: "POST",
|
|
2744
3023
|
body: {
|
|
2745
3024
|
request_id: request.requestId,
|
|
3025
|
+
...request.linkId ? { link_id: request.linkId } : {},
|
|
3026
|
+
...request.direction ? { direction: request.direction } : {},
|
|
2746
3027
|
...request.kind ? { kind: request.kind } : {},
|
|
2747
3028
|
...request.name ? { name: request.name } : {}
|
|
2748
3029
|
}
|
|
@@ -2753,13 +3034,30 @@ function desktopEndpoint(request) {
|
|
|
2753
3034
|
method: "POST",
|
|
2754
3035
|
body: {
|
|
2755
3036
|
request_id: request.requestId,
|
|
2756
|
-
|
|
2757
|
-
|
|
3037
|
+
...request.previewReceipt ? { preview_receipt: request.previewReceipt } : {},
|
|
3038
|
+
...request.confirmApply ? { confirm_apply: true } : {},
|
|
3039
|
+
...request.linkId ? { link_id: request.linkId } : {},
|
|
3040
|
+
...request.direction ? { direction: request.direction } : {},
|
|
3041
|
+
...request.kind ? { kind: request.kind } : {},
|
|
3042
|
+
...request.name ? { name: request.name } : {},
|
|
2758
3043
|
...request.prefer ? { prefer: request.prefer } : {},
|
|
2759
3044
|
...request.acknowledgeUnknownBaseline !== void 0 ? {
|
|
2760
3045
|
acknowledge_unknown_baseline: request.acknowledgeUnknownBaseline
|
|
2761
3046
|
} : {},
|
|
2762
|
-
...request.dryRun !== void 0 ? { dry_run: request.dryRun } : {}
|
|
3047
|
+
...request.dryRun !== void 0 ? { dry_run: request.dryRun } : {},
|
|
3048
|
+
/*
|
|
3049
|
+
* The source-confirmation branch travels on the SAME apply route with an
|
|
3050
|
+
* explicit flag, never a new endpoint. `resolve_source:true` plus the
|
|
3051
|
+
* stated scope triple is the whole act; the service materializes the
|
|
3052
|
+
* real identity/link and preserves any known scope (refusing a conflict
|
|
3053
|
+
* with `origin-conflict`), so nothing here infers Public or an org.
|
|
3054
|
+
*/
|
|
3055
|
+
...request.resolveSource === true ? {
|
|
3056
|
+
resolve_source: true,
|
|
3057
|
+
hub_source: request.hubSource,
|
|
3058
|
+
visibility: request.visibility,
|
|
3059
|
+
tenant_id: request.tenantId ?? null
|
|
3060
|
+
} : {}
|
|
2763
3061
|
}
|
|
2764
3062
|
};
|
|
2765
3063
|
case "hub.applyAll":
|
|
@@ -2777,8 +3075,23 @@ function desktopEndpoint(request) {
|
|
|
2777
3075
|
method: "POST",
|
|
2778
3076
|
body: {
|
|
2779
3077
|
request_id: request.requestId,
|
|
2780
|
-
|
|
2781
|
-
|
|
3078
|
+
...request.linkId ? { link_id: request.linkId } : {},
|
|
3079
|
+
...request.direction ? { direction: request.direction } : {},
|
|
3080
|
+
...request.kind ? { kind: request.kind } : {},
|
|
3081
|
+
...request.name ? { name: request.name } : {}
|
|
3082
|
+
}
|
|
3083
|
+
};
|
|
3084
|
+
case "hub.push":
|
|
3085
|
+
return {
|
|
3086
|
+
path: "/v1/desktop/hub/updates/push",
|
|
3087
|
+
method: "POST",
|
|
3088
|
+
body: {
|
|
3089
|
+
request_id: request.requestId,
|
|
3090
|
+
link_id: request.linkId,
|
|
3091
|
+
direction: request.direction,
|
|
3092
|
+
dry_run: request.dryRun,
|
|
3093
|
+
...request.previewReceipt ? { preview_receipt: request.previewReceipt } : {},
|
|
3094
|
+
...request.confirmPublish ? { confirm_publish: true } : {}
|
|
2782
3095
|
}
|
|
2783
3096
|
};
|
|
2784
3097
|
case "teams.list":
|
|
@@ -2798,7 +3111,14 @@ function desktopEndpoint(request) {
|
|
|
2798
3111
|
return {
|
|
2799
3112
|
path: `/v1/desktop/teams/${encodeURIComponent(request.name)}`,
|
|
2800
3113
|
method: "PATCH",
|
|
2801
|
-
body: {
|
|
3114
|
+
body: {
|
|
3115
|
+
request_id: request.requestId,
|
|
3116
|
+
...request.fields,
|
|
3117
|
+
/* Opaque echo beside the fields; absent/null = legacy unconditional. */
|
|
3118
|
+
...request.expectedDefinitionRevision !== void 0 && request.expectedDefinitionRevision !== null ? {
|
|
3119
|
+
expected_definition_revision: request.expectedDefinitionRevision
|
|
3120
|
+
} : {}
|
|
3121
|
+
}
|
|
2802
3122
|
};
|
|
2803
3123
|
case "sessions.list": {
|
|
2804
3124
|
const params = new URLSearchParams();
|
|
@@ -2927,6 +3247,31 @@ function desktopEndpoint(request) {
|
|
|
2927
3247
|
method: "GET"
|
|
2928
3248
|
};
|
|
2929
3249
|
}
|
|
3250
|
+
case "sessions.files": {
|
|
3251
|
+
const query = new URLSearchParams({
|
|
3252
|
+
limit: String(request.limit ?? 200)
|
|
3253
|
+
});
|
|
3254
|
+
for (const key of [
|
|
3255
|
+
"scope",
|
|
3256
|
+
"kind",
|
|
3257
|
+
"q",
|
|
3258
|
+
"sort",
|
|
3259
|
+
"order",
|
|
3260
|
+
"cursor"
|
|
3261
|
+
]) {
|
|
3262
|
+
const value = request[key];
|
|
3263
|
+
if (value !== void 0) query.set(key, value);
|
|
3264
|
+
}
|
|
3265
|
+
return {
|
|
3266
|
+
path: `/v1/desktop/sessions/${encodeURIComponent(request.sessionId)}/files?${query}`,
|
|
3267
|
+
method: "GET"
|
|
3268
|
+
};
|
|
3269
|
+
}
|
|
3270
|
+
case "sessions.files.materialise":
|
|
3271
|
+
return {
|
|
3272
|
+
path: `/v1/desktop/sessions/${encodeURIComponent(request.sessionId)}/files/${encodeURIComponent(request.fileId)}/materialise`,
|
|
3273
|
+
method: "POST"
|
|
3274
|
+
};
|
|
2930
3275
|
case "sessions.history": {
|
|
2931
3276
|
const query = new URLSearchParams({
|
|
2932
3277
|
limit: String(request.limit ?? 100)
|
|
@@ -3241,7 +3586,10 @@ function desktopEndpoint(request) {
|
|
|
3241
3586
|
// there is no override, because the route's input model forbids extras
|
|
3242
3587
|
// and still wants a JSON OBJECT — an omitted body makes a legal call
|
|
3243
3588
|
// answer 422.
|
|
3244
|
-
body: {
|
|
3589
|
+
body: {
|
|
3590
|
+
document: request.document ?? {},
|
|
3591
|
+
...publicationPolicyBody(request)
|
|
3592
|
+
}
|
|
3245
3593
|
};
|
|
3246
3594
|
}
|
|
3247
3595
|
case "agent.republish": {
|
|
@@ -3257,10 +3605,25 @@ function desktopEndpoint(request) {
|
|
|
3257
3605
|
method: "PUT",
|
|
3258
3606
|
body: {
|
|
3259
3607
|
hub_agent_id: request.hubAgentId,
|
|
3260
|
-
document: request.document ?? {}
|
|
3608
|
+
document: request.document ?? {},
|
|
3609
|
+
...publicationPolicyBody(request),
|
|
3610
|
+
...request.expectedRemoteRevision ? { expected_remote_revision: request.expectedRemoteRevision } : {}
|
|
3261
3611
|
}
|
|
3262
3612
|
};
|
|
3263
3613
|
}
|
|
3614
|
+
case "team.publish": {
|
|
3615
|
+
assertPairedPublicationTarget(request);
|
|
3616
|
+
const query = new URLSearchParams();
|
|
3617
|
+
if (request.visibility === "org" && request.tenantId) {
|
|
3618
|
+
query.set("visibility", "org");
|
|
3619
|
+
query.set("tenant_id", request.tenantId);
|
|
3620
|
+
}
|
|
3621
|
+
return {
|
|
3622
|
+
path: `/v1/teams/${request.teamId}/publish${query.size ? `?${query}` : ""}`,
|
|
3623
|
+
method: "POST",
|
|
3624
|
+
body: publicationPolicyBody(request)
|
|
3625
|
+
};
|
|
3626
|
+
}
|
|
3264
3627
|
case "team.pull": {
|
|
3265
3628
|
const query = new URLSearchParams();
|
|
3266
3629
|
if (request.tenantId) query.set("tenant_id", request.tenantId);
|
|
@@ -13252,6 +13615,11 @@ function describeWindowLaunch(plan, platform = process.platform) {
|
|
|
13252
13615
|
const suffix = extras.length === 0 ? "" : `, ${extras.join(", ")}`;
|
|
13253
13616
|
return `window mode ${plan.mode}: ${plan.width}x${plan.height}, ${behaviour}, page throttling ${plan.backgroundThrottling ? "on" : "off"}${suffix}${assumption}`;
|
|
13254
13617
|
}
|
|
13618
|
+
function focusBrowserChordTarget(window, target2, show) {
|
|
13619
|
+
if (show !== "focus" || window.isDestroyed() || !window.isFocused() || target2.isDestroyed())
|
|
13620
|
+
return;
|
|
13621
|
+
target2.focus();
|
|
13622
|
+
}
|
|
13255
13623
|
const MODE_OF_SHOW = {
|
|
13256
13624
|
focus: "normal",
|
|
13257
13625
|
inactive: "inactive",
|
|
@@ -14766,6 +15134,38 @@ ${result.stdout}`,
|
|
|
14766
15134
|
});
|
|
14767
15135
|
}
|
|
14768
15136
|
}
|
|
15137
|
+
const DIGIT_KEY$1 = /^[1-9]$/;
|
|
15138
|
+
const DIGIT_CODE = /^Digit([1-9])$/;
|
|
15139
|
+
function browserChordIntent(input, platform) {
|
|
15140
|
+
if (input.type !== "keyDown" || input.alt || input.isComposing) return null;
|
|
15141
|
+
const key = input.key.toLowerCase();
|
|
15142
|
+
let intent = null;
|
|
15143
|
+
if (key === "tab" && input.control && !input.meta) {
|
|
15144
|
+
intent = input.shift ? "prev-tab" : "next-tab";
|
|
15145
|
+
} else {
|
|
15146
|
+
const primary = platform === "darwin" ? input.meta && !input.control : input.control && !input.meta;
|
|
15147
|
+
if (!primary) return null;
|
|
15148
|
+
if (key === "+" || key === "=") intent = "zoom-in";
|
|
15149
|
+
else if (key === "-" && !input.shift) intent = "zoom-out";
|
|
15150
|
+
else if (key === "0" && !input.shift) intent = "zoom-reset";
|
|
15151
|
+
else if (platform === "darwin" && input.shift && ["[", "]", "{", "}"].includes(key)) {
|
|
15152
|
+
intent = key === "[" || key === "{" ? "prev-tab" : "next-tab";
|
|
15153
|
+
} else if (key === "r") intent = input.shift ? "hard-reload" : "reload";
|
|
15154
|
+
else if (key === "t") intent = input.shift ? "reopen-tab" : "new-tab";
|
|
15155
|
+
else if (!input.shift) {
|
|
15156
|
+
if (key === "f") intent = "find-page";
|
|
15157
|
+
else if (key === "l") intent = "focus-address";
|
|
15158
|
+
else if (key === "w") intent = "close-tab";
|
|
15159
|
+
else if (key === "[") intent = "back";
|
|
15160
|
+
else if (key === "]") intent = "forward";
|
|
15161
|
+
else {
|
|
15162
|
+
const digit = DIGIT_KEY$1.test(key) ? key : DIGIT_CODE.exec(input.code ?? "")?.[1];
|
|
15163
|
+
if (digit) intent = `tab-${digit}`;
|
|
15164
|
+
}
|
|
15165
|
+
}
|
|
15166
|
+
}
|
|
15167
|
+
return input.isAutoRepeat && intent !== "next-tab" && intent !== "prev-tab" ? null : intent;
|
|
15168
|
+
}
|
|
14769
15169
|
const CONSOLE_METHODS = [
|
|
14770
15170
|
"console_list",
|
|
14771
15171
|
"console_resources",
|
|
@@ -27844,6 +28244,53 @@ class ApprovalStore {
|
|
|
27844
28244
|
);
|
|
27845
28245
|
}
|
|
27846
28246
|
}
|
|
28247
|
+
function runBrowserMenuAction(intent, target2, owner, route) {
|
|
28248
|
+
if (!target2) return;
|
|
28249
|
+
if (target2 === owner && route(intent)) return;
|
|
28250
|
+
if (intent === "reload") target2.webContents?.reload();
|
|
28251
|
+
else if (intent === "hard-reload") target2.webContents?.reloadIgnoringCache();
|
|
28252
|
+
else target2.close();
|
|
28253
|
+
}
|
|
28254
|
+
function createBrowserChordRouter(options) {
|
|
28255
|
+
function dispatch(intent, origin) {
|
|
28256
|
+
if (intent === "reload" || intent === "hard-reload")
|
|
28257
|
+
options.reload(intent === "hard-reload");
|
|
28258
|
+
else if (intent === "back" || intent === "forward") options.history(intent);
|
|
28259
|
+
else if (intent.startsWith("zoom-") && options.zoom) {
|
|
28260
|
+
options.zoom(
|
|
28261
|
+
intent === "zoom-in" ? "in" : intent === "zoom-out" ? "out" : "reset"
|
|
28262
|
+
);
|
|
28263
|
+
} else {
|
|
28264
|
+
options.focusChrome();
|
|
28265
|
+
options.send({ intent, origin });
|
|
28266
|
+
}
|
|
28267
|
+
}
|
|
28268
|
+
return {
|
|
28269
|
+
input(event, input, origin, owns) {
|
|
28270
|
+
const intent = owns ? browserChordIntent(input, options.platform) : null;
|
|
28271
|
+
if (!intent) {
|
|
28272
|
+
const rejected = owns && input.type === "keyDown" && (input.isAutoRepeat || input.isComposing) && browserChordIntent(
|
|
28273
|
+
{ ...input, isAutoRepeat: false, isComposing: false },
|
|
28274
|
+
options.platform
|
|
28275
|
+
);
|
|
28276
|
+
if (rejected) {
|
|
28277
|
+
event.preventDefault();
|
|
28278
|
+
return true;
|
|
28279
|
+
}
|
|
28280
|
+
return false;
|
|
28281
|
+
}
|
|
28282
|
+
event.preventDefault();
|
|
28283
|
+
dispatch(intent, origin);
|
|
28284
|
+
return true;
|
|
28285
|
+
},
|
|
28286
|
+
menu(intent) {
|
|
28287
|
+
const page = options.ownsPage();
|
|
28288
|
+
if (!page && !options.ownsChrome()) return false;
|
|
28289
|
+
dispatch(intent, page ? "page" : "chrome");
|
|
28290
|
+
return true;
|
|
28291
|
+
}
|
|
28292
|
+
};
|
|
28293
|
+
}
|
|
27847
28294
|
const MAX_ENTRIES = 200;
|
|
27848
28295
|
const MAX_BYTES = 256 * 1024;
|
|
27849
28296
|
const MAX_ARG_CHARS = 2e3;
|
|
@@ -30881,6 +31328,168 @@ function factOf(path2) {
|
|
|
30881
31328
|
sha256: ""
|
|
30882
31329
|
};
|
|
30883
31330
|
}
|
|
31331
|
+
const PAGE_ZOOM_STEPS = [
|
|
31332
|
+
0.25,
|
|
31333
|
+
0.33,
|
|
31334
|
+
0.5,
|
|
31335
|
+
0.67,
|
|
31336
|
+
0.75,
|
|
31337
|
+
0.8,
|
|
31338
|
+
0.9,
|
|
31339
|
+
1,
|
|
31340
|
+
1.1,
|
|
31341
|
+
1.25,
|
|
31342
|
+
1.5,
|
|
31343
|
+
1.75,
|
|
31344
|
+
2,
|
|
31345
|
+
2.5,
|
|
31346
|
+
3,
|
|
31347
|
+
4,
|
|
31348
|
+
5
|
|
31349
|
+
];
|
|
31350
|
+
class PageControls {
|
|
31351
|
+
constructor(changed, resultTimeoutMs = 5e3) {
|
|
31352
|
+
this.changed = changed;
|
|
31353
|
+
this.resultTimeoutMs = resultTimeoutMs;
|
|
31354
|
+
}
|
|
31355
|
+
find = null;
|
|
31356
|
+
record = null;
|
|
31357
|
+
epoch = -1;
|
|
31358
|
+
requestId = null;
|
|
31359
|
+
listener = null;
|
|
31360
|
+
notice = null;
|
|
31361
|
+
noticeTabId = null;
|
|
31362
|
+
timer = null;
|
|
31363
|
+
stopTimer() {
|
|
31364
|
+
if (this.timer) clearTimeout(this.timer);
|
|
31365
|
+
this.timer = null;
|
|
31366
|
+
}
|
|
31367
|
+
reconcile(active) {
|
|
31368
|
+
if (this.record && (active !== this.record || !active.presented || active.documentEpoch !== this.epoch || active.view.webContents.isDestroyed()))
|
|
31369
|
+
this.clear();
|
|
31370
|
+
}
|
|
31371
|
+
state(active) {
|
|
31372
|
+
this.reconcile(active);
|
|
31373
|
+
if (active?.tabId !== this.noticeTabId || !active?.presented)
|
|
31374
|
+
this.notice = null;
|
|
31375
|
+
return {
|
|
31376
|
+
find: this.find ? { ...this.find } : null,
|
|
31377
|
+
zoom: active?.view.webContents.getZoomFactor?.() ?? 1,
|
|
31378
|
+
zoomAllowed: active?.owner === "user" && !active.handedTo,
|
|
31379
|
+
notice: this.notice
|
|
31380
|
+
};
|
|
31381
|
+
}
|
|
31382
|
+
clear() {
|
|
31383
|
+
this.stopTimer();
|
|
31384
|
+
const old = this.record;
|
|
31385
|
+
const listener = this.listener;
|
|
31386
|
+
this.record = null;
|
|
31387
|
+
this.find = null;
|
|
31388
|
+
this.requestId = null;
|
|
31389
|
+
this.listener = null;
|
|
31390
|
+
if (old && listener)
|
|
31391
|
+
old.view.webContents.removeListener("found-in-page", listener);
|
|
31392
|
+
if (old && !old.view.webContents.isDestroyed())
|
|
31393
|
+
old.view.webContents.stopFindInPage?.("clearSelection");
|
|
31394
|
+
}
|
|
31395
|
+
open(active) {
|
|
31396
|
+
this.reconcile(active);
|
|
31397
|
+
if (!active.presented) return;
|
|
31398
|
+
if (this.record === active) return;
|
|
31399
|
+
this.clear();
|
|
31400
|
+
this.record = active;
|
|
31401
|
+
this.epoch = active.documentEpoch;
|
|
31402
|
+
this.find = {
|
|
31403
|
+
tabId: active.tabId,
|
|
31404
|
+
query: "",
|
|
31405
|
+
ordinal: 0,
|
|
31406
|
+
matches: 0,
|
|
31407
|
+
pending: false,
|
|
31408
|
+
unreported: false
|
|
31409
|
+
};
|
|
31410
|
+
this.listener = (_event, result) => {
|
|
31411
|
+
if (this.record !== active || !active.presented || active.documentEpoch !== this.epoch || result.requestId !== this.requestId || !this.find)
|
|
31412
|
+
return;
|
|
31413
|
+
if (result.finalUpdate !== false) this.stopTimer();
|
|
31414
|
+
this.find = {
|
|
31415
|
+
...this.find,
|
|
31416
|
+
unreported: false,
|
|
31417
|
+
ordinal: result.activeMatchOrdinal,
|
|
31418
|
+
matches: result.matches,
|
|
31419
|
+
pending: result.finalUpdate === false
|
|
31420
|
+
};
|
|
31421
|
+
this.changed();
|
|
31422
|
+
};
|
|
31423
|
+
active.view.webContents.on("found-in-page", this.listener);
|
|
31424
|
+
}
|
|
31425
|
+
search(active, query, forward, next) {
|
|
31426
|
+
this.open(active);
|
|
31427
|
+
if (!this.find || this.record !== active) return;
|
|
31428
|
+
this.stopTimer();
|
|
31429
|
+
const same = this.find.query === query;
|
|
31430
|
+
const continuing = same && next && this.requestId !== null && !this.find.unreported;
|
|
31431
|
+
this.requestId = null;
|
|
31432
|
+
this.find = {
|
|
31433
|
+
...this.find,
|
|
31434
|
+
query,
|
|
31435
|
+
pending: query.length > 0,
|
|
31436
|
+
unreported: false,
|
|
31437
|
+
...same ? {} : { ordinal: 0, matches: 0 }
|
|
31438
|
+
};
|
|
31439
|
+
if (!query) {
|
|
31440
|
+
active.view.webContents.stopFindInPage?.("clearSelection");
|
|
31441
|
+
return;
|
|
31442
|
+
}
|
|
31443
|
+
this.requestId = active.view.webContents.findInPage?.(query, {
|
|
31444
|
+
forward,
|
|
31445
|
+
// Electron's misleading name means NEW SESSION (44.3 native maps
|
|
31446
|
+
// it to options->new_session), not "advance". Initial/changed/retry
|
|
31447
|
+
// must be true; an existing query's next/previous must be false.
|
|
31448
|
+
findNext: !continuing
|
|
31449
|
+
}) ?? null;
|
|
31450
|
+
const request = this.requestId;
|
|
31451
|
+
this.timer = setTimeout(() => {
|
|
31452
|
+
this.timer = null;
|
|
31453
|
+
if (this.record !== active || !active.presented || active.documentEpoch !== this.epoch || this.requestId !== request || !this.find)
|
|
31454
|
+
return;
|
|
31455
|
+
this.requestId = null;
|
|
31456
|
+
if (active.view.webContents.isDestroyed()) {
|
|
31457
|
+
this.clear();
|
|
31458
|
+
this.changed();
|
|
31459
|
+
return;
|
|
31460
|
+
}
|
|
31461
|
+
active.view.webContents.stopFindInPage?.("clearSelection");
|
|
31462
|
+
this.find = {
|
|
31463
|
+
...this.find,
|
|
31464
|
+
pending: false,
|
|
31465
|
+
unreported: true,
|
|
31466
|
+
ordinal: 0,
|
|
31467
|
+
matches: 0
|
|
31468
|
+
};
|
|
31469
|
+
this.changed();
|
|
31470
|
+
}, this.resultTimeoutMs);
|
|
31471
|
+
this.timer.unref?.();
|
|
31472
|
+
}
|
|
31473
|
+
zoom(active, command) {
|
|
31474
|
+
if (active.owner !== "user" || active.handedTo) {
|
|
31475
|
+
this.notice = "Zoom is off for tabs an agent is driving";
|
|
31476
|
+
this.noticeTabId = active.tabId;
|
|
31477
|
+
return;
|
|
31478
|
+
}
|
|
31479
|
+
this.notice = null;
|
|
31480
|
+
const current = active.view.webContents.getZoomFactor?.() ?? 1;
|
|
31481
|
+
const factor = command === "reset" ? 1 : command === "in" ? PAGE_ZOOM_STEPS.find((step) => step > current + 1e-3) ?? 5 : [...PAGE_ZOOM_STEPS].reverse().find((step) => step < current - 1e-3) ?? 0.25;
|
|
31482
|
+
active.view.webContents.setZoomFactor?.(factor);
|
|
31483
|
+
}
|
|
31484
|
+
/** Call BEFORE a capability transfer. Isolated per-WebContents zoom means
|
|
31485
|
+
* resetting this tab cannot alter another tab at the same origin. */
|
|
31486
|
+
prepareAgent(record) {
|
|
31487
|
+
const changed = this.record === record || (record.view.webContents.getZoomFactor?.() ?? 1) !== 1;
|
|
31488
|
+
if (this.record === record) this.clear();
|
|
31489
|
+
record.view.webContents.setZoomFactor?.(1);
|
|
31490
|
+
if (changed) this.changed();
|
|
31491
|
+
}
|
|
31492
|
+
}
|
|
30884
31493
|
const DOCUMENT_SCOPED = /* @__PURE__ */ new Set([
|
|
30885
31494
|
"read",
|
|
30886
31495
|
// The structured reads (`styles`, `hit_test`, `ancestors`) describe the
|
|
@@ -30967,6 +31576,7 @@ function sessionRequesterOf(requester) {
|
|
|
30967
31576
|
}
|
|
30968
31577
|
class BrowserHost {
|
|
30969
31578
|
registry;
|
|
31579
|
+
pageControls;
|
|
30970
31580
|
cdp;
|
|
30971
31581
|
approvals;
|
|
30972
31582
|
ownership;
|
|
@@ -30991,6 +31601,7 @@ class BrowserHost {
|
|
|
30991
31601
|
hydration = Promise.resolve();
|
|
30992
31602
|
constructor(options) {
|
|
30993
31603
|
this.registry = options.registry;
|
|
31604
|
+
this.pageControls = new PageControls(() => this.onChanged());
|
|
30994
31605
|
this.cdp = options.cdp;
|
|
30995
31606
|
this.approvals = options.approvals;
|
|
30996
31607
|
this.ownership = options.ownership;
|
|
@@ -31014,6 +31625,10 @@ class BrowserHost {
|
|
|
31014
31625
|
return run();
|
|
31015
31626
|
}
|
|
31016
31627
|
async authorizedPerform(method, params, requestId2) {
|
|
31628
|
+
if (typeof params.tab === "string" && TAB_SCOPED.has(method)) {
|
|
31629
|
+
const record2 = this.registry.requireSurface(params.tab);
|
|
31630
|
+
this.pageControls.prepareAgent(record2);
|
|
31631
|
+
}
|
|
31017
31632
|
if (!DOCUMENT_SCOPED.has(method))
|
|
31018
31633
|
return this.perform(method, params, requestId2);
|
|
31019
31634
|
const token = String(params.tab ?? "");
|
|
@@ -31272,6 +31887,7 @@ class BrowserHost {
|
|
|
31272
31887
|
const active = activeRecord && !activeRecord.view.webContents.isDestroyed() ? activeRecord : null;
|
|
31273
31888
|
const navigation = active?.view.webContents.navigationHistory;
|
|
31274
31889
|
return {
|
|
31890
|
+
pageControls: this.pageControls.state(active),
|
|
31275
31891
|
tabs: this.registry.snapshot().map((entry) => ({
|
|
31276
31892
|
tabId: entry.tabId,
|
|
31277
31893
|
title: this.titleForChrome(entry.title) || "New tab",
|
|
@@ -31389,16 +32005,94 @@ class BrowserHost {
|
|
|
31389
32005
|
* one field.
|
|
31390
32006
|
*/
|
|
31391
32007
|
async newTab(sessionId2) {
|
|
32008
|
+
await this.createUserTab(sessionId2 ?? null);
|
|
32009
|
+
return this.chromeState();
|
|
32010
|
+
}
|
|
32011
|
+
/** `newTab`'s body, returning the record so `reopenClosed` can navigate the tab
|
|
32012
|
+
* it created rather than whichever tab is active by the time the await ends. */
|
|
32013
|
+
async createUserTab(sessionId2) {
|
|
31392
32014
|
const record = this.registry.create({
|
|
31393
32015
|
owner: "user",
|
|
31394
|
-
sessionId: sessionId2
|
|
32016
|
+
sessionId: sessionId2
|
|
31395
32017
|
});
|
|
31396
32018
|
await record.view.webContents.loadURL("about:blank");
|
|
31397
32019
|
await this.cdp.attach(record.view.webContents);
|
|
31398
32020
|
this.onChanged();
|
|
32021
|
+
return record;
|
|
32022
|
+
}
|
|
32023
|
+
/** Main owns this short-lived UI focus fact; it conveys no page capability. */
|
|
32024
|
+
chordFocus = false;
|
|
32025
|
+
onChordFocusChanged;
|
|
32026
|
+
/** An explicit tab id fences queued chrome intents: a switch between key
|
|
32027
|
+
* delivery and IPC must never search/zoom the newly active tab instead. */
|
|
32028
|
+
async controlPage(tabId, action, query = "", forward = true, next = false) {
|
|
32029
|
+
return this.registry.lane(tabId, async () => {
|
|
32030
|
+
const active = this.registry.activeTab;
|
|
32031
|
+
if (!active || active.tabId !== tabId || !active.presented || active.view.webContents.isDestroyed())
|
|
32032
|
+
throw new Error("The browser tab is no longer presented.");
|
|
32033
|
+
if (action === "open") this.pageControls.open(active);
|
|
32034
|
+
else if (action === "close") this.pageControls.clear();
|
|
32035
|
+
else if (action === "search")
|
|
32036
|
+
this.pageControls.search(active, query, forward, next);
|
|
32037
|
+
else this.pageControls.zoom(active, action);
|
|
32038
|
+
this.onChanged();
|
|
32039
|
+
return this.chromeState();
|
|
32040
|
+
});
|
|
32041
|
+
}
|
|
32042
|
+
setChordFocus(focused) {
|
|
32043
|
+
this.chordFocus = focused;
|
|
32044
|
+
this.onChordFocusChanged?.(focused);
|
|
32045
|
+
}
|
|
32046
|
+
/** Only user URLs survive a close, never a capability, page state or nonce.
|
|
32047
|
+
* Conversation attribution is retained only to find the appropriate scope. */
|
|
32048
|
+
closedUserTabs = [];
|
|
32049
|
+
rememberClosed(tabId) {
|
|
32050
|
+
const record = this.registry.get(tabId);
|
|
32051
|
+
if (!record || record.owner !== "user" || record.handedTo !== null) return;
|
|
32052
|
+
const url = record.view.webContents.getURL();
|
|
32053
|
+
try {
|
|
32054
|
+
if (!permittedScheme(new URL(url))) return;
|
|
32055
|
+
} catch {
|
|
32056
|
+
return;
|
|
32057
|
+
}
|
|
32058
|
+
this.closedUserTabs.push({ url, sessionId: record.homeSessionId });
|
|
32059
|
+
if (this.closedUserTabs.length > 10) this.closedUserTabs.shift();
|
|
32060
|
+
}
|
|
32061
|
+
clearChordState() {
|
|
32062
|
+
this.pageControls.clear();
|
|
32063
|
+
this.setChordFocus(false);
|
|
32064
|
+
this.closedUserTabs = [];
|
|
32065
|
+
}
|
|
32066
|
+
/**
|
|
32067
|
+
* Forget remembered closes. Called when the user clears browsing data or forgets
|
|
32068
|
+
* a site, because a closed tab's URL can carry a one-time token or name a page
|
|
32069
|
+
* the user just asked this app to erase: Cmd+Shift+T must not resurrect it
|
|
32070
|
+
* (review R3). `origin` filters to one site; omitted forgets every entry. Clearing
|
|
32071
|
+
* only cookies or only the cache leaves the stack alone: neither erases what the
|
|
32072
|
+
* user visited, and a logged-out reopen simply lands on the site's own login.
|
|
32073
|
+
*/
|
|
32074
|
+
forgetClosedTabs(origin) {
|
|
32075
|
+
this.closedUserTabs = origin ? this.closedUserTabs.filter((entry) => {
|
|
32076
|
+
try {
|
|
32077
|
+
return new URL(entry.url).origin !== origin;
|
|
32078
|
+
} catch {
|
|
32079
|
+
return false;
|
|
32080
|
+
}
|
|
32081
|
+
}) : [];
|
|
32082
|
+
}
|
|
32083
|
+
async reopenClosed(sessionId2) {
|
|
32084
|
+
const index = this.closedUserTabs.findLastIndex(
|
|
32085
|
+
(entry2) => sessionId2 === null || entry2.sessionId === sessionId2
|
|
32086
|
+
);
|
|
32087
|
+
if (index < 0) return this.chromeState();
|
|
32088
|
+
const [entry] = this.closedUserTabs.splice(index, 1);
|
|
32089
|
+
const record = await this.createUserTab(sessionId2 ?? entry.sessionId);
|
|
32090
|
+
await record.view.webContents.loadURL(entry.url);
|
|
32091
|
+
this.onChanged();
|
|
31399
32092
|
return this.chromeState();
|
|
31400
32093
|
}
|
|
31401
32094
|
closeTab(tabId) {
|
|
32095
|
+
this.rememberClosed(tabId);
|
|
31402
32096
|
this.dropReceipt(tabId);
|
|
31403
32097
|
this.loadFailures.delete(tabId);
|
|
31404
32098
|
this.registry.destroy(tabId);
|
|
@@ -31425,6 +32119,7 @@ class BrowserHost {
|
|
|
31425
32119
|
closeTabs(intent) {
|
|
31426
32120
|
const tabIds = intent.mode === "ids" ? intent.tabIds : this.registry.list().filter((record) => record.sessionId === intent.sessionId).map((record) => record.tabId);
|
|
31427
32121
|
for (const tabId of tabIds) {
|
|
32122
|
+
this.rememberClosed(tabId);
|
|
31428
32123
|
this.dropReceipt(tabId);
|
|
31429
32124
|
this.loadFailures.delete(tabId);
|
|
31430
32125
|
}
|
|
@@ -31689,8 +32384,10 @@ class BrowserHost {
|
|
|
31689
32384
|
this.onChanged();
|
|
31690
32385
|
return this.chromeState();
|
|
31691
32386
|
}
|
|
31692
|
-
reloadActive() {
|
|
31693
|
-
this.registry.activeTab?.view.webContents
|
|
32387
|
+
reloadActive(hard = false) {
|
|
32388
|
+
const contents = this.registry.activeTab?.view.webContents;
|
|
32389
|
+
if (hard && contents?.reloadIgnoringCache) contents.reloadIgnoringCache();
|
|
32390
|
+
else contents?.reload();
|
|
31694
32391
|
return this.chromeState();
|
|
31695
32392
|
}
|
|
31696
32393
|
stopActive() {
|
|
@@ -31721,6 +32418,8 @@ class BrowserHost {
|
|
|
31721
32418
|
* sees the nonce: it travels to the session through `tabs`, which is what keeps
|
|
31722
32419
|
* this the one authority transfer rather than an exposure (design 6.3, 11.7). */
|
|
31723
32420
|
handOver(tabId, sessionId2) {
|
|
32421
|
+
const record = this.registry.get(tabId);
|
|
32422
|
+
if (record) this.pageControls.prepareAgent(record);
|
|
31724
32423
|
this.dropReceipt(tabId);
|
|
31725
32424
|
this.registry.handOver(tabId, sessionId2);
|
|
31726
32425
|
this.onChanged();
|
|
@@ -31784,6 +32483,7 @@ class BrowserHost {
|
|
|
31784
32483
|
const origin = safeHttpUrl(rawOrigin).origin;
|
|
31785
32484
|
const removed = this.approvals.revokeOrigin(origin);
|
|
31786
32485
|
await this.forgetSiteData(origin);
|
|
32486
|
+
this.forgetClosedTabs(origin);
|
|
31787
32487
|
this.log(`[browser] forgot ${origin}: ${removed} approval(s) revoked`);
|
|
31788
32488
|
this.onChanged();
|
|
31789
32489
|
return { origin, removed, ...this.chromeState() };
|
|
@@ -32624,6 +33324,10 @@ async function startWithRetries(options) {
|
|
|
32624
33324
|
}
|
|
32625
33325
|
const BROWSER_IPC_CHANNELS = [
|
|
32626
33326
|
"browser-state",
|
|
33327
|
+
"browser-set-chord-focus",
|
|
33328
|
+
"browser-page-control",
|
|
33329
|
+
"browser-reopen-tab",
|
|
33330
|
+
"browser-focus-page",
|
|
32627
33331
|
"browser-new-tab",
|
|
32628
33332
|
"browser-close-tab",
|
|
32629
33333
|
"browser-close-tabs",
|
|
@@ -32713,7 +33417,43 @@ function registerBrowserIpc(options) {
|
|
|
32713
33417
|
}
|
|
32714
33418
|
return host.navigateActive(url.trim());
|
|
32715
33419
|
});
|
|
32716
|
-
electron.ipcMain.handle(
|
|
33420
|
+
electron.ipcMain.handle(
|
|
33421
|
+
"browser-page-control",
|
|
33422
|
+
(event, tabId, action, query, forward, next) => {
|
|
33423
|
+
const host = authorize(event);
|
|
33424
|
+
if (typeof action !== "string" || !["open", "close", "search", "in", "out", "reset"].includes(action))
|
|
33425
|
+
throw new Error("Invalid page control action.");
|
|
33426
|
+
if (typeof query !== "string" || query.length > 4096 || typeof forward !== "boolean" || typeof next !== "boolean")
|
|
33427
|
+
throw new Error("Invalid page search input.");
|
|
33428
|
+
return host.controlPage(
|
|
33429
|
+
numberOrThrow(tabId, "tabId"),
|
|
33430
|
+
action,
|
|
33431
|
+
query,
|
|
33432
|
+
forward,
|
|
33433
|
+
next
|
|
33434
|
+
);
|
|
33435
|
+
}
|
|
33436
|
+
);
|
|
33437
|
+
electron.ipcMain.handle("browser-set-chord-focus", (event, focused) => {
|
|
33438
|
+
const host = authorize(event);
|
|
33439
|
+
if (typeof focused !== "boolean")
|
|
33440
|
+
throw new Error("Browser focus must be a boolean.");
|
|
33441
|
+
host.setChordFocus(focused);
|
|
33442
|
+
});
|
|
33443
|
+
electron.ipcMain.handle(
|
|
33444
|
+
"browser-reopen-tab",
|
|
33445
|
+
(event, sessionId2) => authorize(event).reopenClosed(optionalConversationOrThrow(sessionId2))
|
|
33446
|
+
);
|
|
33447
|
+
electron.ipcMain.handle("browser-focus-page", (event) => {
|
|
33448
|
+
authorize(event);
|
|
33449
|
+
options.focusPage?.();
|
|
33450
|
+
});
|
|
33451
|
+
electron.ipcMain.handle("browser-reload", (event, hard) => {
|
|
33452
|
+
const host = authorize(event);
|
|
33453
|
+
if (hard !== void 0 && typeof hard !== "boolean")
|
|
33454
|
+
throw new Error("Hard reload must be a boolean.");
|
|
33455
|
+
return host.reloadActive(hard === true);
|
|
33456
|
+
});
|
|
32717
33457
|
electron.ipcMain.handle("browser-stop", (event) => authorize(event).stopActive());
|
|
32718
33458
|
electron.ipcMain.handle("browser-history", (event, direction) => {
|
|
32719
33459
|
const host = authorize(event);
|
|
@@ -32798,11 +33538,12 @@ function registerBrowserIpc(options) {
|
|
|
32798
33538
|
return host.forgetSite(origin.trim());
|
|
32799
33539
|
});
|
|
32800
33540
|
electron.ipcMain.handle("browser-clear-data", async (event, what) => {
|
|
32801
|
-
authorize(event);
|
|
33541
|
+
const host = authorize(event);
|
|
32802
33542
|
if (what !== "cookies" && what !== "cache" && what !== "everything") {
|
|
32803
33543
|
throw new Error("Unsupported clear-data request.");
|
|
32804
33544
|
}
|
|
32805
33545
|
await options.clearData(what);
|
|
33546
|
+
if (what === "everything") host.forgetClosedTabs();
|
|
32806
33547
|
options.log(`[browser] cleared browsing data: ${what}`);
|
|
32807
33548
|
return { cleared: what };
|
|
32808
33549
|
});
|
|
@@ -34595,6 +35336,22 @@ function refusesNavigation(rawUrl) {
|
|
|
34595
35336
|
}
|
|
34596
35337
|
}
|
|
34597
35338
|
let activeHost = null;
|
|
35339
|
+
function routeBrowserZoomInput(event, input) {
|
|
35340
|
+
const candidate = browserChordIntent(
|
|
35341
|
+
{ ...input, isAutoRepeat: false, isComposing: false },
|
|
35342
|
+
process.platform
|
|
35343
|
+
);
|
|
35344
|
+
if (!candidate?.startsWith("zoom-") || !activeHost) return false;
|
|
35345
|
+
return activeHost.chords.input(
|
|
35346
|
+
event,
|
|
35347
|
+
input,
|
|
35348
|
+
"chrome",
|
|
35349
|
+
activeHost.host.chordFocus
|
|
35350
|
+
);
|
|
35351
|
+
}
|
|
35352
|
+
function routeBrowserMenu(intent) {
|
|
35353
|
+
return activeHost?.chords.menu(intent) ?? false;
|
|
35354
|
+
}
|
|
34598
35355
|
let stopping = null;
|
|
34599
35356
|
function browserHostStopPending() {
|
|
34600
35357
|
return activeHost !== null || stopping !== null || starting !== null;
|
|
@@ -34662,6 +35419,12 @@ function startBrowserHost(options) {
|
|
|
34662
35419
|
expectedUrl: options.expectedUrl,
|
|
34663
35420
|
host: () => bindings.host?.() ?? null,
|
|
34664
35421
|
webauthn: () => bindings.webauthn?.() ?? null,
|
|
35422
|
+
focusPage: () => {
|
|
35423
|
+
const record = bindings.host?.()?.registry.activeTab;
|
|
35424
|
+
const target2 = record?.presented ? electron.webContents.fromId(record.view.webContents.id) : null;
|
|
35425
|
+
if (target2)
|
|
35426
|
+
focusBrowserChordTarget(options.window, target2, options.windowShow);
|
|
35427
|
+
},
|
|
34665
35428
|
availability: () => availability,
|
|
34666
35429
|
clearData: async (what) => {
|
|
34667
35430
|
if (!bindings.clearData)
|
|
@@ -34741,6 +35504,8 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
34741
35504
|
// No `preload`: a driven page has no bridge to anything.
|
|
34742
35505
|
}
|
|
34743
35506
|
});
|
|
35507
|
+
view.webContents.setZoomMode("isolated");
|
|
35508
|
+
view.webContents.setZoomFactor(1);
|
|
34744
35509
|
window.contentView.addChildView(view);
|
|
34745
35510
|
view.setBounds(BACKGROUND_VIEWPORT);
|
|
34746
35511
|
view.setVisible(false);
|
|
@@ -34818,10 +35583,10 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
34818
35583
|
contents.on("will-navigate", onWillNavigate);
|
|
34819
35584
|
contents.on("will-redirect", onWillNavigate);
|
|
34820
35585
|
contents.on("before-input-event", (event, input) => {
|
|
34821
|
-
const
|
|
34822
|
-
|
|
34823
|
-
|
|
34824
|
-
|
|
35586
|
+
const record = registry.get(tabId);
|
|
35587
|
+
const owns = record === registry.activeTab && record?.presented === true;
|
|
35588
|
+
const handled = chords.input(event, input, "page", owns);
|
|
35589
|
+
contents.setIgnoreMenuShortcuts(handled);
|
|
34825
35590
|
});
|
|
34826
35591
|
const notifyChrome = () => {
|
|
34827
35592
|
options.window.webContents.send("browser-state-changed");
|
|
@@ -35125,6 +35890,75 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
35125
35890
|
facts: () => facts,
|
|
35126
35891
|
forgetSiteData: (origin) => clearOriginData(browserSession, origin)
|
|
35127
35892
|
});
|
|
35893
|
+
const chords = createBrowserChordRouter({
|
|
35894
|
+
platform: process.platform,
|
|
35895
|
+
ownsChrome: () => host.chordFocus,
|
|
35896
|
+
ownsPage: () => {
|
|
35897
|
+
const record = registry.activeTab;
|
|
35898
|
+
return Boolean(
|
|
35899
|
+
record?.presented && electron.webContents.getFocusedWebContents()?.id === record.view.webContents.id
|
|
35900
|
+
);
|
|
35901
|
+
},
|
|
35902
|
+
reload: (hard) => {
|
|
35903
|
+
host.reloadActive(hard);
|
|
35904
|
+
},
|
|
35905
|
+
zoom: (command) => {
|
|
35906
|
+
const tabId = registry.activeTab?.tabId;
|
|
35907
|
+
if (tabId !== void 0)
|
|
35908
|
+
void host.controlPage(tabId, command).catch(
|
|
35909
|
+
(error) => log2(
|
|
35910
|
+
`Page zoom refused: ${error instanceof Error ? error.message : "unavailable"}`
|
|
35911
|
+
)
|
|
35912
|
+
);
|
|
35913
|
+
},
|
|
35914
|
+
history: (direction) => {
|
|
35915
|
+
host.historyActive(direction);
|
|
35916
|
+
},
|
|
35917
|
+
send: (message) => options.window.webContents.send("browser-chord", message),
|
|
35918
|
+
focusChrome: () => focusBrowserChordTarget(
|
|
35919
|
+
options.window,
|
|
35920
|
+
options.window.webContents,
|
|
35921
|
+
options.windowShow
|
|
35922
|
+
)
|
|
35923
|
+
});
|
|
35924
|
+
const onChromeInput = (event, input) => {
|
|
35925
|
+
if (event.defaultPrevented) return;
|
|
35926
|
+
const handled = chords.input(event, input, "chrome", host.chordFocus);
|
|
35927
|
+
options.window.webContents.setIgnoreMenuShortcuts(handled);
|
|
35928
|
+
};
|
|
35929
|
+
const resetChordFocus = () => {
|
|
35930
|
+
host.setChordFocus(false);
|
|
35931
|
+
};
|
|
35932
|
+
host.onChordFocusChanged = (focused) => {
|
|
35933
|
+
if (!focused && !options.window.webContents.isDestroyed())
|
|
35934
|
+
options.window.webContents.setIgnoreMenuShortcuts(false);
|
|
35935
|
+
};
|
|
35936
|
+
options.window.webContents.on("before-input-event", onChromeInput);
|
|
35937
|
+
options.window.on("blur", resetChordFocus);
|
|
35938
|
+
options.window.on("closed", resetChordFocus);
|
|
35939
|
+
const resetOnNavigation = (details) => {
|
|
35940
|
+
if (details.isMainFrame && !details.isSameDocument) resetChordFocus();
|
|
35941
|
+
};
|
|
35942
|
+
options.window.webContents.on("did-start-navigation", resetOnNavigation);
|
|
35943
|
+
options.window.webContents.on("render-process-gone", resetChordFocus);
|
|
35944
|
+
const detachChords = () => {
|
|
35945
|
+
host.clearChordState();
|
|
35946
|
+
options.window.webContents.removeListener(
|
|
35947
|
+
"before-input-event",
|
|
35948
|
+
onChromeInput
|
|
35949
|
+
);
|
|
35950
|
+
options.window.removeListener("blur", resetChordFocus);
|
|
35951
|
+
options.window.removeListener("closed", resetChordFocus);
|
|
35952
|
+
options.window.webContents.removeListener(
|
|
35953
|
+
"did-start-navigation",
|
|
35954
|
+
resetOnNavigation
|
|
35955
|
+
);
|
|
35956
|
+
options.window.webContents.removeListener(
|
|
35957
|
+
"render-process-gone",
|
|
35958
|
+
resetChordFocus
|
|
35959
|
+
);
|
|
35960
|
+
};
|
|
35961
|
+
rollback.add(detachChords);
|
|
35128
35962
|
const recorded = readSession(sessionStore.filePath, log2);
|
|
35129
35963
|
host.restoreTabs(recorded);
|
|
35130
35964
|
if (recorded.length) {
|
|
@@ -35240,12 +36074,14 @@ async function initializeBrowserHost(options, bindings) {
|
|
|
35240
36074
|
`[browser] host on ${server.address}:${server.port} (proto ${facts.proto}), profile ${profileDir || "(in-memory)"}, agent tabs ${registry.agentTabCount()}/${8}, console ${consoleStartup.ok ? `on (${consoleStartup.counts().total} surface(s))` : `off (${consoleStartup.reason})`}`
|
|
35241
36075
|
);
|
|
35242
36076
|
const handle2 = {
|
|
36077
|
+
chords,
|
|
35243
36078
|
host,
|
|
35244
36079
|
port: server.port,
|
|
35245
36080
|
profileDir,
|
|
35246
36081
|
agentTabs: () => registry.agentTabCount(),
|
|
35247
36082
|
sessionCookies: () => restoreReport,
|
|
35248
36083
|
stop: async () => {
|
|
36084
|
+
detachChords();
|
|
35249
36085
|
const atStop = captureTabs(
|
|
35250
36086
|
registry.list(),
|
|
35251
36087
|
registry.activeTab?.tabId ?? null,
|
|
@@ -45492,25 +46328,6 @@ function configureAboutPanel() {
|
|
|
45492
46328
|
}
|
|
45493
46329
|
function createApplicationMenu() {
|
|
45494
46330
|
const isDev = Boolean(process.env.ELECTRON_RENDERER_URL);
|
|
45495
|
-
const zoomInHandler = () => {
|
|
45496
|
-
if (mainWindow) {
|
|
45497
|
-
const webContents2 = mainWindow.webContents;
|
|
45498
|
-
const currentZoom = webContents2.getZoomFactor();
|
|
45499
|
-
webContents2.setZoomFactor(currentZoom + 0.1);
|
|
45500
|
-
}
|
|
45501
|
-
};
|
|
45502
|
-
const zoomOutHandler = () => {
|
|
45503
|
-
if (mainWindow) {
|
|
45504
|
-
const webContents2 = mainWindow.webContents;
|
|
45505
|
-
const currentZoom = webContents2.getZoomFactor();
|
|
45506
|
-
webContents2.setZoomFactor(currentZoom - 0.1);
|
|
45507
|
-
}
|
|
45508
|
-
};
|
|
45509
|
-
const actualSizeHandler = () => {
|
|
45510
|
-
if (mainWindow) {
|
|
45511
|
-
mainWindow.webContents.setZoomFactor(1);
|
|
45512
|
-
}
|
|
45513
|
-
};
|
|
45514
46331
|
const template = [
|
|
45515
46332
|
{
|
|
45516
46333
|
label: "File",
|
|
@@ -45534,29 +46351,62 @@ function createApplicationMenu() {
|
|
|
45534
46351
|
label: "View",
|
|
45535
46352
|
submenu: [
|
|
45536
46353
|
{
|
|
45537
|
-
|
|
45538
|
-
|
|
46354
|
+
id: "app-reload",
|
|
46355
|
+
label: "Reload",
|
|
46356
|
+
accelerator: "CmdOrCtrl+R",
|
|
46357
|
+
click: (_item, target2) => runBrowserMenuAction(
|
|
46358
|
+
"reload",
|
|
46359
|
+
target2,
|
|
46360
|
+
mainWindow,
|
|
46361
|
+
routeBrowserMenu
|
|
46362
|
+
)
|
|
45539
46363
|
},
|
|
45540
46364
|
{
|
|
45541
|
-
|
|
45542
|
-
|
|
46365
|
+
id: "app-force-reload",
|
|
46366
|
+
label: "Force Reload",
|
|
46367
|
+
accelerator: "CmdOrCtrl+Shift+R",
|
|
46368
|
+
click: (_item, target2) => runBrowserMenuAction(
|
|
46369
|
+
"hard-reload",
|
|
46370
|
+
target2,
|
|
46371
|
+
mainWindow,
|
|
46372
|
+
routeBrowserMenu
|
|
46373
|
+
)
|
|
45543
46374
|
},
|
|
45544
46375
|
{ type: "separator" },
|
|
45545
46376
|
{
|
|
46377
|
+
id: "app-actual-size",
|
|
45546
46378
|
label: "Actual Size",
|
|
45547
|
-
accelerator: "CmdOrCtrl+
|
|
45548
|
-
click:
|
|
46379
|
+
accelerator: "CmdOrCtrl+0",
|
|
46380
|
+
click: (_item, target2) => {
|
|
46381
|
+
if (!(target2 instanceof electron.BrowserWindow)) return;
|
|
46382
|
+
if (target2 === mainWindow && routeBrowserMenu("zoom-reset")) return;
|
|
46383
|
+
target2.webContents.setZoomFactor(1);
|
|
46384
|
+
}
|
|
45549
46385
|
},
|
|
45550
46386
|
{
|
|
46387
|
+
id: "app-zoom-in",
|
|
45551
46388
|
label: "Zoom In",
|
|
45552
46389
|
accelerator: "CmdOrCtrl+Plus",
|
|
45553
46390
|
// On macOS, this often requires Shift as well (Cmd+Shift+=)
|
|
45554
|
-
click:
|
|
46391
|
+
click: (_item, target2) => {
|
|
46392
|
+
if (!(target2 instanceof electron.BrowserWindow)) return;
|
|
46393
|
+
if (target2 === mainWindow && routeBrowserMenu("zoom-in")) return;
|
|
46394
|
+
target2.webContents.setZoomFactor(
|
|
46395
|
+
target2.webContents.getZoomFactor() + 0.1
|
|
46396
|
+
);
|
|
46397
|
+
}
|
|
45555
46398
|
},
|
|
45556
46399
|
{
|
|
46400
|
+
id: "app-zoom-out",
|
|
45557
46401
|
label: "Zoom Out",
|
|
45558
46402
|
accelerator: "CmdOrCtrl+-",
|
|
45559
|
-
click:
|
|
46403
|
+
click: (_item, target2) => {
|
|
46404
|
+
if (!(target2 instanceof electron.BrowserWindow)) return;
|
|
46405
|
+
if (target2 === mainWindow && routeBrowserMenu("zoom-out")) return;
|
|
46406
|
+
target2.webContents.setZoomFactor(
|
|
46407
|
+
target2.webContents.getZoomFactor() - 0.1
|
|
46408
|
+
);
|
|
46409
|
+
}
|
|
45560
46410
|
},
|
|
45561
46411
|
{ type: "separator" },
|
|
45562
46412
|
{ role: "togglefullscreen" }
|
|
@@ -45582,10 +46432,40 @@ function createApplicationMenu() {
|
|
|
45582
46432
|
* `window-all-closed` path the red button takes, which is the one
|
|
45583
46433
|
* this change made safe for an install in flight.
|
|
45584
46434
|
*/
|
|
45585
|
-
{
|
|
46435
|
+
{
|
|
46436
|
+
id: "app-close",
|
|
46437
|
+
// One honest label for both owners: the SAME accelerator closes a
|
|
46438
|
+
// browser TAB while the browser has focus and the WINDOW elsewhere,
|
|
46439
|
+
// and a menu label cannot follow focus that lives in a page view
|
|
46440
|
+
// (UX r1 U4). The roles it replaced were "Close Window"/"Close".
|
|
46441
|
+
label: "Close Tab or Window",
|
|
46442
|
+
accelerator: "CmdOrCtrl+W",
|
|
46443
|
+
click: (_item, target2) => runBrowserMenuAction(
|
|
46444
|
+
"close-tab",
|
|
46445
|
+
target2,
|
|
46446
|
+
mainWindow,
|
|
46447
|
+
routeBrowserMenu
|
|
46448
|
+
)
|
|
46449
|
+
},
|
|
45586
46450
|
{ type: "separator" },
|
|
45587
46451
|
{ role: "window" }
|
|
45588
|
-
] : [
|
|
46452
|
+
] : [
|
|
46453
|
+
{
|
|
46454
|
+
id: "app-close",
|
|
46455
|
+
// One honest label for both owners: the SAME accelerator closes a
|
|
46456
|
+
// browser TAB while the browser has focus and the WINDOW elsewhere,
|
|
46457
|
+
// and a menu label cannot follow focus that lives in a page view
|
|
46458
|
+
// (UX r1 U4). The roles it replaced were "Close Window"/"Close".
|
|
46459
|
+
label: "Close Tab or Window",
|
|
46460
|
+
accelerator: "CmdOrCtrl+W",
|
|
46461
|
+
click: (_item, target2) => runBrowserMenuAction(
|
|
46462
|
+
"close-tab",
|
|
46463
|
+
target2,
|
|
46464
|
+
mainWindow,
|
|
46465
|
+
routeBrowserMenu
|
|
46466
|
+
)
|
|
46467
|
+
}
|
|
46468
|
+
]
|
|
45589
46469
|
]
|
|
45590
46470
|
},
|
|
45591
46471
|
{
|
|
@@ -46966,14 +47846,16 @@ electron.app.whenReady().then(async () => {
|
|
|
46966
47846
|
if (mainWindow) {
|
|
46967
47847
|
mainWindow.webContents.on("before-input-event", (event, input) => {
|
|
46968
47848
|
const isCmdOrCtrl = input.control || input.meta;
|
|
46969
|
-
if (
|
|
47849
|
+
if (event.defaultPrevented) return;
|
|
47850
|
+
if (routeBrowserZoomInput(event, input)) return;
|
|
47851
|
+
if (isCmdOrCtrl && input.type === "keyDown" && !input.alt && !input.isComposing) {
|
|
46970
47852
|
if (input.key === "+" || input.key === "=") {
|
|
46971
47853
|
zoomInFromEvent();
|
|
46972
47854
|
event.preventDefault();
|
|
46973
47855
|
} else if (input.key === "-") {
|
|
46974
47856
|
zoomOutFromEvent();
|
|
46975
47857
|
event.preventDefault();
|
|
46976
|
-
} else if (input.key === "
|
|
47858
|
+
} else if (input.key === "0") {
|
|
46977
47859
|
actualSizeFromEvent();
|
|
46978
47860
|
event.preventDefault();
|
|
46979
47861
|
}
|