chainlesschain 0.166.84 → 0.166.86

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 (187) hide show
  1. package/README.md +17 -4
  2. package/package.json +3 -2
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/assets/{AIOps-OYLnAlB5.js → AIOps-DZwiXAIh.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-uc9kbLR6.js → ActionButton-aNzXoIJP.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-BH901FG0.js → Analytics-ETQk4ZXt.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-qypKb8GL.js → AppLayout-D5oEbeEC.js} +4 -4
  9. package/src/assets/web-panel/assets/{Artifacts-Q-uPWyLY.js → Artifacts-ja48FAne.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-B8hMGMim.js → Audit-DlN0YnDt.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-BSs8rJL_.js → BackgroundAgents-CzvyNsRg.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-2YMU_nCd.js → Backup-DXgEC2MQ.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-DyMppTuT.js → BaseInput-D9XqejLx.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-B5QGMaDO.js → Chat-BTwuYUlN.js} +5 -5
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-B8ts_JnN.js → ChatBubbleRenderer-0anIC2Wn.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-DAvtgEGd.js → Checkbox-CLuaQbDt.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-BSChEVM3.js → Codegen-KwQUZs8A.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-G0zYohIP.js → Col-BCmROkzc.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-CzCN0B_p.js → Community-CXlUEHR4.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-DrIN3G8z.js → Compact-Dzx-lWI2.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-CIsLa64Z.js → Compliance-CfXW82FF.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-CGYoafsB.js → Cowork-DIISTRm2.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-DJ1JPXuH.js → Cron-nyJ-KcFE.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-B-IqVFJl.js → Crosschain-Dtv1E4cV.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-CAAczPz_.js → DID-BCTpektS.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-Dkpel8VE.js → Dashboard-C1Q_m0So.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-ETNBf8-Z.js → Dropdown-BrQ5_PPL.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-CJGDyjVD.js → EmailListRenderer-DjoNlONP.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-CL_hvVYe.js → EvolutionSettings-DaGaE6bX.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-iexOh6Dh.js → FamilyGuardDashboard-nJDWBECt.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-DnDHvV5D.js → Federation-DhMUY_wG.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-DLCDJjUp.js → FormItemContext-CbONJPuc.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-CaCgXCjS.js → GenericCardRenderer-CDdX4dX-.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-BVm-euUF.js → Git-DXbDVJdR.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-DPnUvLWr.js → Governance-DbAfAvs1.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-5qCWSYKl.js → Inference-Dy-fGea2.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-DXdv2oEh.js → KnowledgeGraph-DAxRpGUF.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-BF2f7bBA.js → Logs-5L1UCR8X.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-u0FPafvT.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-Bp-0Y7Ng.js → Marketplace-DUk_McDG.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-dm-Xdi63.js → McpTools-B6PNsZ_p.js} +2 -2
  42. package/src/assets/web-panel/assets/{Memory-TBHK031z.js → Memory-BUUs8j5F.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-BTILAlds.js → MobileBridge-pXRsgyuO.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-DC0Clgzs.js → MobileProjects-D7v-2Hwm.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-BvyWkmRw.js → Mtc-Deaj4faB.js} +4 -4
  46. package/src/assets/web-panel/assets/{MtcAudit-D7ksLoNa.js → MtcAudit-wUV0VUH1.js} +2 -2
  47. package/src/assets/web-panel/assets/{Multisig-Dpzu7X1t.js → Multisig-C67IIkts.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-DZ0ADHSB.js → NLProgramming-BCA_CWrW.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-hIdkmRug.js → Notes-D9eu14hQ.js} +4 -4
  50. package/src/assets/web-panel/assets/{NotificationSettings-R3jyP6Vf.js → NotificationSettings-Cnd-J4LM.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-d1zrFkqx.js → OrderTableRenderer-C4pHUuyZ.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-DoA5WMcc.js → Organization-4YExAbnp.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-DHjIloAQ.js → Overflow-BF-wFuZz.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-2TMon_Wy.js → P2P-CdiajqCT.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-DEUxGSWO.js → PdhVaultBrowser-BkjfS6Th.js} +5 -5
  56. package/src/assets/web-panel/assets/{Permissions-CxKcZ-8X.js → Permissions-DrZ4D78_.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-CcYtkHqc.js → PersonalDataHub-lDc6OXjz.js} +6 -6
  58. package/src/assets/web-panel/assets/{Pipeline-BxwOuq22.js → Pipeline-DqDS9ON1.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-VIx9pdsH.js → Privacy-BMekZRZu.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-COjp_erK.js → ProjectInit-LYS7NFvJ.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-x9NrZU80.js → ProjectSettings-CcJNHk9A.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-DMgkw7QJ.js → Projects-DrfAHgdF.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-B_fR7Y7Y.js → Providers-aqsly9SR.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-BUvzrn3V.js → QrScannerModal-ZWvR3zqg.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-C0sJwLy2.js → QuickAsk-BT5CgsvW.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-CJC7Wpce.js → Recommend-Cz8Dz2RN.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-B62J6ZP0.js → RemoteSession-BlxPVbtQ.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-4f48kVBn.js → Reputation-B3VGBE-1.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-EzEMaYoV.js → Row-Bwv7vSEA.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-Dy0wD83j.js → RssFeed-DHI085r_.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-GeVRHQND.js → Search-DBler5T0.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-omLr1J7w.js → Security-BZdw43NW.js} +3 -3
  73. package/src/assets/web-panel/assets/{Services-DmGPaDAs.js → Services-Cslk5lUj.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-CAla21Gm.js → Skeleton-Bur-C-25.js} +1 -1
  75. package/src/assets/web-panel/assets/Skills-v0zgLy0X.js +1 -0
  76. package/src/assets/web-panel/assets/{Sla-Cwi15-pZ.js → Sla-B1OWgQ51.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-Cs8Zi1J8.js → SpeechSettings-CaBcEaV4.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-ipuJsDKP.js → SyncSettings-CBbG8L6J.js} +2 -2
  79. package/src/assets/web-panel/assets/Tasks-C7EjXrnN.js +1 -0
  80. package/src/assets/web-panel/assets/{Templates-slUp9yXF.js → Templates-VBBOZ1H5.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-6edCSG5K.js → Tenant-CtQTj7IF.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-DKq84G3h.js → Terminal-DXVTQjnl.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-Dg0Aw6se.js → TimelineRenderer-BRIno0aN.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-D63h7qYd.js → Tokens-uiiAfkYN.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-F7gTP_gv.js → Trigger-CPApN8o6.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-zw8Zqp8k.js → Trust-T2jKVwCE.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-C-YBUmod.js → UkeySign-C2U_gbzP.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-AhVxTgmC.js → VideoEditing-BCdlr3Kj.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-C58zxjIg.js → Wallet-CWnjoSc1.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-D-n-rlfI.js → WebAuthn-CqSbYqHq.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-Ddc8gGD4.js → WorkflowEditor-Dr_I3jcr.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-C66V_U7w.js → chat-Cg21FKdE.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-BcJyVZRj.js → colors-CK85tY9e.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-UgUXWcgP.js → compact-item-m-XYPC7W.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-oxEKHKYP.js → createContext-BmiEeNvs.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-CkMEODFC.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-CbqzrKQO.js → hasIn-CCw4KAoc.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CH13yc9x.js → index-6jXf-Lln.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BdFgUn1S.js → index-8KzhlvJ9.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-D3xNhHF3.js → index-B7xJkhtJ.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DAIuMvVR.js → index-B8IC9ZeZ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CrG-1Kqs.js → index-BGUYgc96.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-Bu1A2sXy.js → index-BGb1j2z9.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BQlGMcZ9.js → index-BHsiSoGY.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DWFNv_EG.js → index-BIOTRzaF.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BrWZmUdA.js → index-BStyjmLG.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-C-p9hhAz.js → index-BUYyhYP6.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CM2S5TJZ.js → index-BcfVHmFK.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-7lSY8B9T.js → index-BiVPFsat.js} +1 -1
  110. package/src/assets/web-panel/assets/index-BjE5qaKn.js +1 -0
  111. package/src/assets/web-panel/assets/{index-B-h0Jgtj.js → index-Br0ZNdu1.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D8rgeCoC.js → index-Br9t_I1X.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DRrxJygS.js → index-BtvVupUL.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-DO-5vgTW.js → index-Bv90WEWa.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DBEL07sa.js → index-BvjC3t35.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-UpN_kC9R.js → index-ByVvAXdl.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-SzGgAqai.js → index-CBcgIWOe.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-C3j9jTfB.js → index-CN2xbLGz.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Bmhw_Ler.js → index-CYEzWoyZ.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Crqqbu-W.js → index-Cf5arJie.js} +1 -1
  121. package/src/assets/web-panel/assets/index-CsFH-2Zk.js +1 -0
  122. package/src/assets/web-panel/assets/{index-BMOY4PSW.js → index-D1sU5-XA.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BT2PZ9df.js → index-D7gS_TJl.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-YvNh1UdB.js → index-DAlGVix-.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BZ7mv_oS.js → index-DI9GJFcn.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Ov77O9mH.js → index-DIlGxS2W.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CJluGB2F.js → index-DMbrl43d.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-C6X26RJu.js → index-DmSgfXuz.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DMbJ06sF.js → index-DpIy2HzE.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CUmYwZyf.js → index-DxRhnsEC.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BNIq0NAn.js → index-IskAKXhx.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DR4YKlLt.js → index-J81uvUMN.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-RnxuL8wM.js → index-OIbfsi-o.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-Bp9rfr-P.js → index-lhoexBDH.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-BpqJNeIj.js → index-sWUmvT8H.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-CuZupgUw.js → index-yYmjkf38.js} +3 -3
  137. package/src/assets/web-panel/assets/{initDefaultProps-BK9ncFiF.js → initDefaultProps-Cc1XOmNe.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-BxzXi1Pe.js → motion-BehsX88u.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-CRmwRuah.js → move-BPx2YsqY.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-BQq5_Znx.js → mtc-parser-BSFJgFQA.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-Ch4VNY2j.js → omit-DBN5KUeo.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-CUioBhrz.js → pickAttrs-BDK1yZ-9.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-Hj3o1CrW.js → placementArrow-C4rMmKNJ.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-PfqJrlkI.js → responsiveObserve-BoeoOnxX.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-BXcnR-Lu.js → slide-BKlr1bl9.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-C74a-ofo.js → statusUtils-Ky1apWPI.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-Bq57I3ls.js → styleChecker-DxxR7uXk.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-ITPUjcDw.js → useFlexGapSupport-DmsUqVe9.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-DzPuXDIS.js → useFs-CwkG7sOg.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-DYSgt9L5.js → usePersonalDataHub-CddgeEfF.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-NPs_EJEk.js → vnode-C_-H8i4Y.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-DZzO6KVS.js → zoom-aAsHUMNE.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/commands/permissions.js +27 -2
  155. package/src/data/changelog.json +26 -0
  156. package/src/lib/background-interaction-resolver.js +4 -0
  157. package/src/lib/context-memory-kernel/durable-memory-port.js +71 -15
  158. package/src/lib/context-memory-kernel/index.js +1 -0
  159. package/src/lib/context-memory-kernel/memory-service.js +43 -16
  160. package/src/lib/context-memory-kernel/runtime.js +5 -3
  161. package/src/lib/context-memory-kernel/segmented-memory-port.js +687 -0
  162. package/src/lib/packer/pack-update-applier.js +41 -17
  163. package/src/lib/packer/pkg-config-generator.js +119 -2
  164. package/src/lib/packer/pkg-runner.js +7 -0
  165. package/src/lib/packer/pkg-targets.js +83 -0
  166. package/src/lib/packer/web-panel-builder.js +7 -0
  167. package/src/lib/permission-authority.js +157 -13
  168. package/src/lib/process-execution-broker/index.js +11 -0
  169. package/src/lib/process-execution-broker/linux-subreaper-helper.js +87 -13
  170. package/src/lib/process-execution-broker/packer-build-policy.js +31 -0
  171. package/src/lib/process-execution-broker/platform-sandbox.js +11 -3
  172. package/src/lib/sandbox-egress-authority-monitor.js +62 -5
  173. package/src/lib/scoped-permission-store.js +119 -6
  174. package/src/lib/settings-authority-domain.cjs +37 -2
  175. package/src/lib/settings-loader.cjs +112 -42
  176. package/src/lib/settings-permission-authority.cjs +373 -0
  177. package/src/runtime/agent-core.js +79 -383
  178. package/src/runtime/headless-runner.js +8 -3
  179. package/src/runtime/headless-stream.js +10 -3
  180. package/src/runtime/permission-authority-host.js +137 -0
  181. package/src/runtime/provider-stream-state.js +379 -0
  182. package/src/assets/web-panel/assets/MarkdownRenderer-qNJS3ygh.js +0 -1
  183. package/src/assets/web-panel/assets/Skills-QqEyIKOI.js +0 -1
  184. package/src/assets/web-panel/assets/Tasks-BbVAg9Z7.js +0 -1
  185. package/src/assets/web-panel/assets/devWarning-BoDvrsgY.js +0 -1
  186. package/src/assets/web-panel/assets/index-BhqRbl5P.js +0 -1
  187. package/src/assets/web-panel/assets/index-DreT6MIR.js +0 -1
@@ -86,11 +86,13 @@ import {
86
86
  mcpStdioCapsuleNativeCodePolicyDigest,
87
87
  } from "../mcp-stdio-native-code-policy.js";
88
88
 
89
+ import { isPackerBuildPolicy } from "./packer-build-policy.js";
89
90
  const SUPPORTED_SANDBOX_BOUNDARIES = new Set(Object.values(SANDBOX_BOUNDARIES));
90
91
  const SUPPORTED_SANDBOX_PROFILES = new Set([
91
92
  "default",
92
93
  "strict",
93
94
  "network-only",
95
+ "build",
94
96
  ]);
95
97
  // Broker-private admission state. Public runtime-probe fields are audit
96
98
  // evidence, not authority to invoke a privileged post-spawn closure.
@@ -1590,6 +1592,15 @@ class ProcessExecutionBroker extends EventEmitter {
1590
1592
  }
1591
1593
 
1592
1594
  const profile = rawPolicy?.profile ?? null;
1595
+ if (
1596
+ profile === "build" &&
1597
+ !isPackerBuildPolicy(rawPolicy, options, launch)
1598
+ ) {
1599
+ throw this._sandboxBoundaryError(
1600
+ "untrusted_build_sandbox_policy",
1601
+ "The build CPU budget requires an original packer policy for this origin and scope",
1602
+ );
1603
+ }
1593
1604
  if (profile !== null && !SUPPORTED_SANDBOX_PROFILES.has(profile)) {
1594
1605
  throw this._sandboxBoundaryError(
1595
1606
  "invalid_sandbox_profile",
@@ -67,10 +67,77 @@ function compilerPath() {
67
67
  return compiler;
68
68
  }
69
69
 
70
+ function isPkgRuntime() {
71
+ if (!process.pkg) return false;
72
+ // The location is derived only from this module and pkg's bootstrap, never
73
+ // from cwd, executable siblings, environment variables or caller paths.
74
+ if (
75
+ typeof process.pkg.defaultEntrypoint !== "string" ||
76
+ !process.pkg.defaultEntrypoint.startsWith("/snapshot/") ||
77
+ !fileURLToPath(import.meta.url).startsWith("/snapshot/")
78
+ )
79
+ throw failure("invalid-standalone-runtime");
80
+ return true;
81
+ }
82
+
83
+ function readPkgAsset(file, maximum) {
84
+ // pkg's snapshot descriptors refer to /dev/null in the kernel and are read
85
+ // through its immutable payload reader. They are NOT native directory FDs.
86
+ // Reject real files mounted under a snapshot-looking pathname as well as
87
+ // symlink aliases; a pathname prefix alone never establishes this identity.
88
+ if (fs.realpathSync(file) !== file || fs.lstatSync(file).isSymbolicLink())
89
+ throw failure("invalid-standalone-asset");
90
+ const fd = fs.openSync(file, fs.constants.O_RDONLY);
91
+ try {
92
+ if (fs.readlinkSync(`/proc/self/fd/${fd}`) !== "/dev/null")
93
+ throw failure("standalone-asset-not-embedded");
94
+ const stat = fs.fstatSync(fd);
95
+ if (
96
+ !stat.isFile() ||
97
+ stat.size < 1 ||
98
+ stat.size > maximum ||
99
+ stat.nlink !== 0 ||
100
+ stat.ino !== 0 ||
101
+ stat.dev !== 0
102
+ )
103
+ throw failure("invalid-standalone-asset");
104
+ // readFileSync(path) reads the embedded payload directly. pkg readSync(fd)
105
+ // can instead read a decompressed external cache when compression is on.
106
+ // Never trust those cache bytes as supervision executable content.
107
+ const bytes = fs.readFileSync(file);
108
+ if (
109
+ !Buffer.isBuffer(bytes) ||
110
+ bytes.length !== stat.size ||
111
+ bytes.length > maximum
112
+ )
113
+ throw failure("invalid-standalone-asset");
114
+ return bytes;
115
+ } finally {
116
+ fs.closeSync(fd);
117
+ }
118
+ }
119
+
70
120
  function packagedImage() {
71
121
  const root = fileURLToPath(
72
122
  new URL("../../assets/linux-subreaper/", import.meta.url),
73
123
  );
124
+ if (isPkgRuntime()) {
125
+ const directory = path.join(root, `linux-${process.arch}`);
126
+ const manifest = readPkgAsset(
127
+ path.join(directory, "manifest.json"),
128
+ MAX_SUBREAPER_MANIFEST_BYTES,
129
+ );
130
+ const bytes = readPkgAsset(
131
+ path.join(directory, "supervisor"),
132
+ MAX_IMAGE_BYTES,
133
+ );
134
+ return {
135
+ bytes,
136
+ identity: validateLinuxSubreaperArtifact(manifest, bytes, {
137
+ arch: process.arch,
138
+ }),
139
+ };
140
+ }
74
141
  // Only source checkouts with no packaged directory may use the development
75
142
  // compiler path. A partial/corrupt installed payload must never fall back.
76
143
  try {
@@ -135,23 +202,28 @@ function compileImage(spawnSync) {
135
202
  const source = fileURLToPath(
136
203
  new URL("./linux-subreaper-supervisor.c", import.meta.url),
137
204
  );
138
- sourceFd = fs.openSync(
139
- source,
140
- fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW,
141
- );
142
- const snapshot = readDescriptor(sourceFd, MAX_SOURCE_BYTES);
205
+ const packed = isPkgRuntime();
206
+ let sourceSnapshot;
207
+ if (packed) {
208
+ sourceSnapshot = readPkgAsset(source, MAX_SOURCE_BYTES);
209
+ } else {
210
+ sourceFd = fs.openSync(
211
+ source,
212
+ fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW,
213
+ );
214
+ const snapshot = readDescriptor(sourceFd, MAX_SOURCE_BYTES);
215
+ if (snapshot.stat.nlink !== 1n) throw failure("source-digest-mismatch");
216
+ sourceSnapshot = snapshot.bytes;
217
+ fs.closeSync(sourceFd);
218
+ sourceFd = null;
219
+ }
143
220
  // npm/git may transport text with CRLF. Compile the exact canonical bytes
144
221
  // that the source digest commits to, passed on stdin rather than reopened.
145
222
  const sourceBytes = Buffer.from(
146
- snapshot.bytes.toString("utf8").replace(/\r\n/g, "\n"),
223
+ sourceSnapshot.toString("utf8").replace(/\r\n/g, "\n"),
147
224
  );
148
- if (
149
- snapshot.stat.nlink !== 1n ||
150
- sha(sourceBytes) !== LINUX_SUBREAPER_SOURCE_DIGEST
151
- )
225
+ if (sha(sourceBytes) !== LINUX_SUBREAPER_SOURCE_DIGEST)
152
226
  throw failure("source-digest-mismatch");
153
- fs.closeSync(sourceFd);
154
- sourceFd = null;
155
227
  const packaged = packagedImage();
156
228
  const compiler = packaged ? null : compilerPath();
157
229
  temporaryRoot = fs.mkdtempSync(
@@ -253,7 +325,9 @@ function compileImage(spawnSync) {
253
325
  // Do not expose compiler stdout/stderr, paths, environment, or native argv.
254
326
  throw failure(
255
327
  error.code === "ENOENT"
256
- ? "system-compiler-or-source-missing"
328
+ ? process.pkg
329
+ ? "standalone-asset-missing"
330
+ : "system-compiler-or-source-missing"
257
331
  : "native-build-setup-failed",
258
332
  );
259
333
  } finally {
@@ -0,0 +1,31 @@
1
+ // In-process identity, not a JSON profile name, admits the packer's larger
2
+ // finite CPU budget. This grants no process permission: the broker's ordinary
3
+ // deny/prompt checks and strict-mode override still apply.
4
+ const policies = new WeakMap();
5
+ const origins = new Set(["packer:pkg", "packer:web-panel-build"]);
6
+
7
+ export const PACKER_BUILD_TIMEOUT_MS = 900_000;
8
+
9
+ export function createPackerBuildPolicy(origin) {
10
+ if (!origins.has(origin)) throw new Error("Unknown packer build origin");
11
+ const policy = Object.freeze({ profile: "build" });
12
+ policies.set(policy, origin);
13
+ return policy;
14
+ }
15
+
16
+ export function isPackerBuildPolicy(policy, options, launch = {}) {
17
+ const { origin, scope, shell, detached, timeout, killSignal } = options;
18
+ return (
19
+ scope === "pack" &&
20
+ origins.has(origin) &&
21
+ policies.get(policy) === origin &&
22
+ launch.sync === true &&
23
+ launch.pty !== true &&
24
+ shell === false &&
25
+ (detached === undefined || detached === false) &&
26
+ Number.isSafeInteger(timeout) &&
27
+ timeout > 0 &&
28
+ timeout <= PACKER_BUILD_TIMEOUT_MS &&
29
+ killSignal === "SIGKILL"
30
+ );
31
+ }
@@ -2128,7 +2128,7 @@ export function applyMacSandbox(
2128
2128
  // non-strict mode records the unavailable primitive and executes the
2129
2129
  // original invocation, while strict mode fails closed. Explicit strict or
2130
2130
  // network-only profiles still opt in to the sandbox-exec wrapper below.
2131
- if ((sandboxOpts.profileName || "default") === "default") {
2131
+ if (["default", "build"].includes(sandboxOpts.profileName || "default")) {
2132
2132
  return createSandboxPlan({
2133
2133
  ...base,
2134
2134
  reason: "macos_default_profile_requires_explicit_policy",
@@ -9969,8 +9969,16 @@ export function applySandbox(
9969
9969
  };
9970
9970
 
9971
9971
  const profile = {
9972
- ...(profiles[profileName] || profiles.default),
9973
- profileName: profiles[profileName] ? profileName : "default",
9972
+ ...(profileName === "build"
9973
+ ? {
9974
+ ...profiles.default,
9975
+ limits: { ...profiles.default.limits, cpu: 600 },
9976
+ }
9977
+ : profiles[profileName] || profiles.default),
9978
+ profileName:
9979
+ profileName === "build" || profiles[profileName]
9980
+ ? profileName
9981
+ : "default",
9974
9982
  requiredBoundaries: sandboxRequest.requiredBoundaries,
9975
9983
  sync: sandboxRequest.sync,
9976
9984
  pty: sandboxRequest.pty,
@@ -1,3 +1,5 @@
1
+ import { randomUUID } from "node:crypto";
2
+
1
3
  /**
2
4
  * Recheck the live shell authority while a Docker egress session exists. This
3
5
  * uses bounded polling as a fallback. Trusted policy owners also call revoke()
@@ -9,19 +11,35 @@ export function createDockerEgressAuthorityMonitor({
9
11
  abortProxy,
10
12
  intervalMs = 500,
11
13
  checkTimeoutMs = 5_000,
14
+ sessionId = null,
15
+ policyVersion = null,
12
16
  }) {
13
17
  if (typeof revalidate !== "function" || typeof abortProxy !== "function")
14
18
  throw new TypeError("Docker egress authority callbacks are required");
19
+ if (
20
+ (sessionId !== null && typeof sessionId !== "string") ||
21
+ (policyVersion !== null && typeof policyVersion !== "string")
22
+ )
23
+ throw new TypeError(
24
+ "Docker egress acknowledgement identities must be strings",
25
+ );
26
+ const stopIdentity = Object.freeze({
27
+ receiverId: randomUUID(),
28
+ sessionId,
29
+ policyVersion,
30
+ });
15
31
  let revoked = null;
16
32
  let session = null;
17
33
  let timer = null;
18
34
  let checking = null;
19
35
  let stopped = false;
20
36
  const cleanupTasks = new Set();
37
+ let proxyStopped = false;
38
+ let sessionStopped = false;
21
39
 
22
- function trackCleanup(operation) {
40
+ function trackCleanup(operation, onStopped) {
23
41
  try {
24
- const task = Promise.resolve(operation());
42
+ const task = Promise.resolve(operation()).then(onStopped);
25
43
  cleanupTasks.add(task);
26
44
  void task.catch((error) => {
27
45
  if (revoked && !revoked.cleanupError) revoked.cleanupError = error;
@@ -41,8 +59,18 @@ export function createDockerEgressAuthorityMonitor({
41
59
  if (!revoked.code) revoked.code = "CC_DOCKER_EGRESS_AUTHORITY_CHANGED";
42
60
  clearTimeout(timer);
43
61
  // Latch first, then cut the broker before closing the target containers.
44
- trackCleanup(abortProxy);
45
- if (session) trackCleanup(() => session.close());
62
+ trackCleanup(abortProxy, () => {
63
+ proxyStopped = true;
64
+ });
65
+ if (session) {
66
+ const closing = session;
67
+ trackCleanup(
68
+ () => closing.close(),
69
+ () => {
70
+ if (session === closing) sessionStopped = true;
71
+ },
72
+ );
73
+ }
46
74
  return revoked;
47
75
  }
48
76
 
@@ -51,9 +79,17 @@ export function createDockerEgressAuthorityMonitor({
51
79
  }
52
80
 
53
81
  function attachSession(value) {
82
+ if (session)
83
+ throw new TypeError("Docker egress monitor session is already attached");
54
84
  session = value;
85
+ sessionStopped = false;
55
86
  if (revoked) {
56
- trackCleanup(() => value.close());
87
+ trackCleanup(
88
+ () => value.close(),
89
+ () => {
90
+ if (session === value) sessionStopped = true;
91
+ },
92
+ );
57
93
  throw revoked;
58
94
  }
59
95
  }
@@ -112,6 +148,7 @@ export function createDockerEgressAuthorityMonitor({
112
148
  }
113
149
 
114
150
  return {
151
+ stopIdentity,
115
152
  get revocationError() {
116
153
  return revoked;
117
154
  },
@@ -134,5 +171,25 @@ export function createDockerEgressAuthorityMonitor({
134
171
  async awaitCleanup() {
135
172
  await Promise.allSettled([...cleanupTasks]);
136
173
  },
174
+ getStopAcknowledgement() {
175
+ // A synchronous writer commit is never a stop ACK. Only the receiving
176
+ // runtime, after stopping checks and awaiting both teardown operations,
177
+ // can report this acknowledgement. Cleanup failures never mint one.
178
+ if (
179
+ !stopped ||
180
+ !revoked ||
181
+ revoked.cleanupError ||
182
+ cleanupTasks.size ||
183
+ !proxyStopped ||
184
+ !sessionStopped
185
+ )
186
+ return null;
187
+ return Object.freeze({
188
+ schema: "chainlesschain.egress-stop-ack/v1",
189
+ ...stopIdentity,
190
+ proxyStopped: true,
191
+ sessionStopped: true,
192
+ });
193
+ },
137
194
  };
138
195
  }
@@ -11,6 +11,7 @@ import path from "node:path";
11
11
  import { createHash, randomUUID } from "node:crypto";
12
12
  import projectRoot from "./project-root.cjs";
13
13
  import permissionRules from "./permission-rules.cjs";
14
+ import persistentSettings from "./settings-permission-authority.cjs";
14
15
  import { getMachineSecurityAnchorDir } from "./paths.js";
15
16
  import {
16
17
  readSecurityStore,
@@ -27,6 +28,7 @@ const STORE_LABEL = "scoped permission";
27
28
  const RULE_ID_PATTERN = /^spr_[0-9a-f]{32}$/;
28
29
  const DECISIONS = new Set(["allow", "ask", "deny"]);
29
30
  const DEFAULT_MAX_RECORDS = 1000;
31
+ const persistentBindings = new WeakMap();
30
32
 
31
33
  // Official mutations revoke every provider in this module instance. Path
32
34
  // matching alone misses aliases and files that did not exist at admission.
@@ -143,7 +145,7 @@ function validateRecord(record, seenIds) {
143
145
  seenIds.has(record.id) ||
144
146
  !DECISIONS.has(record.decision) ||
145
147
  !parseRule(record.rule) ||
146
- !Number.isInteger(record.revision) ||
148
+ !Number.isSafeInteger(record.revision) ||
147
149
  record.revision < 1 ||
148
150
  !Number.isFinite(record.createdAt) ||
149
151
  !Number.isFinite(record.expiresAt) ||
@@ -165,7 +167,7 @@ function validateState(value, workspace) {
165
167
  !value ||
166
168
  value.schema !== STATE_SCHEMA ||
167
169
  value.schemaVersion !== STATE_SCHEMA_VERSION ||
168
- !Number.isInteger(value.generation) ||
170
+ !Number.isSafeInteger(value.generation) ||
169
171
  value.generation < 0 ||
170
172
  !value.workspace ||
171
173
  value.workspace.id !== workspace.id ||
@@ -188,6 +190,16 @@ function statusFor(record, now) {
188
190
  return "active";
189
191
  }
190
192
 
193
+ function nextVersion(value, label) {
194
+ if (value === Number.MAX_SAFE_INTEGER) {
195
+ throw scopedPermissionError(
196
+ SCOPED_PERMISSION_ERROR_CODES.INVALID,
197
+ `Scoped permission ${label} is exhausted`,
198
+ );
199
+ }
200
+ return value + 1;
201
+ }
202
+
191
203
  function projectRecord(record, now, filePath) {
192
204
  return Object.freeze({
193
205
  ...structuredClone(record),
@@ -206,6 +218,7 @@ export class ScopedPermissionStore {
206
218
  maxRecords = DEFAULT_MAX_RECORDS,
207
219
  lock = undefined,
208
220
  randomId = () => `spr_${randomUUID().replaceAll("-", "")}`,
221
+ settingsAuthority = null,
209
222
  } = {}) {
210
223
  this.workspace = workspaceBinding(cwd);
211
224
  this.filePath = path.resolve(
@@ -232,6 +245,17 @@ export class ScopedPermissionStore {
232
245
  );
233
246
  this._lock = lock;
234
247
  this._randomId = randomId;
248
+ if (settingsAuthority) {
249
+ const bound =
250
+ persistentSettings.settingsPermissionAuthorityOptions(
251
+ settingsAuthority,
252
+ );
253
+ if (path.resolve(cwd) !== bound.cwd || this.filePath !== bound.scopedFile)
254
+ throw new TypeError(
255
+ "persistent scoped permission authority options mismatch",
256
+ );
257
+ persistentBindings.set(this, settingsAuthority);
258
+ }
235
259
  }
236
260
 
237
261
  _capture() {
@@ -243,7 +267,22 @@ export class ScopedPermissionStore {
243
267
  randomId: this._randomId.bind(this),
244
268
  maxRecords: this.maxRecords,
245
269
  lock: this._lock || withFileLock,
270
+ settingsAuthority: persistentBindings.get(this) || null,
246
271
  });
272
+ if (captured.settingsAuthority) {
273
+ const bound = persistentSettings.settingsPermissionAuthorityOptions(
274
+ captured.settingsAuthority,
275
+ );
276
+ const workspace = workspaceBinding(bound.cwd);
277
+ if (
278
+ captured.filePath !== bound.scopedFile ||
279
+ captured.workspace.id !== workspace.id ||
280
+ captured.workspace.root !== workspace.root
281
+ )
282
+ throw new TypeError(
283
+ "persistent scoped permission authority options mismatch",
284
+ );
285
+ }
247
286
  if (getScopedPermissionRevision() !== revision)
248
287
  throw scopedPermissionError(
249
288
  "CC_SCOPED_PERMISSION_AUTHORITY_CHANGED",
@@ -254,13 +293,54 @@ export class ScopedPermissionStore {
254
293
 
255
294
  _read(captured = this._capture()) {
256
295
  getScopedPermissionRevision();
257
- const stored = readSecurityStore(captured.filePath, STORE_LABEL);
296
+ const stored = captured.settingsAuthority
297
+ ? persistentSettings.readSettingsPermissionAuthority(
298
+ captured.settingsAuthority,
299
+ ).scopedObservation.settings || {}
300
+ : readSecurityStore(captured.filePath, STORE_LABEL);
258
301
  if (Object.keys(stored).length === 0) return emptyState(captured.workspace);
259
302
  return validateState(stored, captured.workspace);
260
303
  }
261
304
 
262
305
  _mutate(captured, update) {
263
306
  getScopedPermissionRevision(); // Reject observer reentry before the lock.
307
+ if (captured.settingsAuthority) {
308
+ let started = false;
309
+ try {
310
+ persistentSettings.mutateSettingsPermissionSource(
311
+ captured.settingsAuthority,
312
+ {
313
+ logicalPath: captured.filePath,
314
+ prepare(draft) {
315
+ if (Object.keys(draft).length === 0)
316
+ Object.assign(draft, emptyState(captured.workspace));
317
+ validateState(draft, captured.workspace);
318
+ if (update(draft) === false) return false;
319
+ validateState(draft, captured.workspace);
320
+ },
321
+ revokeLocal() {
322
+ started = true;
323
+ beginMutation();
324
+ },
325
+ replace(file, draft) {
326
+ validateState(draft, captured.workspace);
327
+ writeSecurityStore(file, STORE_LABEL, draft);
328
+ },
329
+ },
330
+ );
331
+ if (started) finishMutation("ready");
332
+ } catch (error) {
333
+ if (started)
334
+ finishMutation(
335
+ error.commitState === "unknown" ||
336
+ permissionRevision.state === "invalid"
337
+ ? "invalid"
338
+ : "ready",
339
+ );
340
+ throw error;
341
+ }
342
+ return;
343
+ }
264
344
  fs.mkdirSync(path.dirname(captured.filePath), {
265
345
  recursive: true,
266
346
  mode: 0o700,
@@ -412,7 +492,7 @@ export class ScopedPermissionStore {
412
492
  reason: normalizedReason,
413
493
  };
414
494
  Object.assign(draft, current, {
415
- generation: current.generation + 1,
495
+ generation: nextVersion(current.generation, "generation"),
416
496
  updatedAt: now,
417
497
  rules: [...retained, created],
418
498
  });
@@ -462,13 +542,13 @@ export class ScopedPermissionStore {
462
542
  }
463
543
  revoked = {
464
544
  ...record,
465
- revision: record.revision + 1,
545
+ revision: nextVersion(record.revision, "revision"),
466
546
  revokedAt: now,
467
547
  };
468
548
  const rules = [...current.rules];
469
549
  rules[index] = revoked;
470
550
  Object.assign(draft, current, {
471
- generation: current.generation + 1,
551
+ generation: nextVersion(current.generation, "generation"),
472
552
  updatedAt: now,
473
553
  rules,
474
554
  });
@@ -477,3 +557,36 @@ export class ScopedPermissionStore {
477
557
  return projectRecord(revoked, now, captured.filePath);
478
558
  }
479
559
  }
560
+
561
+ // Only the production provider uses a scoped observation already validated in
562
+ // the same durable read as settings. A store cannot substitute another source.
563
+ export function projectScopedPermissionObservation(
564
+ store,
565
+ binding,
566
+ observation,
567
+ ) {
568
+ if (persistentBindings.get(store) !== binding)
569
+ throw new TypeError(
570
+ "scoped store must use the provider's persistent authority",
571
+ );
572
+ const captured = ScopedPermissionStore.prototype._capture.call(store);
573
+ if (observation.logicalPath !== captured.filePath)
574
+ throw new TypeError("persistent scoped permission source mismatch");
575
+ const stored = observation.settings || {};
576
+ const state =
577
+ Object.keys(stored).length === 0
578
+ ? emptyState(captured.workspace)
579
+ : validateState(stored, captured.workspace);
580
+ const now = captured.now();
581
+ return Object.freeze({
582
+ schema: state.schema,
583
+ schemaVersion: state.schemaVersion,
584
+ generation: state.generation,
585
+ updatedAt: state.updatedAt,
586
+ workspace: structuredClone(state.workspace),
587
+ file: captured.filePath,
588
+ rules: state.rules.map((record) =>
589
+ projectRecord(record, now, captured.filePath),
590
+ ),
591
+ });
592
+ }
@@ -727,12 +727,24 @@ function transitionSettingsAuthority(
727
727
  replace,
728
728
  revokeLocal,
729
729
  transactionId = randomUUID(),
730
+ expectedSnapshot = null,
731
+ localRevision = null,
730
732
  } = {},
731
733
  ) {
732
734
  const state = stateFor(handle);
733
735
  // Snapshot caller data before any callback. These are trusted host APIs, but
734
736
  // mutable intents must not turn an already-validated no-op into a mutation.
735
737
  intent = plainCopy(intent);
738
+ if (expectedSnapshot !== null) {
739
+ expectedSnapshot = plainCopy(expectedSnapshot);
740
+ shape(expectedSnapshot, [
741
+ "domainId",
742
+ "epoch",
743
+ "generation",
744
+ "digest",
745
+ "state",
746
+ ]);
747
+ }
736
748
  requireSynchronous(observeContexts);
737
749
  requireSynchronous(revokeLocal);
738
750
  if (intent.kind === "write") requireSynchronous(replace);
@@ -743,7 +755,15 @@ function transitionSettingsAuthority(
743
755
  try {
744
756
  return locked(state, () => {
745
757
  const perform = () => {
746
- const current = readSettingsAuthority(handle, { observeContexts });
758
+ const current = readSettingsAuthority(handle, {
759
+ observeContexts,
760
+ localRevision,
761
+ });
762
+ if (
763
+ expectedSnapshot !== null &&
764
+ !sameData(current.snapshot, expectedSnapshot)
765
+ )
766
+ refuse("CC_SETTINGS_AUTHORITY_CONFLICT");
747
767
  if (
748
768
  intent.kind === "register" &&
749
769
  current.ledger.contexts.some(
@@ -841,7 +861,15 @@ function transitionSettingsAuthority(
841
861
  };
842
862
  };
843
863
  if (intent.kind !== "write") return perform();
844
- const admission = readSettingsAuthority(handle, { observeContexts });
864
+ const admission = readSettingsAuthority(handle, {
865
+ observeContexts,
866
+ localRevision,
867
+ });
868
+ if (
869
+ expectedSnapshot !== null &&
870
+ !sameData(admission.snapshot, expectedSnapshot)
871
+ )
872
+ refuse("CC_SETTINGS_AUTHORITY_CONFLICT");
845
873
  records.prepareTransition({
846
874
  ledger: admission.ledger,
847
875
  transactionId,
@@ -878,6 +906,12 @@ function transitionSettingsAuthority(
878
906
  }
879
907
  }
880
908
 
909
+ // Official read/modify/write adapters take an initial snapshot under the same
910
+ // authority lock. The later transition MUST still compare expectedSnapshot.
911
+ function readSettingsAuthorityForUpdate(handle, options) {
912
+ return locked(stateFor(handle), () => readSettingsAuthority(handle, options));
913
+ }
914
+
881
915
  function recoverSettingsAuthority(
882
916
  handle,
883
917
  { transactionId, observeContexts, outcome } = {},
@@ -954,6 +988,7 @@ function recoverSettingsAuthority(
954
988
  }
955
989
 
956
990
  module.exports = {
991
+ readSettingsAuthorityForUpdate,
957
992
  DOMAIN_SCHEMA,
958
993
  initializeSettingsAuthorityDomain,
959
994
  pinSettingsAuthorityDomain,