@bivy/bivy 0.20.9-staging.9 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/README.md +1 -2
  2. package/dist/agent-instructions.js +14 -4
  3. package/dist/apps/remote-preview.js +7 -0
  4. package/dist/apps/service.js +6 -1
  5. package/dist/apps/styles.css +56 -70
  6. package/dist/automation-reseal.js +30 -0
  7. package/dist/config-cli.js +2 -0
  8. package/dist/controllers/credential-commands.js +3 -27
  9. package/dist/credentials/api.js +2 -43
  10. package/dist/credentials/document.js +6 -14
  11. package/dist/credentials/store.js +5 -6
  12. package/dist/device-registry.js +27 -0
  13. package/dist/harness/checkpoint.js +0 -0
  14. package/dist/node-config.js +4 -3
  15. package/dist/runtime/model-catalog.js +16 -0
  16. package/dist/runtime/tool-call-map.js +1 -1
  17. package/dist/runtime/tool-trace.js +1 -1
  18. package/dist/server.js +136 -244
  19. package/dist/session/event-log.js +136 -29
  20. package/dist/session/inline-image-fetch.js +24 -33
  21. package/dist/session/message-components.js +429 -0
  22. package/dist/session/run-terminal.js +9 -7
  23. package/dist/session/transcript-persistence.js +135 -10
  24. package/dist/work-instructions.js +50 -0
  25. package/package.json +2 -2
  26. package/web/assets/AutomationsView-HnUfeti_.js +51 -0
  27. package/web/assets/ChangesCard-Dnkguen5.js +4 -0
  28. package/web/assets/LibraryView-CSKKV8TI.js +2 -0
  29. package/web/assets/{ProviderConnect-BPwnaFGk.js → ProviderConnect-DNgxGmP9.js} +1 -1
  30. package/web/assets/SessionList-CYU9IGnd.js +1 -0
  31. package/web/assets/Settings-HQZtxiMV.js +10 -0
  32. package/web/assets/{Sheet-DOOJosQY.js → Sheet-DoPtOHBC.js} +1 -1
  33. package/web/assets/{StatusDot-dpbztK53.js → Spinner-CPdRfDcT.js} +1 -1
  34. package/web/assets/{Terminal-DVGXS6Yd.js → Terminal-DY6UB5U-.js} +1 -1
  35. package/web/assets/{VoiceSettings-DX-n0SFl.js → VoiceSettings-BoQ_Mhpm.js} +1 -1
  36. package/web/assets/{abnfDiagram-VCTEODGH-CnJ4astd.js → abnfDiagram-VCTEODGH-n-P11_L4.js} +1 -1
  37. package/web/assets/arc-BNLueWOY.js +1 -0
  38. package/web/assets/architecture-7GRP2DOG-DyG-wgaH.js +1 -0
  39. package/web/assets/{architectureDiagram-5GKGNRK7-B26-V_Xd.js → architectureDiagram-5GKGNRK7-C0b9IP5U.js} +1 -1
  40. package/web/assets/{blockDiagram-I7D4REHJ-DuoZkDHs.js → blockDiagram-I7D4REHJ-iVx1FQBD.js} +1 -1
  41. package/web/assets/{c4Diagram-7LVT6UL2-B81PZ-Vw.js → c4Diagram-7LVT6UL2-DIwEaAvJ.js} +1 -1
  42. package/web/assets/channel-HmCJmS4T.js +1 -0
  43. package/web/assets/{chunk-4HAMMTFA-DmSrqg9X.js → chunk-4HAMMTFA-DSsyukSz.js} +1 -1
  44. package/web/assets/chunk-75Z2AOVW-zwLYo-XL.js +2 -0
  45. package/web/assets/{chunk-DU6HZSFF-jMBIr1yK.js → chunk-DU6HZSFF-PGuLkqeP.js} +15 -15
  46. package/web/assets/chunk-F27PBJKO-CpkyeGC9.js +1 -0
  47. package/web/assets/{chunk-GMAD6QVW-C5YdBKWY.js → chunk-GMAD6QVW-CZSmK3Ms.js} +1 -1
  48. package/web/assets/{chunk-GVQU2GXP-DOOAmJLJ.js → chunk-GVQU2GXP-C2XMkY6v.js} +1 -1
  49. package/web/assets/{chunk-IMKFNOWR-CISXYXGE.js → chunk-IMKFNOWR-DAIVz3j5.js} +1 -1
  50. package/web/assets/{chunk-L3NEJ4N5-CvWtiEy-.js → chunk-L3NEJ4N5-C0geNTDK.js} +1 -1
  51. package/web/assets/{chunk-OSK3NFVY-yVAn5yky.js → chunk-OSK3NFVY-D-WN2fBr.js} +2 -2
  52. package/web/assets/{chunk-P2QGCYS3-D-VGoELb.js → chunk-P2QGCYS3-DYGhprKz.js} +1 -1
  53. package/web/assets/{chunk-POPQ4Y6H-0Mj4Bp-N.js → chunk-POPQ4Y6H-Dlsu2a2Q.js} +1 -1
  54. package/web/assets/{chunk-PWAF6VOD-Dvvdg6s1.js → chunk-PWAF6VOD-DK0QWYdc.js} +1 -1
  55. package/web/assets/{chunk-SHT3W25Y-DcllnbDq.js → chunk-SHT3W25Y-BpQHIdUi.js} +1 -1
  56. package/web/assets/{chunk-SVP7TREG-DnuOGeio.js → chunk-SVP7TREG-Cs5YWxpG.js} +1 -1
  57. package/web/assets/{chunk-TICWLB2K-Dr76NyiT.js → chunk-TICWLB2K-BRsWLPXA.js} +1 -1
  58. package/web/assets/chunk-XXDRQBXY-CjF14Z7v.js +1 -0
  59. package/web/assets/classDiagram-ZZMXUADV-BmdAoNdO.js +1 -0
  60. package/web/assets/classDiagram-v2-VYDZK3BY-BmdAoNdO.js +1 -0
  61. package/web/assets/colors-Cg5Vh3br.js +1 -0
  62. package/web/assets/{cose-bilkent-JH36ORCC-BIqBF2fY.js → cose-bilkent-JH36ORCC-CEUD3V3W.js} +1 -1
  63. package/web/assets/{cynefin-OW5HDTMX-DoAt_4E6.js → cynefin-OW5HDTMX-DoHWnu_-.js} +1 -1
  64. package/web/assets/cynefinDiagram-5FMLGOSQ-CgPeHmV5.js +62 -0
  65. package/web/assets/{dagre-GXQ25YYZ-DIAXxVMd.js → dagre-GXQ25YYZ-CrIlgwM7.js} +1 -1
  66. package/web/assets/{defaultLocale-BFoDCU3G.js → defaultLocale-CNPGWpMu.js} +1 -1
  67. package/web/assets/{diagram-S7CK7UJ4-DA78JGp6.js → diagram-S7CK7UJ4-BM_l51zV.js} +1 -1
  68. package/web/assets/diagram-UQ7AKVKN-CfkxqgPI.js +41 -0
  69. package/web/assets/{diagram-VSXAHHWV-DCkvR_pJ.js → diagram-VSXAHHWV-0y5vCI9g.js} +1 -1
  70. package/web/assets/diagram-VX7I27RA-BMkMy7jn.js +24 -0
  71. package/web/assets/diagram-Z3DM3KII--0fxfDqG.js +24 -0
  72. package/web/assets/dist-kYfyPZP9.js +1 -0
  73. package/web/assets/{ebnfDiagram-PWID7BFC-CSCD0PAi.js → ebnfDiagram-PWID7BFC-6tPNzbJl.js} +1 -1
  74. package/web/assets/embed-BXV41wg7.js +201 -0
  75. package/web/assets/{erDiagram-RLTQ6QDP-M512qtMu.js → erDiagram-RLTQ6QDP-Bjqm_o3R.js} +1 -1
  76. package/web/assets/eventmodeling-NTZA5JFV-CoCZxN1n.js +1 -0
  77. package/web/assets/flowDiagram-HODETNUW-CznfWzEq.js +1 -0
  78. package/web/assets/ganttDiagram-EL5Y4UJY-92X7KOOI.js +292 -0
  79. package/web/assets/{gitGraph-4MIJSDKK-CwjwFpZb.js → gitGraph-4MIJSDKK-B5F-u7Vq.js} +1 -1
  80. package/web/assets/gitGraphDiagram-WWUBYQGX-Ct2hVG0b.js +106 -0
  81. package/web/assets/index-BKSbod42.css +1 -0
  82. package/web/assets/{index-CNs5i7tU.js → index-CnjJQpgZ.js} +2 -2
  83. package/web/assets/{info-A6RAGUB7-D6nXu5V2.js → info-A6RAGUB7-D3xmYWyC.js} +1 -1
  84. package/web/assets/infoDiagram-27XIBGKW-lzqZ7xaA.js +2 -0
  85. package/web/assets/init-ZlXS9mIS.js +1 -0
  86. package/web/assets/{ishikawaDiagram-5VMMS53U-4bsiyG2x.js → ishikawaDiagram-5VMMS53U-CsVZHXR0.js} +1 -1
  87. package/web/assets/{journeyDiagram-3NMN7TZE-o3U3L2rt.js → journeyDiagram-3NMN7TZE-DN9AdyVy.js} +1 -1
  88. package/web/assets/{kanban-definition-UXKFOSKX-CQOPj0NZ.js → kanban-definition-UXKFOSKX-gvkBaOFe.js} +1 -1
  89. package/web/assets/linear-CeYXFQza.js +1 -0
  90. package/web/assets/{mermaid-parser.core-Ba2-DGvb.js → mermaid-parser.core-CPwOm7-a.js} +3 -3
  91. package/web/assets/{mermaid.core-BxdMVbm9.js → mermaid.core-F09Wr40d.js} +6 -6
  92. package/web/assets/{mindmap-definition-YA3MSWOX-1Eu4-zLM.js → mindmap-definition-YA3MSWOX-Qzc2J9Pm.js} +1 -1
  93. package/web/assets/mount-Bvl-yslT.js +36 -0
  94. package/web/assets/ordinal-BdBDtYTt.js +1 -0
  95. package/web/assets/{packet-AYTQ26CC-BTZ7CbVd.js → packet-AYTQ26CC-Unxh5mP2.js} +1 -1
  96. package/web/assets/{pegDiagram-XKGWAZYB-DNdK3axo.js → pegDiagram-XKGWAZYB-BIqcRp3m.js} +1 -1
  97. package/web/assets/{pie-WAS4IAKB-DidjfqgW.js → pie-WAS4IAKB-BipHZKbc.js} +1 -1
  98. package/web/assets/{pieDiagram-E7YTZNPT-Dme68TUA.js → pieDiagram-E7YTZNPT-gaTNuzPD.js} +2 -2
  99. package/web/assets/{quadrantDiagram-AXDQQJYC-z0xeSJSB.js → quadrantDiagram-AXDQQJYC-3BEmlbuE.js} +1 -1
  100. package/web/assets/{radar-RG4KPBEZ-BV50NO32.js → radar-RG4KPBEZ-Cm1_Q0XJ.js} +1 -1
  101. package/web/assets/{railroad-74A4TZTK-BOkd4wGS.js → railroad-74A4TZTK-CJ4K8tjT.js} +1 -1
  102. package/web/assets/railroad-abnf-HS5TGJTU-BVKI4cmM.js +1 -0
  103. package/web/assets/railroad-ebnf-LZEXJU2U-UMcDSelb.js +1 -0
  104. package/web/assets/railroad-peg-WCYAUIDC-C00zpjQU.js +1 -0
  105. package/web/assets/{railroadDiagram-O6MQD6OU-2eK1mPm_.js → railroadDiagram-O6MQD6OU-Nzyn7Xx6.js} +1 -1
  106. package/web/assets/range-EplFIxc7.js +1 -0
  107. package/web/assets/{requirementDiagram-BXWQKSXE-DvlVp433.js → requirementDiagram-BXWQKSXE-9zXuiai_.js} +1 -1
  108. package/web/assets/{sankeyDiagram-P5KCCOFB-C6CsEyCg.js → sankeyDiagram-P5KCCOFB-Cnw1rQun.js} +1 -1
  109. package/web/assets/{sequenceDiagram-WJ2MYXX4-1wwxxN6P.js → sequenceDiagram-WJ2MYXX4-BSLLRV-U.js} +3 -3
  110. package/web/assets/{settingsRoute-Dxrvnqih.js → settingsRoute-C2Up46o6.js} +1 -1
  111. package/web/assets/src-CFHfg5gg.js +1 -0
  112. package/web/assets/stateDiagram-D77RDMKH-D07b4cJB.js +1 -0
  113. package/web/assets/stateDiagram-v2-MP3YSRHH-DaG9Yzhk.js +1 -0
  114. package/web/assets/step-BDqHAzds.js +1 -0
  115. package/web/assets/{swimlanes-42K2YHIH-XLThGmTf.js → swimlanes-42K2YHIH-RpDl0CG9.js} +1 -1
  116. package/web/assets/swimlanesDiagram-VR7AAH4N-7003ldWX.js +8 -0
  117. package/web/assets/time-Dzw-YSCF.js +1 -0
  118. package/web/assets/{timeline-definition-24CTP7MA-BEOV0lDT.js → timeline-definition-24CTP7MA-BgQOP12r.js} +1 -1
  119. package/web/assets/{treeView-Q6P3EWNA-Dm4FCZVW.js → treeView-Q6P3EWNA-BiSBsrlo.js} +1 -1
  120. package/web/assets/treemap-BfjIY-m6.js +1 -0
  121. package/web/assets/{treemap-WGGIJYW6-DEZGmkE8.js → treemap-WGGIJYW6-CNdjKqUG.js} +1 -1
  122. package/web/assets/useStore-CxjHbFPA.js +16 -0
  123. package/web/assets/{vennDiagram-4TSXK5OY-CDRUEJ_c.js → vennDiagram-4TSXK5OY-DLzOr3Yv.js} +1 -1
  124. package/web/assets/{wardley-WFR3VGLG-CjZ5JazT.js → wardley-WFR3VGLG-LCC8FWVb.js} +1 -1
  125. package/web/assets/{wardleyDiagram-VM6X3IG4-COsxLnU6.js → wardleyDiagram-VM6X3IG4-WrwzM3YW.js} +1 -1
  126. package/web/assets/{xychartDiagram-S5SC5T6Z-BfwzNIP-.js → xychartDiagram-S5SC5T6Z-B_HuoAnl.js} +3 -3
  127. package/web/index.html +2 -2
  128. package/web/sw.js +1 -1
  129. package/dist/ephemeral-exec.js +0 -108
  130. package/dist/hosted-custody.js +0 -30
  131. package/web/assets/AutomationsView-Dk1aHviY.js +0 -51
  132. package/web/assets/ChangesCard-Bn37dRew.js +0 -4
  133. package/web/assets/LibraryView-CGkpNOgR.js +0 -2
  134. package/web/assets/Settings-DJjEVwmu.js +0 -10
  135. package/web/assets/arc-Pry-7G1_.js +0 -1
  136. package/web/assets/architecture-7GRP2DOG-kbFZ_7eU.js +0 -1
  137. package/web/assets/array-BifhSqXX.js +0 -1
  138. package/web/assets/channel-CpJ3OYta.js +0 -1
  139. package/web/assets/chunk-75Z2AOVW-CGlA2AB-.js +0 -2
  140. package/web/assets/chunk-F27PBJKO-Cto7X88Z.js +0 -1
  141. package/web/assets/chunk-XXDRQBXY-DqAYeljN.js +0 -1
  142. package/web/assets/classDiagram-ZZMXUADV-BSqiC-6r.js +0 -1
  143. package/web/assets/classDiagram-v2-VYDZK3BY-BSqiC-6r.js +0 -1
  144. package/web/assets/cynefinDiagram-5FMLGOSQ-B2jZZ_es.js +0 -62
  145. package/web/assets/diagram-UQ7AKVKN-D7BIW4QU.js +0 -41
  146. package/web/assets/diagram-VX7I27RA-qmkf9rFQ.js +0 -24
  147. package/web/assets/diagram-Z3DM3KII-BZf2h-T8.js +0 -24
  148. package/web/assets/dist-v5Q1xZ2K.js +0 -1
  149. package/web/assets/eventmodeling-NTZA5JFV-DHYpZdDY.js +0 -1
  150. package/web/assets/flowDiagram-HODETNUW-BdNS-1c7.js +0 -1
  151. package/web/assets/ganttDiagram-EL5Y4UJY-DGMQzJ8U.js +0 -292
  152. package/web/assets/gitGraphDiagram-WWUBYQGX-DNfbdhPa.js +0 -106
  153. package/web/assets/index-kWXUrhG8.css +0 -1
  154. package/web/assets/infoDiagram-27XIBGKW-QcpEFiaQ.js +0 -2
  155. package/web/assets/init-C-OQMol4.js +0 -1
  156. package/web/assets/line-Cq9nN3X2.js +0 -1
  157. package/web/assets/linear-SzVmGSw4.js +0 -1
  158. package/web/assets/mount-C9EzYXqA.js +0 -31
  159. package/web/assets/ordinal-BDEzSJ7C.js +0 -1
  160. package/web/assets/path-fybaL0A-.js +0 -1
  161. package/web/assets/railroad-abnf-HS5TGJTU-DiQLjR_J.js +0 -1
  162. package/web/assets/railroad-ebnf-LZEXJU2U-D4bSTzXb.js +0 -1
  163. package/web/assets/railroad-peg-WCYAUIDC-DDhl4AMh.js +0 -1
  164. package/web/assets/src-B6xuSHsQ.js +0 -1
  165. package/web/assets/stateDiagram-D77RDMKH-_fkXrLZe.js +0 -1
  166. package/web/assets/stateDiagram-v2-MP3YSRHH-Cuo-j5c1.js +0 -1
  167. package/web/assets/swimlanesDiagram-VR7AAH4N-DOpCt5KW.js +0 -8
  168. package/web/assets/useStore-C1E8iwAQ.js +0 -29
@@ -1,108 +0,0 @@
1
- // SPDX-License-Identifier: AGPL-3.0-only
2
- // Copyright (c) 2026 Petter André Sjulstad
3
- // Ephemeral provisioning proxy (node-broker path).
4
- //
5
- // A remote device that holds the user's cloud token asks this node to make ONE
6
- // allowlisted HTTPS request to a provider (Fly/Hetzner/AWS/...) on its behalf —
7
- // the browser can't call those APIs directly (no CORS). The token/credentials
8
- // ride in the request headers and are used transiently; nothing is persisted
9
- // here, so the provisioning stays end-to-end (the control plane never sees
10
- // it). The host allowlist is the SSRF guard and must be kept in lock-step with
11
- // the two other copies: `ALLOWED_HOSTS` in packages/core/src/ephemeral.ts
12
- // (the browser-side adapter) and the control-plane's cold-start relay in
13
- // services/control-plane/src/index.ts.
14
- export const EPHEMERAL_ALLOWED_HOSTS = new Set([
15
- "api.hetzner.cloud",
16
- "api.machines.dev",
17
- "api.fly.io",
18
- "ec2.us-east-1.amazonaws.com",
19
- "ec2.us-west-2.amazonaws.com",
20
- "ec2.eu-west-1.amazonaws.com",
21
- "ec2.eu-central-1.amazonaws.com",
22
- "ec2.ap-southeast-1.amazonaws.com",
23
- "ec2.ap-northeast-1.amazonaws.com",
24
- "ssm.us-east-1.amazonaws.com",
25
- "ssm.us-west-2.amazonaws.com",
26
- "ssm.eu-west-1.amazonaws.com",
27
- "ssm.eu-central-1.amazonaws.com",
28
- "ssm.ap-southeast-1.amazonaws.com",
29
- "ssm.ap-northeast-1.amazonaws.com",
30
- ]);
31
- /** Hard cap on redirect hops, so a provider (or a MITM) can't wedge us in a loop. */
32
- const MAX_REDIRECTS = 5;
33
- function checkAllowedHost(url) {
34
- let host;
35
- try {
36
- host = new URL(url).host;
37
- }
38
- catch {
39
- throw new Error(`Bad provider URL: ${url}`);
40
- }
41
- if (!EPHEMERAL_ALLOWED_HOSTS.has(host))
42
- throw new Error(`Refusing to proxy to non-provider host: ${host}`);
43
- return host;
44
- }
45
- /**
46
- * How a redirect changes the follow-up request, mirroring the WHATWG fetch spec's
47
- * own `redirect: "follow"` behavior (which we're replicating manually below so we
48
- * can re-validate the target host on every hop): 303 always downgrades to a
49
- * bodyless GET; 301/302 do the same but only for a non-GET/HEAD method; 307/308
50
- * preserve the original method and body.
51
- */
52
- function nextHopRequest(status, method, payload) {
53
- if (status === 303 || ((status === 301 || status === 302) && method !== "GET" && method !== "HEAD")) {
54
- return { method: "GET", payload: undefined };
55
- }
56
- return { method, payload };
57
- }
58
- /**
59
- * Perform one allowlisted provider request for a remote device. Rejects any
60
- * non-provider host — including a redirect target: the allowlist check ran only
61
- * on the *initial* URL, but a plain `fetch` follows redirects transparently, so a
62
- * provider response (or anyone able to influence it) could 302 us — Authorization
63
- * header and all — to an arbitrary host. `redirect: "manual"` disables that
64
- * auto-follow so every hop's Location is re-checked against the same allowlist
65
- * before it's requested.
66
- */
67
- export async function execEphemeralRequest(request, fetchImpl = fetch) {
68
- let url = String(request?.url ?? "");
69
- let method = String(request?.method ?? "GET").toUpperCase();
70
- const headers = { ...(request?.headers ?? {}) };
71
- let payload;
72
- if (request?.body !== undefined && request?.body !== null && method !== "GET" && method !== "HEAD") {
73
- payload = typeof request.body === "string" ? request.body : JSON.stringify(request.body);
74
- if (!Object.keys(headers).some((h) => h.toLowerCase() === "content-type"))
75
- headers["content-type"] = "application/json";
76
- }
77
- const controller = new AbortController();
78
- const timeout = setTimeout(() => controller.abort(), 30_000);
79
- try {
80
- for (let hop = 0;; hop++) {
81
- const host = checkAllowedHost(url);
82
- const res = await fetchImpl(url, { method, headers, body: payload, signal: controller.signal, redirect: "manual" });
83
- if (res.status >= 300 && res.status < 400 && res.status !== 304) {
84
- if (hop >= MAX_REDIRECTS)
85
- throw new Error(`Too many redirects proxying to ${host}`);
86
- const location = res.headers.get("location");
87
- if (!location)
88
- throw new Error(`Redirect from ${host} (${res.status}) had no Location header`);
89
- // Resolve relative to the current hop; the loop's next iteration
90
- // re-validates this new host before it's ever requested — the whole
91
- // point of this loop.
92
- url = new URL(location, url).toString();
93
- ({ method, payload } = nextHopRequest(res.status, method, payload));
94
- continue;
95
- }
96
- const text = await res.text();
97
- let body = text;
98
- try {
99
- body = text ? JSON.parse(text) : null;
100
- }
101
- catch { /* non-JSON provider response */ }
102
- return { status: res.status, body };
103
- }
104
- }
105
- finally {
106
- clearTimeout(timeout);
107
- }
108
- }
@@ -1,30 +0,0 @@
1
- // SPDX-License-Identifier: AGPL-3.0-only
2
- // Copyright (c) 2026 Petter André Sjulstad
3
- // One pure policy decision: does THIS daemon hold only control-plane-custodied
4
- // credentials (the separately escrowed unattended snapshot), or is it a normal
5
- // personal node that owns its vault?
6
- //
7
- // The distinction matters everywhere model-auth sync branches: a custody node
8
- // never pushes/pulls the account vault, never publishes the unattended escrow,
9
- // and treats the control plane's filtered snapshot as an authoritative set
10
- // (reconcile deletes what a newer snapshot omits). Getting this wrong on a
11
- // personal node silently breaks credential sync AND makes the unattended-runs
12
- // toggle a no-op — the "Allowed — encrypted cloud copy enabled" UI then lies,
13
- // and every Bivy Cloud session fails with "credential didn't reach Bivy Cloud".
14
- /**
15
- * True when this daemon must run with hosted-custody semantics:
16
- * - `BIVY_HOSTED_CREDENTIAL_CUSTODY` — the dedicated flag the provisioner sets
17
- * on managed (Bivy Cloud) machines; always authoritative.
18
- * - `BIVY_GITHUB_HOSTED_TASKS` + `BIVY_EPHEMERAL` — back-compat for
19
- * provisioned user-owned queue runners that predate the dedicated flag.
20
- *
21
- * `BIVY_GITHUB_HOSTED_TASKS` ALONE is not custody: it is persisted onto any
22
- * long-lived personal node when a GitHub App is connected (it only means "poll
23
- * the hosted task queue"). Such a node owns its own logins and must keep full
24
- * personal-vault semantics — account sync, escrow publishing, loud toggles.
25
- */
26
- export function hostedCustodyNode(env = process.env) {
27
- if (env.BIVY_HOSTED_CREDENTIAL_CUSTODY)
28
- return true;
29
- return Boolean(env.BIVY_GITHUB_HOSTED_TASKS && env.BIVY_EPHEMERAL);
30
- }