@bivy/bivy 0.20.9-staging.12 → 0.20.9-staging.13

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 (102) hide show
  1. package/dist/automation-reseal.js +30 -0
  2. package/dist/device-registry.js +27 -0
  3. package/dist/server.js +41 -1
  4. package/package.json +1 -1
  5. package/web/assets/AutomationsView-DN6Pjj3D.js +51 -0
  6. package/web/assets/{ChangesCard-g8Lhp8-o.js → ChangesCard-aSANT98o.js} +1 -1
  7. package/web/assets/{LibraryView-2DXscx59.js → LibraryView-CcssDQpe.js} +1 -1
  8. package/web/assets/{ProviderConnect-Cl2HBpl_.js → ProviderConnect-GHqdbDfx.js} +1 -1
  9. package/web/assets/{Settings-DUh6WdcC.js → Settings-zrbfuGw7.js} +3 -3
  10. package/web/assets/{Sheet-BERX6Dsv.js → Sheet-akpaXVWk.js} +1 -1
  11. package/web/assets/{Terminal-CJcgCagB.js → Terminal-Cl9BAqmG.js} +1 -1
  12. package/web/assets/{VoiceSettings-DkSdCkze.js → VoiceSettings-CiVFD62Z.js} +1 -1
  13. package/web/assets/{abnfDiagram-VCTEODGH-BHD5JTM6.js → abnfDiagram-VCTEODGH-DvcKa8Q6.js} +1 -1
  14. package/web/assets/architecture-7GRP2DOG-Db3dVfEg.js +1 -0
  15. package/web/assets/{architectureDiagram-5GKGNRK7-C_GKL4K7.js → architectureDiagram-5GKGNRK7-C5UHXNNA.js} +1 -1
  16. package/web/assets/{blockDiagram-I7D4REHJ-CRq2fdX9.js → blockDiagram-I7D4REHJ-B3bEudR9.js} +1 -1
  17. package/web/assets/{c4Diagram-7LVT6UL2-CvXSE3hG.js → c4Diagram-7LVT6UL2-B-Uwyk2S.js} +1 -1
  18. package/web/assets/channel-BmwZ91Zu.js +1 -0
  19. package/web/assets/{chunk-4HAMMTFA-Ds9o7yrU.js → chunk-4HAMMTFA-ZZNhY7ou.js} +1 -1
  20. package/web/assets/{chunk-75Z2AOVW-BwiC6QFm.js → chunk-75Z2AOVW-DkSlF2wc.js} +1 -1
  21. package/web/assets/{chunk-DU6HZSFF-236r-frX.js → chunk-DU6HZSFF-DJSerjpq.js} +1 -1
  22. package/web/assets/{chunk-F27PBJKO-CguQ8WaZ.js → chunk-F27PBJKO-BnSlJxd6.js} +1 -1
  23. package/web/assets/{chunk-GMAD6QVW-DmBwXsGy.js → chunk-GMAD6QVW-k1Kqheha.js} +1 -1
  24. package/web/assets/{chunk-GVQU2GXP-DnkJJSYL.js → chunk-GVQU2GXP-D-Dky606.js} +1 -1
  25. package/web/assets/{chunk-IMKFNOWR-YG1z0eu5.js → chunk-IMKFNOWR-CMgW8VOp.js} +1 -1
  26. package/web/assets/{chunk-L3NEJ4N5-D39eIpWM.js → chunk-L3NEJ4N5-BPppfNZq.js} +1 -1
  27. package/web/assets/{chunk-OSK3NFVY-CGrQqCBq.js → chunk-OSK3NFVY-X1S-7cI8.js} +1 -1
  28. package/web/assets/{chunk-P2QGCYS3-CnzAU-Mz.js → chunk-P2QGCYS3-C3D0xAbV.js} +1 -1
  29. package/web/assets/{chunk-POPQ4Y6H-CWalH36f.js → chunk-POPQ4Y6H-rzpiAvDt.js} +1 -1
  30. package/web/assets/{chunk-PWAF6VOD-BQT5ioTL.js → chunk-PWAF6VOD-BnelcVCG.js} +1 -1
  31. package/web/assets/{chunk-SHT3W25Y-wfqek-d7.js → chunk-SHT3W25Y-BpUiekby.js} +1 -1
  32. package/web/assets/{chunk-SVP7TREG-CBp3IjhM.js → chunk-SVP7TREG-CHzYiMcX.js} +1 -1
  33. package/web/assets/{chunk-TICWLB2K-ags6QsSk.js → chunk-TICWLB2K-Cil76YwI.js} +1 -1
  34. package/web/assets/classDiagram-ZZMXUADV-BWeCowiO.js +1 -0
  35. package/web/assets/classDiagram-v2-VYDZK3BY-BWeCowiO.js +1 -0
  36. package/web/assets/{cynefin-OW5HDTMX-DO3oi7vt.js → cynefin-OW5HDTMX-DqYTG6s3.js} +1 -1
  37. package/web/assets/{cynefinDiagram-5FMLGOSQ-CIXw7Cc6.js → cynefinDiagram-5FMLGOSQ-DHoCWcHR.js} +1 -1
  38. package/web/assets/{dagre-GXQ25YYZ-BLXWq9eV.js → dagre-GXQ25YYZ-CkVRQJ7Q.js} +1 -1
  39. package/web/assets/{diagram-S7CK7UJ4-bA0zwJY_.js → diagram-S7CK7UJ4-DTqxklJ8.js} +1 -1
  40. package/web/assets/{diagram-UQ7AKVKN-DKogFgPR.js → diagram-UQ7AKVKN-BfPq1M8P.js} +1 -1
  41. package/web/assets/{diagram-VSXAHHWV-qkLzNlr2.js → diagram-VSXAHHWV-BQnLbJ0g.js} +1 -1
  42. package/web/assets/{diagram-VX7I27RA-_osxbKbn.js → diagram-VX7I27RA-B8A1-dub.js} +1 -1
  43. package/web/assets/{diagram-Z3DM3KII-CQljxyfX.js → diagram-Z3DM3KII-CRBTYKWA.js} +1 -1
  44. package/web/assets/{ebnfDiagram-PWID7BFC-C8Y5lz7G.js → ebnfDiagram-PWID7BFC-FvVv2X7o.js} +1 -1
  45. package/web/assets/{erDiagram-RLTQ6QDP-DjUCgPos.js → erDiagram-RLTQ6QDP-D1s8uXzs.js} +1 -1
  46. package/web/assets/eventmodeling-NTZA5JFV-DRobz4Mt.js +1 -0
  47. package/web/assets/flowDiagram-HODETNUW-DmXstahq.js +1 -0
  48. package/web/assets/{ganttDiagram-EL5Y4UJY-CMCiD5IY.js → ganttDiagram-EL5Y4UJY-BEdenIa6.js} +1 -1
  49. package/web/assets/{gitGraph-4MIJSDKK-BRcacSQ-.js → gitGraph-4MIJSDKK-BCH2_BAZ.js} +1 -1
  50. package/web/assets/{gitGraphDiagram-WWUBYQGX-0js7hKj5.js → gitGraphDiagram-WWUBYQGX-BYL-zyse.js} +1 -1
  51. package/web/assets/{index-BdEB2YRe.js → index-ROUVrPbc.js} +2 -2
  52. package/web/assets/{info-A6RAGUB7-CsrRX5La.js → info-A6RAGUB7-CKrUmOha.js} +1 -1
  53. package/web/assets/{infoDiagram-27XIBGKW-DDP3W2Tm.js → infoDiagram-27XIBGKW-Dgv66P4Q.js} +1 -1
  54. package/web/assets/{ishikawaDiagram-5VMMS53U-BMu0M7NV.js → ishikawaDiagram-5VMMS53U-C0kmn2Cr.js} +1 -1
  55. package/web/assets/{journeyDiagram-3NMN7TZE-BPr-VSMD.js → journeyDiagram-3NMN7TZE-5jZi913z.js} +1 -1
  56. package/web/assets/{kanban-definition-UXKFOSKX-BM-VHNhy.js → kanban-definition-UXKFOSKX-DO4Z-hZf.js} +1 -1
  57. package/web/assets/{line-Bd9NaoV1.js → line-zuKPCmLl.js} +1 -1
  58. package/web/assets/{mermaid-parser.core-hutbDo6D.js → mermaid-parser.core-4-0aU2cI.js} +3 -3
  59. package/web/assets/{mermaid.core-gqG1ONr1.js → mermaid.core-BZrDCPKc.js} +4 -4
  60. package/web/assets/{mindmap-definition-YA3MSWOX-DxVb-AvM.js → mindmap-definition-YA3MSWOX-DOFnNlT5.js} +1 -1
  61. package/web/assets/{mount-DShkRPG0.js → mount-BpoYlWmV.js} +5 -5
  62. package/web/assets/{packet-AYTQ26CC-dFLVGDcI.js → packet-AYTQ26CC-BDFArHuv.js} +1 -1
  63. package/web/assets/{pegDiagram-XKGWAZYB-Bazytp0F.js → pegDiagram-XKGWAZYB-7CxEp7-m.js} +1 -1
  64. package/web/assets/{pie-WAS4IAKB-CTkqaK_f.js → pie-WAS4IAKB-BUC9CmzW.js} +1 -1
  65. package/web/assets/{pieDiagram-E7YTZNPT-CDvZ4aIB.js → pieDiagram-E7YTZNPT-BlXxIkan.js} +1 -1
  66. package/web/assets/{quadrantDiagram-AXDQQJYC-DTSeVxbf.js → quadrantDiagram-AXDQQJYC-C5GRb0RN.js} +1 -1
  67. package/web/assets/{radar-RG4KPBEZ-CKfc3MS_.js → radar-RG4KPBEZ-M1s8yzHp.js} +1 -1
  68. package/web/assets/{railroad-74A4TZTK-Cxcv3-64.js → railroad-74A4TZTK-BQj2Bxlk.js} +1 -1
  69. package/web/assets/railroad-abnf-HS5TGJTU-cooT4VHw.js +1 -0
  70. package/web/assets/railroad-ebnf-LZEXJU2U-Dbxg-HJI.js +1 -0
  71. package/web/assets/railroad-peg-WCYAUIDC-DF7RNXo3.js +1 -0
  72. package/web/assets/{railroadDiagram-O6MQD6OU-DevTuLL1.js → railroadDiagram-O6MQD6OU-n0Sd3MRX.js} +1 -1
  73. package/web/assets/{requirementDiagram-BXWQKSXE-BYjGKExS.js → requirementDiagram-BXWQKSXE-A0anIwln.js} +1 -1
  74. package/web/assets/{sankeyDiagram-P5KCCOFB-CfVa0PNX.js → sankeyDiagram-P5KCCOFB-f_ILKHwt.js} +1 -1
  75. package/web/assets/{sequenceDiagram-WJ2MYXX4-Dl5bPCHn.js → sequenceDiagram-WJ2MYXX4-Z4Yxn3Me.js} +1 -1
  76. package/web/assets/{settingsRoute-d6enyGGs.js → settingsRoute-Co4_ejOs.js} +1 -1
  77. package/web/assets/{stateDiagram-D77RDMKH-BtU_gQEb.js → stateDiagram-D77RDMKH-DH4tyyvM.js} +1 -1
  78. package/web/assets/stateDiagram-v2-MP3YSRHH-BGcz3nv5.js +1 -0
  79. package/web/assets/{swimlanes-42K2YHIH-DIe9GxhW.js → swimlanes-42K2YHIH-D0mYIRp_.js} +1 -1
  80. package/web/assets/swimlanesDiagram-VR7AAH4N-DytMuA5I.js +8 -0
  81. package/web/assets/{timeline-definition-24CTP7MA-B9g7nrL1.js → timeline-definition-24CTP7MA-D9SvE_xH.js} +1 -1
  82. package/web/assets/{treeView-Q6P3EWNA-DdT2XETS.js → treeView-Q6P3EWNA-BJZ3tNbp.js} +1 -1
  83. package/web/assets/{treemap-WGGIJYW6-h4WmocS0.js → treemap-WGGIJYW6-B4y9-El8.js} +1 -1
  84. package/web/assets/{useStore-DzDtTF5N.js → useStore-BjgRUXv4.js} +1 -1
  85. package/web/assets/{vennDiagram-4TSXK5OY-gk44eWcf.js → vennDiagram-4TSXK5OY-COLSJIgu.js} +1 -1
  86. package/web/assets/{wardley-WFR3VGLG-uJbKN4qW.js → wardley-WFR3VGLG-D8rExT50.js} +1 -1
  87. package/web/assets/{wardleyDiagram-VM6X3IG4-Diy79JCP.js → wardleyDiagram-VM6X3IG4-BSLx_T3_.js} +1 -1
  88. package/web/assets/{xychartDiagram-S5SC5T6Z-CbeKz8Bk.js → xychartDiagram-S5SC5T6Z-DekMZK0J.js} +1 -1
  89. package/web/index.html +1 -1
  90. package/web/sw.js +1 -1
  91. package/web/assets/AutomationsView-BWARomwT.js +0 -51
  92. package/web/assets/architecture-7GRP2DOG-BK3P2Dfz.js +0 -1
  93. package/web/assets/channel-Bsrodtv-.js +0 -1
  94. package/web/assets/classDiagram-ZZMXUADV-BBOjgswF.js +0 -1
  95. package/web/assets/classDiagram-v2-VYDZK3BY-BBOjgswF.js +0 -1
  96. package/web/assets/eventmodeling-NTZA5JFV-CKIRww6K.js +0 -1
  97. package/web/assets/flowDiagram-HODETNUW-C9kJw-vn.js +0 -1
  98. package/web/assets/railroad-abnf-HS5TGJTU-CDmyp3sp.js +0 -1
  99. package/web/assets/railroad-ebnf-LZEXJU2U-CbiTHSV5.js +0 -1
  100. package/web/assets/railroad-peg-WCYAUIDC-CVsfoDy0.js +0 -1
  101. package/web/assets/stateDiagram-v2-MP3YSRHH-CGVAIFE8.js +0 -1
  102. package/web/assets/swimlanesDiagram-VR7AAH4N-CY0bvLUP.js +0 -8
@@ -0,0 +1,30 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-only
2
+ // Copyright (c) 2026 Petter André Sjulstad
3
+ import { open, seal } from "./e2e.js";
4
+ export async function resealAutomationTemplates(opts) {
5
+ const prefix = `bivy-room-v1:${opts.nodeId}:`;
6
+ const result = { resealed: 0, unreadable: [] };
7
+ for (const template of opts.templates) {
8
+ if (!template.templateCiphertext.startsWith(prefix))
9
+ continue;
10
+ const payload = template.templateCiphertext.slice(prefix.length);
11
+ if (tryOpen(opts.current, payload) !== undefined)
12
+ continue;
13
+ const plaintext = opts.retired.map((key) => tryOpen(key, payload)).find((text) => text !== undefined);
14
+ if (plaintext === undefined) {
15
+ result.unreadable.push(template.id);
16
+ continue;
17
+ }
18
+ await opts.save(template.id, `${prefix}${seal(opts.current, plaintext)}`);
19
+ result.resealed += 1;
20
+ }
21
+ return result;
22
+ }
23
+ function tryOpen(key, payload) {
24
+ try {
25
+ return open(key, payload);
26
+ }
27
+ catch {
28
+ return undefined;
29
+ }
30
+ }
@@ -7,6 +7,7 @@ import { generatePairingKeypair, generateRoomKey, generatePairSecret, deriveWrap
7
7
  import { seal, open } from "./e2e.js";
8
8
  const DEFAULT_PAIR_TTL_MS = 5 * 60_000;
9
9
  const ROOM_KEY_BYTES = 32;
10
+ const MAX_RETIRED_ROOM_KEYS = 8;
10
11
  /**
11
12
  * Validate + canonicalize a pre-shared room-key seed. Returns the canonical
12
13
  * base64 of a well-formed 32-byte key, or undefined for anything malformed
@@ -81,6 +82,7 @@ export class PairingStore {
81
82
  return new PairingStore(filePath, {
82
83
  nodeKeypair: parsed.nodeKeypair,
83
84
  roomKeyB64: parsed.roomKeyB64,
85
+ ...(Array.isArray(parsed.retiredRoomKeysB64) && parsed.retiredRoomKeysB64.length ? { retiredRoomKeysB64: parsed.retiredRoomKeysB64 } : {}),
84
86
  devices: Array.isArray(parsed.devices) ? parsed.devices : [],
85
87
  });
86
88
  }
@@ -130,6 +132,30 @@ export class PairingStore {
130
132
  roomKey() {
131
133
  return Buffer.from(this.data.roomKeyB64, "base64");
132
134
  }
135
+ /** Room keys replaced by earlier rotations that still guard stored data. */
136
+ retiredRoomKeys() {
137
+ return (this.data.retiredRoomKeysB64 ?? []).map((key) => Buffer.from(key, "base64"));
138
+ }
139
+ /** Drop retired room keys once nothing stored is sealed under them. */
140
+ forgetRetiredRoomKeys() {
141
+ if (!this.data.retiredRoomKeysB64)
142
+ return;
143
+ delete this.data.retiredRoomKeysB64;
144
+ this.persist();
145
+ }
146
+ /** Open a payload sealed under the current room key or a retired one. */
147
+ openSealed(payload) {
148
+ let lastError;
149
+ for (const key of [this.roomKey(), ...this.retiredRoomKeys()]) {
150
+ try {
151
+ return open(key, payload);
152
+ }
153
+ catch (error) {
154
+ lastError = error;
155
+ }
156
+ }
157
+ throw lastError;
158
+ }
133
159
  /** Issue a single-use, expiring pairing secret to embed in a linking QR. */
134
160
  issuePairSecret(ttlMs = DEFAULT_PAIR_TTL_MS) {
135
161
  this.sweepSecrets();
@@ -215,6 +241,7 @@ export class PairingStore {
215
241
  }
216
242
  /** Rotate the room key and re-wrap it for all current devices. */
217
243
  rotateRoomKey() {
244
+ this.data.retiredRoomKeysB64 = [this.data.roomKeyB64, ...(this.data.retiredRoomKeysB64 ?? [])].slice(0, MAX_RETIRED_ROOM_KEYS);
218
245
  this.data.roomKeyB64 = generateRoomKey().toString("base64");
219
246
  this.persist();
220
247
  const roomKey = this.roomKey();
package/dist/server.js CHANGED
@@ -54,6 +54,7 @@ import { ControlPlaneSessionLocationRegistry, LayeredSessionLocationRegistry } f
54
54
  import { attachAdoptedSessions, classifyAttachFailure } from "./runtime/adoption.js";
55
55
  import { createCredentialStore, testProviderCredential } from "./runtime/credentials.js";
56
56
  import { decodeAutomationTemplate } from "./automation-template.js";
57
+ import { resealAutomationTemplates } from "./automation-reseal.js";
57
58
  import { passWebhookFilter } from "./automation-filter-gate.js";
58
59
  import { isModelAuthError, authProviderForSession, classifyModelAuthError } from "./runtime/auth-errors.js";
59
60
  import { createCredentialVault, migrateVaultDir } from "./runtime/credential-store.js";
@@ -1080,6 +1081,7 @@ const linkedDevices = createLinkedDeviceController({
1080
1081
  syncPairingMetadata();
1081
1082
  relay?.pushRotate(deliveries);
1082
1083
  broadcast({ type: "devices.updated", devices });
1084
+ void resealRetiredAutomationTemplates();
1083
1085
  },
1084
1086
  });
1085
1087
  const accessDevices = createAccessDeviceController({
@@ -3537,6 +3539,7 @@ function startRelayIfConfigured() {
3537
3539
  if (config.controlPlaneUrl && config.enrollmentToken) {
3538
3540
  sessionAdvertiseTarget = { controlPlaneUrl: config.controlPlaneUrl, enrollmentToken: config.enrollmentToken };
3539
3541
  void syncModelAuthFromControlPlane();
3542
+ void resealRetiredAutomationTemplates();
3540
3543
  if (remoteRuntimeEnabled()) {
3541
3544
  // Stage 3: layer a control-plane-backed location registry UNDER the in-memory
3542
3545
  // one (so a lookup surviving a restart resolves from durable state), then
@@ -3698,6 +3701,43 @@ async function modelAuthFetch(pathname, init = {}) {
3698
3701
  headers.set("content-type", "application/json");
3699
3702
  return fetch(`${sessionAdvertiseTarget.controlPlaneUrl.replace(/\/$/, "")}${pathname}`, { ...init, headers });
3700
3703
  }
3704
+ // A device revoke rotates the room key. Re-seal this node's stored automation
3705
+ // instructions under the new key so the node and its devices can still read
3706
+ // them, then drop the retired keys. Retried at startup until it completes.
3707
+ async function resealRetiredAutomationTemplates() {
3708
+ const retired = pairingStore.retiredRoomKeys();
3709
+ if (!retired.length || !sessionAdvertiseTarget)
3710
+ return;
3711
+ const current = pairingStore.roomKey();
3712
+ try {
3713
+ const res = await modelAuthFetch("/node/automation-templates");
3714
+ if (!res?.ok)
3715
+ throw new Error(`control plane returned ${res?.status}`);
3716
+ const { templates } = await res.json();
3717
+ const result = await resealAutomationTemplates({
3718
+ nodeId: identity.nodeId,
3719
+ current,
3720
+ retired,
3721
+ templates,
3722
+ save: async (id, templateCiphertext) => {
3723
+ const saved = await modelAuthFetch(`/node/automation-templates/${encodeURIComponent(id)}`, { method: "PUT", body: JSON.stringify({ templateCiphertext }) });
3724
+ if (!saved?.ok)
3725
+ throw new Error(`control plane returned ${saved?.status}`);
3726
+ },
3727
+ });
3728
+ if (result.resealed)
3729
+ console.log(`[automation-reseal] re-sealed ${result.resealed} automation template(s) under the rotated room key`);
3730
+ if (result.unreadable.length)
3731
+ console.warn(`[automation-reseal] ${result.unreadable.length} automation template(s) were sealed under a key this node no longer has: ${result.unreadable.join(", ")}`);
3732
+ // Another rotation during this pass retired `current`; run again for it.
3733
+ if (!pairingStore.roomKey().equals(current))
3734
+ return void resealRetiredAutomationTemplates();
3735
+ pairingStore.forgetRetiredRoomKeys();
3736
+ }
3737
+ catch (error) {
3738
+ console.warn("[automation-reseal] will retry at next start:", error.message);
3739
+ }
3740
+ }
3701
3741
  const remoteSessionAdmission = createRemoteSessionAdmission(async (idempotencyKey) => {
3702
3742
  // Only remote scopes reach this callback. Self-hosted control planes answer
3703
3743
  // allowed without an extension; losing enrollment mid-launch must fail closed.
@@ -5554,7 +5594,7 @@ async function executeWorkItem(item, report, signal) {
5554
5594
  throw new Error("automation instructions were encrypted for a different node");
5555
5595
  }
5556
5596
  try {
5557
- const template = decodeAutomationTemplate(open(pairingStore.roomKey(), payload.join(":")));
5597
+ const template = decodeAutomationTemplate(pairingStore.openSealed(payload.join(":")));
5558
5598
  credentialLabels = template.credentialLabels;
5559
5599
  filter = template.filter;
5560
5600
  item = { ...item, body: template.instructions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bivy/bivy",
3
- "version": "0.20.9-staging.12",
3
+ "version": "0.20.9-staging.13",
4
4
  "type": "module",
5
5
  "license": "AGPL-3.0-only",
6
6
  "description": "Run coding agents on machines you own. Open-source, self-hostable agent workspace.",